2013-03-20 7 views
0

Я пишу приложение, которое будет анализировать скрипт на пользовательском языке (на основе немного на синтаксисе Си и 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 (это правильный термин?), Который может действовать рекурсивно. Я думал работать изнутри наружу, но я убежден, что это будет довольно медленно.

Я не ищет кого-то, чтобы переписать его для меня, но общая идея об алгоритмах или методах/библиотеках, которые я мог бы использовать, улучшит мой метод.

В качестве побочного вопроса, как компиляторы имеют дело с несколькими вложенными скобками в исходном коде?

+1

Посмотрите на грамматику, лексеры и парсеры. Это инструменты, необходимые для анализа этого. –

+0

Я посмотрю на них после того, как я быстро взглянул на Let's Build the Compiler, как это было предложено [Andrew Cooper] (http://stackoverflow.com/users/377639/andrew-cooper) в его ответе –

ответ

3

Let's Build a Compiler, автор Jack Crenshaw, представляет собой фантастическое, легко читаемое введение в создание базового компилятора. Обсуждаемые методы должны помочь с тем, что вы пытаетесь сделать здесь.

+0

Я сделаю все возможное, чтобы проверить это, и попытаться принять от него методы. Но я беспокоюсь о том, чтобы тратить время на чтение большой серии статей. Я все равно сделаю это. Спасибо за ссылку –