2011-12-28 3 views
0

Я создал простую грамматику в AntlWorks. Затем я сгенерировал код, и у меня есть два файла: grammarLexer.java и grammarParser.java. Моя цель - создать отображение моей грамматики на Java-язык. Что мне делать дальше, чтобы достичь этого?Простой грамматический анализатор Antlworks

Это моя грамматика: `грамматика грамматики; prog: ((FOR | WHILE | IF | PRINT | DECLARATION | ENTER | (WS * FUNCTION) | VARIABLE) | FUNCTION_DEC) +;

FOR  :  WS* 'for' WS+ VARIABLE WS+ DIGIT+ WS+ DIGIT+ WS* ENTER (FOR | WHILE | IF | PRINT | DECLARATION | ENTER | (WS* FUNCTION) | INC_DEC)* WS* 'end' WS* ENTER; 
WHILE  :  WS* 'while' WS+ (VARIABLE | DIGIT+) WS* EQ_OPERATOR WS* (VARIABLE | DIGIT+) WS* ENTER (FOR | WHILE | IF | PRINT | DECLARATION | ENTER | (WS* FUNCTION) | (WS* INC_DEC))* WS* 'end' WS* ENTER; 
IF  :   WS* 'if' WS+ (FUNCTION | VARIABLE | DIGIT+) WS* EQ_OPERATOR WS* (VARIABLE | DIGIT+) WS* ENTER (FOR | WHILE | IF | PRINT | DECLARATION | ENTER | (WS* FUNCTION) | INC_DEC)* (WS* 'else' ENTER (FOR | WHILE | IF | PRINT | DECLARATION | ENTER | (WS* FUNCTION) | (WS* INC_DEC))*)? WS* 'end' WS* ENTER; 

CHAR  :  ('a'..'z'|'A'..'Z')+; 
EQ_OPERATOR : ('<' | '>' | '==' | '>=' | '<=' | '!='); 
DIGIT  :  '0'..'9'+; 
ENTER  :  '\n'; 
WS  :  ' ' | '\t'; 

PRINT_TEMPLATE :  WS+ (('"' (CHAR | DIGIT | WS)* '"') | VARIABLE | DIGIT+ | FUNCTION | INC_DEC); 
PRINT    :  WS* 'print' PRINT_TEMPLATE (',' PRINT_TEMPLATE)* WS* ENTER; 

VARIABLE  : CHAR(CHAR|DIGIT)*; 
FUN_TEMPLATE : WS* (VARIABLE | DIGIT+ | '"' (CHAR | DIGIT | WS)* '"'); 
FUNCTION  : VARIABLE '(' (FUN_TEMPLATE (WS* ',' FUN_TEMPLATE)*)? ')' WS* ENTER*; 

DECLARATION  : WS* VARIABLE WS* ('=' WS* (DIGIT+ | '"' (CHAR | DIGIT | WS)* '"' | VARIABLE)) WS* ENTER; 
FUNCTION_DEC : WS*'def' WS* FUNCTION (FOR | WHILE | IF | PRINT | DECLARATION | ENTER | (WS* FUNCTION) | INC_DEC)* WS* 'end' WS* ENTER*; 

INC_DEC   : VARIABLE ('--' | '++') WS* ENTER*;` 

Вот мой Основной класс для синтаксического анализа: `
импорта org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CommonToken; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.Parser;

public class Main { 
    public static void main(String[] args) throws Exception { 
     // the input source 
     String source = 
      "for i 1 3\n " + 
      "printHi()\n " + 
      "end\n " + 
      "if fun(y, z) == 0\n " + 
      "end\n "; 
// create an instance of the lexer 
     grammarLexer lexer = new grammarLexer(new ANTLRStringStream(source)); 

     // wrap a token-stream around the lexer 
     CommonTokenStream tokens = new CommonTokenStream(lexer); 

     // traverse the tokens and print them to see if the correct tokens are created 
     int n = 1; 
     for(Object o : tokens.getTokens()) { 
      CommonToken token = (CommonToken)o; 
      System.out.println("token(" + n + ") = " + token.getText().replace("\n", "\\n")); 
      n++; 
     } 
     grammarParser parser = new grammarParser(tokens); 
     parser.file(); 
} 
} 
` 
+2

