1#!/usr/bin/ruby
2# encoding: utf-8
3
4require 'antlr3/test/functional'
5
6class TestLLStarParser < ANTLR3::Test::Functional
7  inline_grammar( <<-'END' )
8    grammar LLStar;
9
10    options { language = Ruby; }
11    @header {  require 'stringio' }
12    @init { @output = StringIO.new() }
13    @members {
14      def output
15        @output.string
16      end
17    }
18
19    program
20        :   declaration+
21        ;
22
23    /** In this rule, the functionHeader left prefix on the last two
24     *  alternatives is not LL(k) for a fixed k.  However, it is
25     *  LL(*).  The LL(*) algorithm simply scans ahead until it sees
26     *  either the ';' or the '{' of the block and then it picks
27     *  the appropriate alternative.  Lookhead can be arbitrarily
28     *  long in theory, but is <=10 in most cases.  Works great.
29     *  Use ANTLRWorks to see the look use (step by Location)
30     *  and look for blue tokens in the input window pane. :)
31     */
32    declaration
33        :   variable
34        |   functionHeader ';'
35      { @output.puts( $functionHeader.name + " is a declaration") }
36        |   functionHeader block
37      { @output.puts( $functionHeader.name + " is a definition") }
38        ;
39
40    variable
41        :   type declarator ';'
42        ;
43
44    declarator
45        :   ID
46        ;
47
48    functionHeader returns [name]
49        :   type ID '(' ( formalParameter ( ',' formalParameter )* )? ')'
50      {$name = $ID.text}
51        ;
52
53    formalParameter
54        :   type declarator
55        ;
56
57    type
58        :   'int'
59        |   'char'
60        |   'void'
61        |   ID
62        ;
63
64    block
65        :   '{'
66                variable*
67                stat*
68            '}'
69        ;
70
71    stat: forStat
72        | expr ';'
73        | block
74        | assignStat ';'
75        | ';'
76        ;
77
78    forStat
79        :   'for' '(' assignStat ';' expr ';' assignStat ')' block
80        ;
81
82    assignStat
83        :   ID '=' expr
84        ;
85
86    expr:   condExpr
87        ;
88
89    condExpr
90        :   aexpr ( ('==' | '<') aexpr )?
91        ;
92
93    aexpr
94        :   atom ( '+' atom )*
95        ;
96
97    atom
98        : ID
99        | INT
100        | '(' expr ')'
101        ;
102
103    ID  :   ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
104        ;
105
106    INT :	('0'..'9')+
107        ;
108
109    WS  :   (   ' '
110            |   '\t'
111            |   '\r'
112            |   '\n'
113            )+
114            {$channel=HIDDEN}
115        ;
116  END
117
118
119  example "parsing with a LL(*) grammar" do
120    lexer = LLStar::Lexer.new( <<-'END'.fixed_indent( 0 ) )
121      char c;
122      int x;
123
124      void bar(int x);
125
126      int foo(int y, char d) {
127        int i;
128        for (i=0; i<3; i=i+1) {
129          x=3;
130          y=5;
131        }
132      }
133    END
134    parser = LLStar::Parser.new lexer
135
136    parser.program
137    parser.output.should == <<-'END'.fixed_indent( 0 )
138      bar is a declaration
139      foo is a definition
140    END
141  end
142
143end
144