source: other-projects/rsyntax-textarea/devel-packages/jflex-1.4.3/examples/cup/ycalc.cup@ 25584

Last change on this file since 25584 was 25584, checked in by davidb, 12 years ago

Initial cut an a text edit area for GLI that supports color syntax highlighting

File size: 9.7 KB
Line 
1/*
2 This example comes from a short article series in the Linux
3 Gazette by Richard A. Sevenich and Christopher Lopes, titled
4 "Compiler Construction Tools". The article series starts at
5
6 http://www.linuxgazette.com/issue39/sevenich.html
7
8 Small changes and updates to newest JFlex+Cup versions
9 by Gerwin Klein
10*/
11
12/*
13 Commented By: Christopher Lopes
14 File Name: ycalc.cup
15 To Create: > java java_cup.Main < ycalc.cup
16*/
17
18
19/* ----------------------Preliminary Declarations Section--------------------*/
20
21/* Import the class java_cup.runtime.* */
22import java_cup.runtime.*;
23
24/* Parser code to change the way the parser reports errors (include
25 line and column number of the error). */
26parser code {:
27
28 /* Change the method report_error so it will display the line and
29 column of where the error occurred in the input as well as the
30 reason for the error which is passed into the method in the
31 String 'message'. */
32 public void report_error(String message, Object info) {
33
34 /* Create a StringBuffer called 'm' with the string 'Error' in it. */
35 StringBuffer m = new StringBuffer("Error");
36
37 /* Check if the information passed to the method is the same
38 type as the type java_cup.runtime.Symbol. */
39 if (info instanceof java_cup.runtime.Symbol) {
40 /* Declare a java_cup.runtime.Symbol object 's' with the
41 information in the object info that is being typecasted
42 as a java_cup.runtime.Symbol object. */
43 java_cup.runtime.Symbol s = ((java_cup.runtime.Symbol) info);
44
45 /* Check if the line number in the input is greater or
46 equal to zero. */
47 if (s.left >= 0) {
48 /* Add to the end of the StringBuffer error message
49 the line number of the error in the input. */
50 m.append(" in line "+(s.left+1));
51 /* Check if the column number in the input is greater
52 or equal to zero. */
53 if (s.right >= 0)
54 /* Add to the end of the StringBuffer error message
55 the column number of the error in the input. */
56 m.append(", column "+(s.right+1));
57 }
58 }
59
60 /* Add to the end of the StringBuffer error message created in
61 this method the message that was passed into this method. */
62 m.append(" : "+message);
63
64 /* Print the contents of the StringBuffer 'm', which contains
65 an error message, out on a line. */
66 System.err.println(m);
67 }
68
69 /* Change the method report_fatal_error so when it reports a fatal
70 error it will display the line and column number of where the
71 fatal error occurred in the input as well as the reason for the
72 fatal error which is passed into the method in the object
73 'message' and then exit.*/
74 public void report_fatal_error(String message, Object info) {
75 report_error(message, info);
76 System.exit(1);
77 }
78:};
79
80
81
82/* ------------Declaration of Terminals and Non Terminals Section----------- */
83
84/* Terminals (tokens returned by the scanner).
85
86 Terminals that have no value are listed first and then terminals
87 that do have an value, in this case an integer value, are listed on
88 the next line down. */
89terminal SEMI, PLUS, MINUS, TIMES, DIVIDE, LPAREN, RPAREN;
90terminal Integer NUMBER, ID;
91
92/* Non terminals used in the grammar section.
93
94 Non terminals that have an object value are listed first and then
95 non terminals that have an integer value are listed. An object
96 value means that it can be any type, it isn't set to a specific
97 type. So it could be an Integer or a String or whatever. */
98non terminal Object expr_list, expr_part;
99non terminal Integer expr, factor, term;
100
101
102/* -------------Precedence and Associatively of Terminals Section----------- */
103
104/*
105 Precedence of non terminals could be defined here. If you do define
106 precedence here you won't need to worry about precedence in the
107 Grammar Section, i.e. that TIMES should have a higher precedence
108 than PLUS.
109
110 The precedence defined here would look something like this where the
111 lower line always will have higher precedence than the line before it.
112
113 precedence left PLUS, MINUS;
114 precedence left TIMES, DIVIDE;
115*/
116
117
118/* ----------------------------Grammar Section-------------------- */
119
120/* The grammar for our parser.
121
122 expr_list ::= expr_list expr_part
123 | expr_part
124 expr_part ::= expr SEMI
125 expr ::= expr PLUS factor
126 | expr MINUS factor
127 | factor
128 factor ::= factor TIMES term
129 | factor DIVIDE term
130 | term
131 term ::= LPAREN expr RPAREN
132 | NUMBER
133 | ID
134*/
135
136/* 'expr_list' is the start of our grammar. It can lead to another
137 'expr_list' followed by an 'expr_part' or it can just lead to an
138 'expr_part'. The lhs of the non terminals 'expr_list' and
139 'expr_part' that are in the rhs side of the production below need
140 to be found. Then the rhs sides of those non terminals need to be
141 followed in a similar manner, i.e. if there are any non terminals
142 in the rhs of those productions then the productions with those non
143 terminals need to be found and those rhs's followed. This process
144 keeps continuing until only terminals are found in the rhs of a
145 production. Then we can work our way back up the grammar bringing
146 any values that might have been assigned from a terminal. */
147
148 expr_list ::= expr_list expr_part
149 |
150 expr_part;
151
152/* 'expr_part' is an 'expr' followed by the terminal 'SEMI'. The ':e'
153 after the non terminal 'expr' is a label an is used to access the
154 value of 'expr' which will be an integer. The action for the
155 production lies between {: and :}. This action will print out the
156 line " = + e" where e is the value of 'expr'. Before the action
157 takes places we need to go deeper into the grammar since 'expr' is
158 a non terminal. Whenever a non terminal is encountered on the rhs
159 of a production we need to find the rhs of that non terminal until
160 there are no more non terminals in the rhs. So when we finish
161 going through the grammar and don't encounter any more non
162 terminals in the rhs productions will return until we get back to
163 'expr' and at that point 'expr' will contain an integer value. */
164
165 expr_part ::= expr:e
166 {: System.out.println(" = " + e); :}
167 SEMI
168 ;
169
170/* 'expr' can lead to 'expr PLUS factor', 'expr MINUS factor', or
171 'factor'. The 'TIMES' and 'DIVIDE' productions are not at this
172 level. They are at a lower level in the grammar which in affect
173 makes them have higher precedence. Actions for the rhs of the non
174 terminal 'expr' return a value to 'expr'. This value that is
175 created is an integer and gets stored in 'RESULT' in the action.
176 RESULT is the label that is assigned automatically to the rhs, in
177 this case 'expr'. If the rhs is just 'factor' then 'f' refers to
178 the non terminal 'factor'. The value of 'f' is retrieved with the
179 function 'intValue()' and will be stored in 'RESULT'. In the other
180 two cases 'f' and 'e' refers to the non terminals 'factor' and
181 'expr' respectively with a terminal between them, either 'PLUS' or
182 'MINUS'. The value of each is retrieved with the same function
183 'intValue'. The values will be added or subtracted and then the
184 new integer will be stored in 'RESULT'.*/
185
186 expr ::= expr:e PLUS factor:f
187 {: RESULT = new Integer(e.intValue() + f.intValue()); :}
188 |
189 expr:e MINUS factor:f
190 {: RESULT = new Integer(e.intValue() - f.intValue()); :}
191 |
192 factor:f
193 {: RESULT = new Integer(f.intValue()); :}
194 ;
195
196/* 'factor' can lead to 'factor TIMES term', 'factor DIVIDE term', or
197 'term'. Since the productions for TIMES and DIVIDE are lower in
198 the grammar than 'PLUS' and 'MINUS' they will have higher
199 precedence. The same sort of actions take place in the rhs of
200 'factor' as in 'expr'. The only difference is the operations that
201 takes place on the values retrieved with 'intValue()', 'TIMES' and
202 'DIVIDE' here instead of 'PLUS' and 'MINUS'. */
203
204 factor ::= factor:f TIMES term:t
205 {: RESULT = new Integer(f.intValue() * t.intValue()); :}
206 |
207 factor:f DIVIDE term:t
208 {: RESULT = new Integer(f.intValue() / t.intValue()); :}
209 |
210 term:t
211 {: RESULT = new Integer(t.intValue()); :}
212 ;
213
214/* 'term' can lead to 'LPAREN expr RPAREN', 'NUMBER', or 'ID'. The
215 first production has the non terminal 'expr' in it so the
216 production with its lhs side needs to be found and followed. The
217 next rhs has no non terminals. So the grammar ends here and can go
218 back up. When it goes back up it will bring the value that was
219 retrieved when the scanner encounter the token 'NUMBER'. 'RESULT'
220 is assigned 'n', which refers to 'NUMBER', as the action for this
221 production. The same action occurs for 'ID', except the 'i' is
222 used to refer to 'ID'. 'ID' is also the only thing on the rhs of
223 the production. And since 'ID' is a terminal the grammar will end
224 here and go back up. */
225
226 term ::= LPAREN expr:e RPAREN
227 {: RESULT = e; :}
228 |
229 NUMBER:n
230 {: RESULT = n; :}
231 |
232 ID:i
233 {: RESULT = i; :}
234 ;
Note: See TracBrowser for help on using the repository browser.