码里用的lookahead的个数(*):
Ruby代码
1.def check_lookaheads(file)
2. lookaheads = open file, ''r'' do |f|
3. ret = []
4. f.readlines.grep(/^\s+(.+\.la\((\d+)\).+)$/i) do
5. ret << "#{$2}: #{$1}"
6. end
7. ret
8. end
9.end
10.
11.if __FILE__ == $0
12. la = check_lookaheads ARGV[0] || ''JerryParser.cs''
13. puts ''Lookaheads:'', la, ''''
14. puts "Non-LL(1)''s:", la.select { |l| ?1 != l[0] }
15.end
一个简单的语言的语法(三):做些小调整,并将生成目标换到CSharp2(3)
时间:2011-10-07 javaeye RednaxelaFX
明白了这个道理,就应该尽量将重写规则中的各个根节点设计成能直接区分的。
实际上不只是树的语法,在编程语言的源码的语法设计上也是一样:最容易解析的语法是每条规则都 以特殊的token开头的语法,例如说声明变量就以var关键字开头,声明函数就以function关键字开头等。 这样能保证语法只需要1个lookahead。而类似C的语法对解析器来说实在算不上友善……|||
(*:ANTLR在遇到比较复杂的判断条件时不会直接在规则对应的方法里调用input.LA(n),而是会生成 一个DFA类来计算应该走的分支。上面的Ruby脚本不检查这个状况。)
其次,所有虚构token都添加了一些信息在后面。例如说原本一元负号的规则是:
Java代码
MINUS primaryExpression
-> ^( UNARY_MINUS primaryExpression )
则UNARY_MINUS这个虚构token将不包含任何文字、位置信息。因为MINUS原本携带的位置信息已经丢失 了,所以如果后续处理中需要知道这个表达式的位置就没办法得到。
改写为这样:
Java代码
MINUS primaryExpression
-> ^( UNARY_MINUS[$MINUS] primaryExpression )
则使得UNARY_MINUS继承MINUS匹配时的文字、位置等属性,解决了前面的问题。
除此之外,原本写在program规则里的嵌入动作也去掉了。之前写在那里主要是为了在parser内输出 AST的字符串表示,只是演示用。
修改后的完整语法如下:
C#代码
1.grammar Jerry;
2.
3.options {
4. language = CSharp2;
5. output = AST;
6. ASTLabelType = CommonTree;
7.}
8.
9.tokens {
10. // imaginary tokens
11. SIMPLE_VAR_DECL;
12. SIMPLE_VAR_DECL_INIT;
13. ARRAY_VAR_DECL;
14. ARRAY_VAR_DECL_INIT;
15. ARRAY_LITERAL;
16. SIMPLE_VAR_ACCESS;
17. ARRAY_VAR_ACCESS;
18. UNARY_MINUS;
19. BLOCK;
20. EMPTY_BLOCK;
21. EXPR_STMT;
22.}
23.
24.// parser rules
25.
26.program : statement+ EOF!
27. ;
28.
29.statement
30. : expressionStatement
31. | variableDeclaration
32. | blockStatement
33. | ifStatement
34. | whileStatement
35. | breakStatement
36. | readStatement
37. | writeStatement
38. ;
39.
40.expressionStatement
41. : expression SEMICOLON
42. - > ^( EXPR_STMT[$expression.start, "ExprStmt"] expression )
43. ;
44.
45.variableDeclaration
46. : typeSpecifier
47. ( id1=Identifier
48. ( ( -> ^( SIMPLE_VAR_DECL[$id1, "VarDecl"] ^( typeSpecifier ) $id1 ) )
49. | ( EQ expression
50. -> ^( SIMPLE_VAR_DECL_INIT[$id1, "VarDeclInit"] ^( typeSpecifier ) $id1 expression ) )
51. | ( ( LBRACK Integer RBRACK )+
52. -> ^( ARRAY_VAR_DECL[$id1, "VarDecl"] ^( typeSpecifier Integer+ ) $id1 ) )
53. | ( ( LBRACK Integer RBRACK )+ EQ arrayLiteral
54. -> ^( ARRAY_VAR_DECL_INIT[$id1, "VarDeclInit"] ^( typeSpecifier Integer+ ) $id1 arrayLiteral ) )
5
|