Методы парсинга блоков кода без фигурных скобок - PullRequest
4 голосов
/ 16 мая 2019

Я пишу простой парсер / интерпретатор на C # с нуля (сторонних библиотек нет).Он компилируется в байт-код, а затем у меня есть класс, который выполняет байт-код.Я подхожу к завершению.Я только что реализовал циклы while и for и работаю с блоками if | else if | else.

В настоящее время мой анализатор требует, чтобы все эти структуры использовали curlyбрекеты.Я хотел бы сделать его более C-подобным и иметь необязательные фигурные скобки, когда блок содержит только одну инструкцию.Это доставляет мне проблемы.

if (condition)
{
    // Make curly braces optional when there is just one statement here
}

Проблема в отслеживании состояния.Как парсер узнает, когда закончился блок без фигурных скобок.Один из подходов состоит в том, чтобы проверить, существует ли блок без фигурных скобок после каждого оператора.Однако существует множество различных сценариев, которые могли бы составить заявление, и поэтому эти проверки должны быть в нескольких местах.Мне это кажется немного хрупким.

Мне просто интересно, если бы кто-нибудь сделал это и знает какие-нибудь хитрые уловки для отслеживания, когда заканчивается блок кода, когда нет фигурных скобок.

1 Ответ

4 голосов
/ 16 мая 2019

Вам нужно посмотреть в парсер рекурсивного спуска . Это делает создание парсеров намного проще. Предположим, у вас есть грамматика, похожая на эту:

statement
   : 'if' paren_expr ['{'] statement ['}'] 

paren_expr
   : '(' expr ')'

затем с помощью рекурсивного спуска вы можете сделать что-то вроде:

public void Statement()
{
    if(curToken == Token.If)
    {
       Eat(Token.If); // Eat is convenience method that moves token pointer on
       if(curToken == Token.LParen)
       {
          Eat(Token.LParen)
          ParenExpr();
          Eat(Token.RParen);
       }
       if(curToken == Token.LBrace) // this will signify a block of statements
       {   
          Eat(Token.LBrace);
          while(curToken != Token.RBrace)
             Statement();
          Eat(Token.RBrace);
       }
       else
          Statement();              
    }
}

public void ParenExpr()
{
   // do other token checks
}

выполняя это для всех ваших нетерминалов, вы можете легко создать AST и из этого вы можете сгенерировать свой байт-код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...