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