Интерпретатор выражений ANTLR - PullRequest
1 голос
/ 19 декабря 2010

Я создал следующую грамматику: я хотел бы получить некоторую идею о том, как создать интерпретатор, который возвращает дерево в java, которое я позже смогу использовать для печати на экране. Я бита стека о том, как начать на нем.

grammar myDSL;

options {
  language = Java;
}
@header {
  package DSL;
}
@lexer::header {
  package DSL;
}


program
    :  IDENT '={' components* '}'
    ;


components
    : IDENT '=('(shape)(shape|connectors)* ')'
    ;

shape
    :  'Box' '(' (INTEGER ','?)* ')'
    |  'Cylinder' '(' (INTEGER ','?)* ')'
    |  'Sphere' '(' (INTEGER ','?)* ')'
    ;

connectors
    :  type '(' (INTEGER ','?)* ')'
    ;    

type
    :  'MG'
    |  'EL'
    ;

IDENT: ('a'..'z' | 'A'..'Z')('a'..'z' | 'A'..'Z' | '0'..'0')*;

INTEGER: '0'..'9'+;

// This if for the empty spaces between tokens and avoids them in the parser
WS: (' ' | '\t' | '\n' | '\r' | '\f')+ {$channel=HIDDEN;};

COMMENT: '//' .* ('\n' | '\r') {$channel=HIDDEN;};

1 Ответ

3 голосов
/ 19 декабря 2010

Пара замечаний:

Нет необходимости устанавливать язык для Java, который является целевым языком по умолчанию. Таким образом, вы можете удалить это:

options {
  language = Java;
}

Ваш IDENT содержит ошибку:

IDENT: ('a'..'z' | 'A'..'Z')('a'..'z' | 'A'..'Z' | '0'..'0')*;

'0'..'0'), скорее всего, должно быть '0'..'9').

Подправило (INTEGER ','?)* также соответствует источнику, как 1 2 3 4 (без запятых!). Возможно, вы хотели сделать: (INTEGER (',' INTEGER)*)?

Теперь, что касается вашего вопроса: как позволить ANTLR создать правильное AST? Это можно сделать, добавив output = AST; в свой блок параметров:

options {
  //language = Java;
  output = AST;
}

А затем либо добавьте «операторы дерева» ^ и ! в правила парсера, либо используйте правила перезаписи дерева: rule: a b c -> ^(c b a).

«Оператор дерева» ^ используется для определения корня (под) дерева, а ! используется для исключения токена из (под) дерева.

Правила перезаписи имеют ^( /* tokens here */ ), где первый токен (сразу после ^() является корнем (под) дерева, а все последующие токены являются дочерними узлами корня.

Пример может быть в порядке. Давайте возьмем ваше первое правило:

program
  :  IDENT '={' components* '}'
  ;

и вы хотите, чтобы IDENT был корнем, components* дочерних элементов, и вы хотите исключить ={ и } из дерева. Вы можете сделать это, выполнив:

program
  :  IDENT^ '={'! components* '}'!
  ;

или выполнив:

program
  :  IDENT '={' components* '}' -> ^(IDENT components*)
  ;
...