Hi all
Now I struggling to construct a compiler for a simple grammar as show
below, which doesn't include type checking, in two passes, front
end(semantic analyzer) and back end.
At first I started to construct the semantic analyzer and it seems run
correctly but the part of procedure declaration didn't work( may be
because there is no semantic actions associated with it so I am little
confused).
Package cmm;
Tokens
var = 'var';
main = 'main';
lpar = '(';
rpar = ')';
comma = ',';
lbra = '{';
rbra = '}';
write = 'write';
writeln = 'writeln';
semi = ';';
plus = '+';
minus = '-';
mult = '*';
div = '/';
if = 'if';
then = 'then';
else = 'else';
endif = 'endif';
while = 'while';
do = 'do';
read = 'read';
return = 'return';
coleq = ':=';
ge = '>=';
gt = '>';
le = '<=';
lt = '<';
ne = '!=';
eq = '==';
number = ['0'..'9']+;
id = ['a'..'z'] (['a'..'z'] | ['0'..'9'])*;
blank = (' '|13|10)+;
Ignored Tokens
blank;
Productions
program = fdecls main_st
;
main_st = main body
;
fdecls =
{multi_fdecls} fdecls fdecl |
{no_fdecl}
;
fdecl = fhead body
;
fhead = fid lpar param_action rpar
;
fid = id
;
param_action = params
;
params =
{multi_params} params comma id |
{one_param} id |
{no_param}
;
body = lbra vdaction stmts rbra
;
vdaction = vardecls
;
vardecls=
{multi_var_decls} vardecls vardecl |
{no_var_decl}
;
vardecl = var ids semi
;
ids =
{multi_ids} ids comma id |
{one_id} id
;
stmts =
{multi_stmts} stmts st |
{one_stmt} st
;
st =
{write_st} write expression semi |
{writeln_st} writeln semi |
{read_st} read id semi |
{assign_st} id coleq expression semi |
{if_st} ifstmt |
{while_st} whilestmt |
{body_st} body |
{return_st} return expression semi
;
ifstmt =
{if_then} if cond then st endif semi |
{if_then_else} if cond then [left]:st else [right]:st endif semi
;
whilestmt = while cond do st
;
cond =
{cond_gt} [left]:expression gt [right]:expression |
{cond_ge} [left]:expression ge [right]:expression |
{cond_lt} [left]:expression lt [right]:expression |
{cond_le} [left]:expression le [right]:expression |
{cond_ne} [left]:expression ne [right]:expression |
{cond_eq} [left]:expression eq [right]:expression
;
expression =
{explus} expression plus term |
{exminus} expression minus term |
{exterm} term
;
term =
{termmult} term mult factor |
{termdiv} term div factor |
{termfactor} factor
;
factor =
{factid} id |
{factfc} id lpar fparams rpar |
{factnum} number |
{factparen} lpar expression rpar
;
fparams =
{fparams} fparams comma fparam |
{fparam} fparam |
{noparam}
;
fparam = expression
;
So at first to design the semantic analyzer, I have to decide what the
semantic actions needed at each node
as in the following :
1. Because my grammar doesn't contain type checking it would be easy
since the attributes maybe is
the token name only for identifiers, but I constructed Lst class to
include 4 attributes(name, kind, level,params)
for the identifier also level is used for scopeing and kind represents
4 casesVAR, FUNC, BLOCK, AND
CONST and params , which is the number of paramaters of the procedure..
2. I have to evaluate the part of expressions
3 the procedure attribute which is params,
so for example in the case of identifer params = 0,
4. My confused is here , do I have to add semantic actions for if
statement and while statement (of course including condition part)at
this step or can I delay that for back end step.
Also I designed Information class , the information which will be
added at each node and SymMnger2 class for managing symbol table in
addition to Lst classed which I menetioned about it before.
Is the above steps ok to implement semantic analyzer?
According to the above grammar and above steps, I design the semantic
analyzer as in the following code :
(sorry if the code is little long)
I send it because I am really confused about what I have to do exactly
to implement semantic analyzer.
and I ask if any body can help to clarify every thing in
implementaion process and to check if what I did
is correct or not and try to help in finding my mistakes in my
program( the part related to procedure declaration and maybe other
positions in the code).
1. Lst class
1 package cmm;
2
3 public class Lst {
4 private String name;
5 private int kind;
6 private int level;
7 private int params;
8 private Lst prev;
9
10 public Lst(String name, int kind, int level, int params) {
11 this.name = name;
12 this.kind = kind;
13 this.level = level;
14 this.params = params;
15 this.prev = null;
16 }
17
18 public void setParams(int params) {
19 this.params = params;
20 }
21
22 public int getParams() {
23 return params;
24 }
25
26 public void setPrev(Lst prev) {
27 this.prev = prev;
28 }
29
30 public Lst getPrev() {
31 return prev;
32 }
33
34 public String getName() {
35 return name;
36 }
37
38 public int getKind() {
39 return kind;
40 }
41
42 public int getLevel() {
43 return level;
44 }
45
46 public String toString() {
47 return "name :" + name + "kind :" + kind + "level :" + level +
48 "paramaters :" + params;
49 }
50 }
2. Information class
1 package cmm;
2 import java.util.*;
3
4 public class Information {
5 private LinkedList<Information> list;
6 private Lst list2;
7 private int val;
8 private int number;
9
10 public Information() {
11 list = new LinkedList<Information>();
12 list2 = null;
13 val = 0;
14 }
15
16 public Information(LinkedList<Information> list) {
17 this.list = list;
18 list2 = null;
19 val = 0;
20 }
21
22 public Information(Lst list2) {
23 this.list2 = list2;
24 list = null;
25 val = 0;
26 }
27
28 public Information(int val) {
29 this.val = val;
30 list = null;
31 list2 = null;
32 }
33
34 public LinkedList<Information> getList() {
35 return list;
36 }
37
38 public Lst getList2() {
39 return list2;
40 }
41
42 public int getVal() {
43 return val;
44 }
45
46 public void setNumber(int number) {
47 this.number = number;
48 }
49
50 public int getNumber() {
51 return number;
52 }
53
54 public void addChild(Information inf) {
55 list.add(inf);
56 }
57
58 public void printInfo() {
59 System.out.println("Attributes of the syntax tree : ");
60 for(Information info : list) {
61 System.out.println(" no of Variables :" + info.getVal()
+ info.getList2());
62 }
63 }
64 }
3. SymMnger2 class
1 package cmm;
2 import java.util.*;
3
4 public class SymMnger2 {
5 public static final int VAR = 0;
6 public static final int BLOCK = 1;
7 public static final int FUNC = 2;
8 public static final int CONST = 4;
9
10 Lst head = null, tail = null;
11 private int level = 0;
12
13 public SymMnger2() {
14 head = tail = null;
15 }
16
17 public void setLevel(int level) {
18 this.level = level;
19 }
20
21 public int getLevel() {
22 return level;
23 }
24
25 public void enterScope() {
26 level++;
27 registName(null, BLOCK, 0, 0);
28 }
29
30 public void leaveScope() {
31 Lst list;
32 for(list = tail; list != head && list.getKind() != BLOCK;
33 list = list.getPrev()) {
34 }
35 tail = list.getPrev();
36 level--;
37 }
38
39 public Lst searchCurrent(String name) {
40 Lst list;
41 for(list = tail; list != head && list.getKind() != BLOCK;
42 list = list.getPrev()) {
43 if(name.equals(list.getName())) {
44 return list;
45 }
46 }
47 return null;
48 }
49
50 public Lst searchAll(String name) {
51 Lst list;
52 for(list = tail; list != head; list = list.getPrev()) {
53 if(name.equals(list.getName())) {
54 return list;
55 }
56 }
57 return null;
58 }
59
60 public void registName(String name, int kind, int level, int
fParam ) {
61 Lst list = new Lst(name, kind, level, fParam);
62 list.setPrev(tail);
63 tail = list;
64 }
65
66 public Lst searchF(int level) {
67 Lst list;
68
69 for(list = tail; list != null; list = list.getPrev()) {
70 if(list.getKind() == FUNC && list.getLevel() == level-1) {
71 return list;
72 }
73 }
74 System.out.println("searchF");
75 return list;
76 }
77
78 public void proc_params(int val) {
79 Lst list = null;
80
81 for(; list.getKind() != FUNC; list = list.getPrev()) {
82 }
83 list.setParams(val);
84 }
85 }
4. Semantic class (which is hte semantic analyzer)
1 package cmm;
2 import cmm.analysis.*;
3 import cmm.node.*;
4 import cmm.*;
5 import java.util.*;
6
7 class Semantic extends DepthFirstAdapter {
8 public Hashtable table = new Hashtable(10001);
9 private SymMnger2 st;
10 private int level;
11
12 Semantic(SymMnger2 st) {
13 this.st = st;
14 }
15
16 public void outAProgram(AProgram node) {
17 Information i1 = (Information)table.get(node.getFdecls());
18 Information i2 = (Information)table.get(node.getMainSt());
19 Information info = new Information();
20
21 info.addChild(i1);
22 info.addChild(i2);
23 //info.printInfo();
24 }
25
26 public void outAMainSt(AMainSt node) {
27 Information info = (Information)table.get(node.getBody());
28 table.put(node, info);
29 }
30
31 public void outAMultiFdeclsFdecls(AMultiFdeclsFdecls node) {
32 Information i1 = (Information)table.get(node.getFdecls());
33 Information i2 = (Information)table.get(node.getFdecl());
34 Information info = new Information();
35
36 info.addChild(i1);
37 info.addChild(i2);
38 table.put(node, info);
39 }
40
41 public void outANoFdeclFdecls(ANoFdeclFdecls node) {
42 Information info = new Information();
43 table.put(node, info);
44 }
45
46 public void outAFdecl(AFdecl node) {
47 Information i1 = (Information)table.get(node.getFhead());
48 Information i2 = (Information)table.get(node.getBody());
49 Information info = new Information();
50
51 info.addChild(i1);
52 info.addChild(i2);
53 table.put(node, info);
54 }
55
56 public void outAFhead(AFhead node) {
57 Information i1 = (Information)table.get(node.getFid());
58 Information i2 = (Information)table.get(node.getParamAction());
59 st.proc_params(i2.getVal());
60 Information info = new Information();
61 info.addChild(i1);
62 info.addChild(i2);
63 table.put(node, info);
64 }
65
66 public void outAFid(AFid node) {
67 String name = node.getId().getText();
68
69 if (st.searchAll(name) == null){
70 st.registName(name, SymMnger2.FUNC, st.getLevel(), 0);
71 }
72 else {
73 System.out.println("This identifier has been already
declared(4)!");
74 System.exit(0);
75 }
76 st.registName("block", SymMnger2.BLOCK, 0, 0);
77 }
78
79 public void inAParamAction(AParamAction node) {
80 st.setLevel(level++);
81 }
82
83 public void outAParamAction(AParamAction node) {
84 Information info = (Information)table.get(node.getParams());
85 st.setLevel(level--);
86 table.put(node, info);
87 }
88
89 public void outAMultiParamsParams(AMultiParamsParams node) {
90 String name = node.getId().getText();
91
92 if (st.searchCurrent(name) == null){
93 st.registName(name, SymMnger2.VAR, st.getLevel(), 0);
94 } else {
95 System.out.println("This identifier has been already " +
96 "declared(p1)!");
97 System.exit(0);
98 }
99
100 Information i = (Information)table.get(node.getParams());
101 Information info = new Information(i.getVal()+1);
102 table.put(node, info);
103 }
104
105 public void outAOneParamParams(AOneParamParams node) {
106 String name = node.getId().getText();
107
108 if (st.searchCurrent(name) == null) {
109 st.registName(name, SymMnger2.VAR, st.getLevel(), 0);
110 }
111 else {
112 System.out.println("This identifier has been already" +
113 "declared(p2)!");
114 System.exit(0);
115 }
116
117 Information info = new Information(1);
118 table.put(node, info);
119 }
120
121 public void outANoParamParams(ANoParamParams node) {
122 Information info = new Information(0);
123 table.put(node, info);
124 }
125
126 public void inABody(ABody node) {
127 st.enterScope();
128 }
129
130 public void outABody(ABody node) {
131 Information i1 = (Information)table.get(node.getVdaction());
132 Information i2 = (Information)table.get(node.getStmts());
133 Information info = new Information();
134
135 info.addChild(i1);
136 info.addChild(i2);
137 table.put(node, info);
138 st.leaveScope();
139 }
140
141 public void outAVdaction(AVdaction node) {
142 Information info = (Information)table.get(node.getVardecls());
143 table.put(node, info);
144 }
145
146 public void outAMultiVarDeclsVardecls(AMultiVarDeclsVardecls node) {
147 Information i1 = (Information)table.get(node.getVardecls());
148 Information i2 = (Information)table.get(node.getVardecl());
149 Information info = new Information(i1.getVal()+i2.getVal());
150
151 table.put(node, info);
152 }
153
154 public void outANoVarDeclVardecls(ANoVarDeclVardecls node) {
155 Information info = new Information();
156 table.put(node, info);
157 }
158
159 public void outAVardecl(AVardecl node) {
160 Information i = (Information)table.get(node.getIds());
161 Information info = new Information(i.getVal());
162
163 table.put(node, info);
164 }
165
166 public void outAMultiIdsIds(AMultiIdsIds node) {
167 String name = node.getId().getText();
168 Lst list = st.searchCurrent(name);
169 if (list == null){
170 st.registName(name, st.VAR, st.getLevel(), 0);
171 }
172 else {
173 System.out.println("This identifier has been " +
174 "already declared(2)!");
175 System.exit(0);
176 }
177
178 Information i = (Information)table.get(node.getIds());
179 Information info = new Information(i.getVal()+1);
180
181 table.put(node, info);
182 }
183
184 public void outAOneIdIds(AOneIdIds node) {
185 String name = node.getId().getText();
186 Lst list = st.searchCurrent(name);
187 if (list == null){
188 st.registName(name, st.VAR, st.getLevel(), 0);
189 }
190 else {
191 System.out.println("This identifier has been" +
192 "already declared(3)!");
193 System.exit(0);
194 }
195
196 Information info = new Information(1);
197 table.put(node, info);
198 }
199
200 public void outAMultiStmtsStmts(AMultiStmtsStmts node) {
201 Information i1 = (Information)table.get(node.getStmts());
202 Information i2 = (Information)table.get(node.getSt());
203
204 Information info = new Information();
205 info.addChild(i1);
206 info.addChild(i2);
207 table.put(node, info);
208 }
209
210 public void outAOneStmtStmts(AOneStmtStmts node) {
211 Information info = (Information)table.get(node.getSt());
212 table.put(node, info);
213 }
214
215 public void outAWriteStSt(AWriteStSt node) {
216 Information i = (Information)table.get(node.getExpression());
217 Information info = new Information();
218 info.setNumber(i.getNumber());
219 table.put(node, info);
220 }
221
222 public void outAWritelnStSt(AWritelnStSt node) {
223 Information info = new Information();
224 table.put(node, info);
225 }
226
227 public void outAReadStSt(AReadStSt node) {
228 String name = node.getId().getText();
229 Lst list = st.searchAll(name);
230
231 if (list == null){
232 System.out.println("This identifier(" +
233 name +
234 ") has not been declared!");
235 System.exit(0);
236 }
237
238 if (list.getKind() != SymMnger2.VAR){
239 System.out.println("This identifier(" +
240 name +
241 ") has not been declared as identifier!");
242 System.exit(0);
243 }
244
245 Information info = new Information(list);
246 table.put(node, info);
247 }
248
249 public void outAAssignStSt(AAssignStSt node) {
250 Lst list;
251
252 String name = node.getId().getText();
253 list = st.searchAll(name);
254 if (list == null){
255 System.out.println("This identifier(" +
256 name +
257 ") has not been declared!");
258 System.exit(0);
259 }
260
261 if (list.getKind() != SymMnger2.VAR){
262 System.out.println("This identifier(" +
263 name +
264 ") has not been declared as identifier!");
265 System.exit(0);
266 }
267
268 Information i1 = (Information)table.get(node.getExpression());
269 Information i2 = new Information(list);
270 Information info = new Information();
271 info.setNumber(i1.getNumber());
272 info.addChild(i2);
273 table.put(node, info);
274 }
275
276 public void outAIfStSt(AIfStSt node) {
277 Information info = (Information)table.get(node.getIfstmt());
278 table.put(node, info);
279 }
280
281 public void outAWhileStSt(AWhileStSt node)
282 {
283 Information info = (Information)table.get(node.getWhilestmt());
284 table.put(node, info);
285 }
286
287 public void outABodyStSt(ABodyStSt node) {
288 Information info = (Information)table.get(node.getBody());
289 table.put(node, info);
290 }
291
292 public void outAReturnStSt(AReturnStSt node) {
293 Information i = (Information)table.get(node.getExpression());
294 Information info = new Information();
295 info.setNumber(i.getNumber());
296 table.put(node, info);
297 }
298
299 public void outAIfThenIfstmt(AIfThenIfstmt node) {
300 Information i1 = (Information)table.get(node.getCond());
301 Information i2 = (Information)table.get(node.getSt());
302 Information info = new Information();
303
304 info.addChild(i1);
305 info.addChild(i2);
306 table.put(node, info);
307 }
308
309 public void outAIfThenElseIfstmt(AIfThenElseIfstmt node) {
310 Information i1 = (Information)table.get(node.getCond());
311 Information i2 = (Information)table.get(node.getLeft());
312 Information i3 = (Information)table.get(node.getRight());
313 Information info = new Information();
314
315 info.addChild(i1);
316 info.addChild(i2);
317 info.addChild(i2);
318 table.put(node, info);
319 }
320
321 public void outAWhilestmt(AWhilestmt node) {
322 Information i1 = (Information)table.get(node.getCond());
323 Information i2 = (Information)table.get(node.getSt());
324 Information info = new Information();
325
326 info.addChild(i1);
327 info.addChild(i2);
328 table.put(node, info);
329 }
330
331 public void outACondGtCond(ACondGtCond node) {
332 Information i1 = (Information)table.get(node.getLeft());
333 Information i2 = (Information)table.get(node.getRight());
334 Information info = new Information();
335 info.addChild(i1);
336 info.addChild(i2);
337 table.put(node, info);
338 }
339
340 public void outACondGeCond(ACondGeCond node) {
341 Information i1 = (Information)table.get(node.getLeft());
342 Information i2 = (Information)table.get(node.getRight());
343 Information info = new Information();
344
345 info.addChild(i1);
346 info.addChild(i2);
347 table.put(node, info);
348 }
349
350 public void outACondLtCond(ACondLtCond node) {
351 Information i1 = (Information)table.get(node.getLeft());
352 Information i2 = (Information)table.get(node.getRight());
353 Information info = new Information();
354
355 info.addChild(i1);
356 info.addChild(i2);
357 table.put(node, info);
358 }
359
360 public void outACondLeCond(ACondLeCond node) {
361 Information i1 = (Information)table.get(node.getLeft());
362 Information i2 = (Information)table.get(node.getRight());
363 Information info = new Information();
364
365 info.addChild(i1);
366 info.addChild(i2);
367 table.put(node, info);
368 }
369
370 public void outACondNeCond(ACondNeCond node) {
371 Information i1 = (Information)table.get(node.getLeft());
372 Information i2 = (Information)table.get(node.getRight());
373 Information info = new Information();
374
375 info.addChild(i1);
376 info.addChild(i2);
377 table.put(node, info);
378 }
379
380 public void outACondEqCond(ACondEqCond node) {
381 Information i1 = (Information)table.get(node.getLeft());
382 Information i2 = (Information)table.get(node.getRight());
383 Information info = new Information();
384
385 info.addChild(i1);
386 info.addChild(i2);
387 table.put(node, info);
388 }
389
390 public void outAExplusExpression(AExplusExpression node) {
391 Information i1 = (Information)table.get(node.getExpression());
392 Information i2 = (Information)table.get(node.getTerm());
393 Information info = new Information();
394
395 info.setNumber(i1.getNumber() + i2.getNumber());
396 table.put(node, info);
397 }
398
399 public void outAExminusExpression(AExminusExpression node) {
400 Information i1 = (Information)table.get(node.getExpression());
401 Information i2 = (Information)table.get(node.getTerm());
402 Information info = new Information();
403
404 info.setNumber(i1.getNumber() - i2.getNumber());
405 table.put(node, info);
406 }
407
408 public void outAExtermExpression(AExtermExpression node ){
409 Information info = (Information)table.get(node.getTerm());
410 table.put(node, info);
411 }
412
413 public void outATermmultTerm(ATermmultTerm node) {
414 Information i1 = (Information)table.get(node.getTerm());
415 Information i2 = (Information)table.get(node.getFactor());
416 Information info = new Information();
417
418 info.setNumber(i1.getNumber() * i2.getNumber());
419 table.put(node, info);
420 }
421
422 public void outATermdivTerm(ATermdivTerm node) {
423 Information i1 = (Information)table.get(node.getTerm());
424 Information i2 = (Information)table.get(node.getFactor());
425 Information info = new Information();
426
427 info.setNumber(i1.getNumber() / i2.getNumber());
428 table.put(node, info);
429 }
430
431 public void outATermfactorTerm(ATermfactorTerm node) {
432 Information info = (Information)table.get(node.getFactor());
433 table.put(node, info);
434 }
435
436 public void outAFactidFactor(AFactidFactor node) {
437 String name = node.getId().getText();
438
439 Lst list = st.searchAll(name);
440 if (list == null){
441 System.out.println("This identifier(" +
442 name +
443 ") is not declared!! (F1)");
444 System.exit(0);
445 }
446
447 if (list.getKind() == SymMnger2.VAR){
448 Information info = new Information(list);
449 table.put(node, info);
450 }
451 else {
452 System.out.println("This identifier (" +
453 name +
454 ") is not declared as variable or constant");
455 System.exit(0);
456 }
457 }
458
459 public void outAFactfcFactor(AFactfcFactor node) {
460 String name = node.getId().getText();
461 Lst list = st.searchAll(name);
462
463 if (list == null){
464 System.out.println("This identifier (" +
465 name +
466 ") is not declared!!(f3)");
467 System.exit(0);
468 }
469
470 if (list.getKind() != SymMnger2.FUNC){
471 System.out.println("This identifier (" +
472 name +
473 ") is not declared as function");
474 System.exit(0);
475 }
476
477 Information i1 = (Information)table.get(node.getFparams());
478 Information i2 = new Information(list);
479
480 if (list.getParams() != i1.getVal()){
481 System.out.println("The number of parameters does not match" +
482 " as the declaration(" + name +
483 " : " +
484 list.getParams() +
485 " -> " +
486 i1.getVal() +
487 ")");
488 System.exit(0);
489 }
490 Information info = new Information();
491 info.addChild(i1);
492 info.addChild(i2);
493 table.put(node, info);
494 }
495
496 public void outAFactnumFactor(AFactnumFactor node) {
497 int x = Integer.parseInt(node.getNumber().getText());
498 Information info = new Information();
499 info.setNumber(x);
500 table.put(node, info);
501 }
502
503 public void outAFactparenFactor(AFactparenFactor node) {
504 Information info = (Information)table.get(node.getExpression());
505 table.put(node, info);
506 }
507
508 public void outAFparamsFparams(AFparamsFparams node) {
509 Information i1 = (Information)table.get(node.getFparams());
510 Information i2 = (Information)table.get(node.getFparam());
511 Information info = new Information(i1.getVal()+i2.getVal());
512 table.put(node, info);
513 }
514
515 public void outAFparamFparams(AFparamFparams node) {
516 Information info = new Information(1);
517 table.put(node, info);
518 }
519
520 public void outANoparamFparams(ANoparamFparams node) {
521 Information info = new Information(0);
522 table.put(node, info);
523 }
524
525 public void outAFparam(AFparam node) {
526 Information info = (Information)table.get(node.getExpression());
527 table.put(node, info);
528 }
529 }
5. SemanticTest class(for testing)
1 package cmm;
2
3 import cmm.parser.*;
4 import cmm.lexer.*;
5 import cmm.node.*;
6 import java.io.*;
7
8 public class SemanticTest {
9 public static void main (String[] arguments) {
10 SymMnger2 table = new SymMnger2();
11
12 try {
13 System.out.println("Enter a program :");
14
15 Parser p = new Parser(new Lexer(new PushbackReader
16 (new
InputStreamReader(System.in), 1024)));
17
18 Start tree = p.parse();
19 tree.apply(new Semantic(table));
20 }
21 catch(Exception e) {
22 System.out.println(e.getMessage());
23 }
24 }
25 }
I am so sorry to write what I did exactly,but the reason is to
understand and make sure from every step in implementaion.
so please take it easy and try to help me to understand , even if it
takes from you several emails till I manage and understand.
So I appreciate really any one who try to help in understanding how to
construct semantic analyzer till I run my program correctly.
thanks in advance.
_______________________________________________
SableCC-Discussion mailing list
[email protected]
http://lists.sablecc.org/listinfo/sablecc-discussion