Я пишу приложение, которое будет анализировать скрипт на пользовательском языке (на основе немного на синтаксисе Си и Allman style) и я ищу лучший (читаемый: быстрый) способ разбора блоков кода сценария в строковые массивы, чем то, как я это делаю сейчас (текущий метод будет делать, но больше для отладки, чем что-либо еще).Parsing script loops in C#
Содержимое сценария в настоящее время считывается из файла в массив строк и передается методу.
Вот шаблон блока сценария:
loop [/* some conditional */ ]
{
/* a whole bunch of commands that are to be read into
* a List<string>, then converted to a string[] and
* passed to the next step for execution */
/* some command that has a bracket delimited set of
* properties or attributes */
{
/* some more commands to be acted on */
}
}
В основном, фигурные блоки скобки могут быть вложенными (так же, как и в любом другом C на основе языка), и я ищу лучший способ найти индивидуальные блоки вроде этого.
фигурной скобки разграниченных блоки будут ВСЕГДА быть отформатированы, как это - содержимое скобок будут начать на линии после открывающей скобки и будет сопровождаться кронштейном на линии после последнего атрибут/команд/комментария /без разницы.
Примером может быть:
loop [ someVar <= 10 ]
{
informUser "Get ready to do something"
readValue
{
valueToLookFor = 0x54
timeout = 10 /* in seconds */
}
}
Это скажет приложение для цикла в то время как someVar меньше, чем 10 (извините за сосание яйца комментарий). Каждый раз мы передаем сообщение пользователю и ищем определенное значение где-то (с таймаутом 10 секунд).
Вот как я это делаю в минуту (примечание: метод, который вызывает это проходит всю строку [], содержащий текущий скрипт в него с индексом, чтобы читать):
private string[] findEntireBlock(string[] scriptContents, int indexToReadFrom,
out int newIndex)
{
newIndex = 0;
int openBraceCount = 0; // for '{' char count
int closeBraceCount = 0; // for '}' char count
int openSquareCount = 0; // for '[' char count
int closeSquareCount = 0; // for ']' char count
List<string> fullblock = new List<string>();
for (int i = indexToReadFrom; i < scriptContents.Length; i++)
{
if (scriptContents[i].Contains('}'))
{
if (scriptContents[i].Contains("[") && fullblock.Count > 0)
{
//throw new exception, as we shouldn't expect to
//to find a line which starts with [ when we've already
}
else
{
if (scriptContents[i].Contains('{')) openBraceCount++;
if (scriptContents[i].Contains('}')) closeBraceCount++;
if (scriptContents[i].Contains('[')) openSquareCount++;
if (scriptContents[i].Contains(']')) closeBraceCount++;
newIndex = i;
fullblock.Add(scriptContents[i]);
break;
}
}
else
{
if (scriptContents[i].Contains("[") && fullblock.Count > 0)
{
//throw new exception, as we shouldn't expect to
//to find a line which starts with [ when we've already
}
else
{
if (scriptContents[i].Contains('{')) openBraceCount++;
if (scriptContents[i].Contains('}')) closeBraceCount++;
if (scriptContents[i].Contains('[')) openSquareCount++;
if (scriptContents[i].Contains(']')) closeBraceCount++;
fullblock.Add(scriptContents[i]);
}
}
}
if (openBraceCount == closeBraceCount &&
openSquareCount == closeSquareCount)
return fullblock.ToArray();
else
//throw new exception, the number of open brackets doesn't match
//the number of close brackets
}
I согласитесь, что это может быть немного тупым и медленным методом, чтобы следовать, поэтому я прошу какие-либо идеи о том, как повторно реализовать это для скорости и ясности (если баланс может быть удовлетворен, то есть).
Я ищу, чтобы держаться подальше от RegEx, потому что я не могу использовать его для поддержания скобок, и я не уверен, можете ли вы написать инструкцию RegEx (это правильный термин?), Который может действовать рекурсивно. Я думал работать изнутри наружу, но я убежден, что это будет довольно медленно.
Я не ищет кого-то, чтобы переписать его для меня, но общая идея об алгоритмах или методах/библиотеках, которые я мог бы использовать, улучшит мой метод.
В качестве побочного вопроса, как компиляторы имеют дело с несколькими вложенными скобками в исходном коде?
Посмотрите на грамматику, лексеры и парсеры. Это инструменты, необходимые для анализа этого. –
Я посмотрю на них после того, как я быстро взглянул на Let's Build the Compiler, как это было предложено [Andrew Cooper] (http://stackoverflow.com/users/377639/andrew-cooper) в его ответе –