Этот блог является продолжением серии моих блогов о JavaCC Установка JavaCC для Mac. Цель этого блога - реализовать очень простой, но расширяемый синтаксический анализатор на основе команд. Команды будут

moveForward()
turnRight() 

Вот схема железной дороги для языка

Мы будем использовать генерацию кода JavaCC для создания синтаксического анализатора, передав ему правильную грамматику EBNF.

Грамматика EBNF

CFG - контекстно-свободная грамматика - это набор производственных правил, которые могут применяться независимо от контекста к любому нетерминальному

EBNF - язык метасинтаксиса, основанный на теории CFG и позволяющий анализировать фразы и предложения. По сути, это просто набор вызовов функций Regex и Recursive, которые используются для формирования дерева синтаксического анализа.

Терминалы - все, что не имеет никаких производственных правил. Например. строки «BEGIN» и «END» являются терминалами в программе на Паскале.

Нетерминальные элементы - это что-либо, что может создавать один или несколько нетерминалов. (может даже называть себя)

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

<number: [“1”- “9”] ([“0”- “9”])+

Пример программы

FORWARD 20
LEFT 120
RIGHT 40
FORWARD 20

Вывод программы

Call:   Program
  Call:   MoveForward
    Consumed token: <"FORWARD" at line 1 column 1>
    Consumed token: <<DIGITS>: "20" at line 1 column 9>
    Consumed token: <<EOL>: "
" at line 1 column 11>
  Return: MoveForward
Processed Move FORWARD
  Call:   Error
    Consumed token: <<ERROR>: "L" at line 2 column 1>
  Return: Error
  Call:   handleError
*** ERROR: Line 2 after "L"
    Consumed token: <<ERROR>: "E" at line 2 column 2> (in getNextToken)
    Consumed token: <<ERROR>: "F" at line 2 column 3> (in getNextToken)
    Consumed token: <<ERROR>: "T" at line 2 column 4> (in getNextToken)
    Consumed token: <<DIGITS>: "120" at line 2 column 6> (in getNextToken)
    Consumed token: <<EOL>: "
" at line 2 column 9> (in getNextToken)
  Return: handleError
  Call:   TurnRight
    Consumed token: <"RIGHT" at line 3 column 1>
    Consumed token: <<DIGITS>: "40" at line 3 column 7>
    Consumed token: <<EOL>: "
" at line 3 column 9>
  Return: TurnRight
Processed Turn RIGHT
  Call:   MoveForward
    Consumed token: <"FORWARD" at line 4 column 1>
    Consumed token: <<DIGITS>: "20" at line 4 column 9>
    Consumed token: <<EOF> at line 4 column 10>
  Return: MoveForward
Processed Move FORWARD
Return: Program

Как видите, все было успешно проанализировано, а команда LEFT не была включена и пропущена. Теперь нетрудно расширить этот синтаксический анализатор, включив в него столько команд, сколько вы хотите, но чем это вообще может быть полезно? Я согласен с тем, что сам по себе синтаксический анализ не очень полезен, но не намного сложнее придать смысл каждому из этих узлов синтаксического анализа, которые мы только что создали.

В этом разборе вы создали AST, в котором программа является корневым узлом и имеет четырех дочерних узлов. Теперь все, что вам нужно сделать, это пройти по дереву и выполнить соответствующую операцию для каждого узла!

FORWARD 20 <- node 1
Error <- node 2
RIGHT 40 <- node 3
FORWARD 20 <- node 4

В следующем блоге мы попытаемся взять эти узлы и вернуть векторную сумму всех команд.