могли бы вы рассказать немного? Что вы пытаетесь точно сопоставить? Пример очень поможет. –

+0

Привет !, Я прочитал ваш блог - введение в ANTLR. Я нашел его очень полезным, спасибо большое! :) Как вы там сказали, я создал Основной класс, а источник String представлял собой действительный ввод моей грамматики. Затем я запускаю приложение и получаю аналогичный результат в вашем примере :). Затем я хотел попробовать с парсером. Я сделал все, что в вашем блоге, но теперь у меня есть эта проблема: файл метода() не определен для типа grammarParser. Спасибо за вашу помощь :) – ruhungry

+1

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

ответ

3

Как я уже упомянул в комментариях: неправильное использование правил lexer. Посмотрите на правила lexer как на основные строительные блоки вашего языка. Очень похоже на то, как вы описываете воду в химии. Вы бы не описывают воду, как это:

WATER 
: 'HHO' 
; 

т.е .: как один элемент. Вода должна быть описана как 3 отдельных элементов:

water 
: Hydrogen Hydrogen Oxygen 
; 

Hydrogen : 'H'; 
Oxygen : 'O'; 

, где Hydrogen и Oxygen являются основными строительными блоками (правила лексера) и water представляет собой соединение (правило СА).

Хорошее эмпирическое правило состоит в том, что если вы создаете правила лексера, которые состоят из нескольких других правил лексера, есть вероятность, что в вашей грамматике есть что-то подозрительное. Конечно, это не всегда так.

Допустим, вы хотите, чтобы разобрать следующий вход:

for i 1 3 
    print(i) 
end 

if fun(y, z) == 0 
    print('foo') 
end 

грамматику может выглядеть следующим образом:

grammar T; 

options { 
    output=AST; 
} 

tokens { 
    BLOCK; 
    CALL; 
    PARAMS; 
} 

// parser rules 
parse 
: block EOF! 
; 

block 
: stat* -> ^(BLOCK stat*) 
; 

stat 
: for_stat 
| if_stat 
| func_call 
; 

for_stat 
: FOR^ ID expr expr block END! 
; 

if_stat 
: IF^ expr block END! 
; 

expr 
: eq_expr 
; 

eq_expr 
: atom (('==' | '!=')^ atom)* 
; 

atom 
: func_call 
| INT 
| ID 
| STR 
; 

func_call 
: ID '(' params ')' -> ^(CALL ID params) 
; 

params 
: (expr (',' expr)*)? -> ^(PARAMS expr*) 
; 

// lexer rules 
FOR : 'for'; 
END : 'end'; 
IF : 'if'; 
ID : ('a'..'z' | 'A'..'Z')+; 
INT : '0'..'9'+; 
STR : '\'' ~('\'')* '\''; 
SP : (' ' | '\t' | '\r' | '\n')+ {skip();}; 

И если вы сейчас запустить этот тест класс:

import org.antlr.runtime.*; 
import org.antlr.runtime.tree.*; 
import org.antlr.stringtemplate.*; 

public class Main { 
    public static void main(String[] args) throws Exception { 
    String src = 
     "for i 1 3   \n" + 
     " print(i)   \n" + 
     "end    \n" + 
     "     \n" + 
     "if fun(y, z) == 0 \n" + 
     " print('foo')  \n" + 
     "end    \n"; 
    TLexer lexer = new TLexer(new ANTLRStringStream(src)); 
    TParser parser = new TParser(new CommonTokenStream(lexer)); 
    CommonTree tree = (CommonTree)parser.parse().getTree(); 
    DOTTreeGenerator gen = new DOTTreeGenerator(); 
    StringTemplate st = gen.toDOT(tree); 
    System.out.println(st); 
    } 
} 

вы увидите, что какой-то вывод печатается на консоли wh ич соответствует следующему AST:

enter image description here

+1

@whiteangel, создавая байт-коды Java и оптимизацию AST, выходит за рамки ответа SO. Я рекомендую вам получить копию «Паттернов реализации языка» Теренца Парра (http://pragprog.com/book/tpdsl/language-implementation-patterns), где он объясняет, как создавать байт-коды для языка в одном из в последующих главах. Удачи! –