Я разрабатываю свой мини-интерпретатор (не спрашивайте зачем), так вот у меня возникла проблема: "Препретатор"(как я его назвал) в самом начале обходит весь файл с кодом и ищет по ключевому слову "function" функции, а затем добавляет их в список в виде структуры (указывается номер строки её начала). Далее, в основном цикле, когда доходит очередь до строки вызова функции, "постпретатор" берёт структуру из списка и добавляет в неё номер строки инициализатора этой функции, затем оно перед символом завершения функции ("}") оно пишет команду вида "goto;8" и затем переводит номер строки выполнения на номер строку начала функции, затем после выполнения функции оно должно перевести номер строки выполнения обратно в основной цикл. Но функция может находится в любой части скрипта, поэтому и был придуман "препретатор". У меня же с одной функцией, всё работает, а вот с двумя уже не хочет: оно почему-то не подставляет команду перевода номера строки в первую функцию, а во вторую подставляет нормально.
Основной код C#
/// <summary>
/// Структура функции
/// </summary>
struct Function
{
public int start;
public int point;
public string name;
}
/// <summary>
/// Список структур функции
/// </summary>
static SortedList<string, Function> funct = new SortedList<string, Function>();
/// <summary>
/// Препретатор функция
/// </summary>
/// <param name="game">Массив строк всего скрипта</param>
/// <param name="main">Сам скрипт</param>
public static void Compilation(string[] game, ref string main)
{
//funct.Clear();
for (int i = 0; i < game.Length; i++)
{
if (game[i].Split(';')[0] == "function")
{
//создание или "взятие" функции
Function fn;
if (!funct.ContainsKey(game[i].Split(';')[1]))
{
fn = new Function();
fn.start = i + 1;
string name = game[i].Split(';')[1];
fn.name = name;
funct.Add(name, fn);
}
else
{
fn = funct[game[i].Split(';')[1]];
}
//Подсчёт строк функции
int o = 1;
for (; !game[i + o].EndsWith("}"); o++) ;
var rrrhhh = ""; //временная переменная с итоговым кодом скрипта
var telo = "";//тело функции
for (int p = 0; p < ((i + o)); p++)
{
rrrhhh += game[p] + "\n"; //заполнение до конца функции
}
for (int q = i; q < i+o; q++)
{
telo += game[q] + "\n"; //заполнение тела
}
telo = telo.Split('\n')[telo.Split('\n').Length - 2];//обрезка } (там 2 должно быть, потому что индекс с 0, а количество с 1)
//Console.WriteLine(telo);
if (!telo.Contains("goto;"))
rrrhhh = rrrhhh.Insert(rrrhhh.Length, String.Format("goto;{0}", fn.point)+"\n}");//если "гото" нет, то добавляем
else//иначе изменяем
{
rrrhhh = rrrhhh.Substring(0, rrrhhh.Length - 3);//обрезаем перенос строки и }
int y = rrrhhh.Length-1;//получаем длинну в виде индекса
int t = 0;//создает временную переменную
for (; rrrhhh[y] == ';'; y--, t++) ;//считаем от конца и до ; (это символ передачи аргументов)
//t++;
rrrhhh = rrrhhh.Substring(0, rrrhhh.Length - t);//обрезаем по него
rrrhhh += ";" + fn.point.ToString() + "\n}";//добавляем новый "гото"
//Console.WriteLine(rrrhhh);
}
main = rrrhhh; //изменяем основной скрипт
}
}
}
/// <summary>
/// Постпретатор функция
/// </summary>
/// <param name="game">Массив строк со скриптом</param>
/// <param name="main">Сам скрипт</param>
/// <param name="name">Имя функции</param>
public static void Compilation(string[] game, ref string main, string name)
{
///Тут всё почти также как и там, но другой начало
for (int i = 0; i < game.Length; i++)
{
if (game[i].Split(';')[0] == "function")
{
//Console.WriteLine(i);
Function fn = funct[name]; //получем функцию из списка по её имени
//Далее всё вроде так же, хотя я мог что то изменить
int o = 1;
for (; !game[i + o].EndsWith("}"); o++) ;
var rrrhhh = "";
var telo = "";
for (int p = 0; p < ((i + o)); p++)
{
rrrhhh += game[p] + "\n";
}
for (int q = i; q < i + o; q++)
{
telo += game[q] + "\n";
}
telo = telo.Split('\n')[telo.Split('\n').Length - 2];
if (!telo.Contains("goto;"))
rrrhhh = rrrhhh.Insert(rrrhhh.Length, String.Format("goto;{0}", fn.point) + "\n}");
else
{
rrrhhh = rrrhhh.Substring(0, rrrhhh.Length - 3);
int y = rrrhhh.Length - 1;
int t = 0;
for (; rrrhhh[y] == ';'; y--, t++) ;
//t++;
rrrhhh = rrrhhh.Substring(0, rrrhhh.Length - t);
rrrhhh += ";" + fn.point.ToString() + "\n}";
//Console.WriteLine(rrrhhh);
}
main = rrrhhh;
//Console.WriteLine(telo);
}
}
}
public static void loadgame(string path)
{
//Начало препретатора
Console.WriteLine("Start Compilation");
Compilation(game.Split('\n'), ref game);
lenght = game.Split('\n').Length;
Console.WriteLine("Stop Compilation");
//конец препретатора
for (int i = 0; i < lenght; i++)
{
switch (game.Split('\n')[i].Split(';')[0])
{
case "func":
//func;test
Function fc = funct[game.Split('\n')[i].Split(';')[1]]; //получение из аргумента имени функции
fc.point = i+2; //передача текущего номера строки
funct[game.Split('\n')[i].Split(';')[1]] = fc; //замена функции в списке
Compilation(game.Split('\n'), ref game, game.Split('\n')[i].Split(';')[1]); //запуск постпретатора
//Compilation(game.Split('\n'), ref game);
lenght = game.Split('\n').Length;//пересчёт новой общей длинны скрипта
i = fc.start;//передача управления другой строке
break;
}
}
}
Это сам скрипт
func;test
//mess - просто текст в консоль выводит
mess;Добро пожаловать в Test.
func;fc
//функции
function;test
isfunction;
mess;Функция, функция
mess;Тело, тело
mess;Кто то батя в C#
}
isfunction;
function;fc
isfunction;
mess;Функция другая
}
Используй отладчик. В методе Compilation 2 проблемы, одна фундаментальная.
1) Ты смотришь окончание строки, но не предусматриваешь возможный перевод строки, пробел, табуляцию
//Подсчёт строк функции
int o = 1;
for (; !game[i + o].TrimEnd('\n', '\r').EndsWith("}"); o++) ;
2) В конце метода ты изменяешь основную переменную main, но расчёты ведешь на старых данных по переменной game. Тебе надо или отказаться от переменной game, или делать в неё инсерт строки goto.
main = rrrhhh; //изменяем основной скрипт
Виртуальный выделенный сервер (VDS) становится отличным выбором
Не видно ui обьектов в canvasУ меня 2 canvas, я не вижу обьектов на втором canvas они невидимые, почему так
Всем приветСитуация следующая: Есть модуль создания волн вражеских кораблей