aState
141 | */
142 |
143 | private val ZZ_ATTRIBUTE_PACKED_0:String =
144 | "\1\0\1\1\1\11\1\1\1\11\1\1";
145 |
146 | private def zzUnpackAttribute() : Array[Int] = {
147 | val result:Array[Int] = new Array[Int](6);
148 | var offset:Int = 0;
149 | offset = zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
150 | return result;
151 | }
152 |
153 | private def zzUnpackAttribute(packed:String,offset:Int,result:Array[Int]) : Int = {
154 | var i:Int = 0; /* index in packed string */
155 | var j:Int = offset; /* index in unpacked array */
156 | val l:Int = packed.length();
157 | while (i < l) {
158 | var count:Int = packed.charAt(i); i+= 1;
159 | var value:Int = packed.charAt(i); i+= 1;
160 | do { result(j) = value; j+=1; count -= 1; } while (count > 0);
161 | }
162 | return j;
163 | }
164 | private val ZZ_ATTRIBUTE:Array[Int] = zzUnpackAttribute();
165 |
166 |
167 | /** the current state of the DFA */
168 | private var zzState : Int = 0;
169 |
170 | /** the current lexical state */
171 | private var zzLexicalState : Int = YYINITIAL;
172 |
173 | /** this buffer contains the current text to be matched and is
174 | the source of the yytext() string */
175 | private var zzBuffer : Array[Char] = new Array(ZZ_BUFFERSIZE);
176 |
177 | /** the textposition at the last accepting state */
178 | private var zzMarkedPos : Int = 0;
179 |
180 | /** the current text position in the buffer */
181 | private var zzCurrentPos : Int = 0;
182 |
183 | /** startRead marks the beginning of the yytext() string in the buffer */
184 | private var zzStartRead : Int = 0;
185 |
186 | /** endRead marks the last character in the buffer, that has been read
187 | from input */
188 | private var zzEndRead : Int = 0;
189 |
190 | /** number of newlines encountered up to the start of the matched text */
191 | private var yyline : Int = 0;
192 |
193 | /** the number of characters up to the start of the matched text */
194 | private var yychar : Int = 0;
195 |
196 | /**
197 | * the number of characters from the last newline up to the start of the
198 | * matched text
199 | */
200 | private var yycolumn : Int = 0;
201 |
202 | /**
203 | * zzAtBOL == true <=> the scanner is currently at the beginning of a line
204 | */
205 | private var zzAtBOL : Boolean = true;
206 |
207 | /** zzAtEOF == true <=> the scanner is at the EOF */
208 | private var zzAtEOF : Boolean = false;
209 |
210 | /* user code: */
211 | // These features are added to the Scanner class
212 | var lookahead : CalcTokens.YYToken = null;
213 |
214 | override def hasNext() : Boolean = {
215 | if (lookahead == null) lookahead = yylex();
216 | lookahead match {
217 | case x:CalcTokens.YYEOF => false;
218 | case x:CalcTokens.YYToken => true;
219 | }
220 | };
221 |
222 | override def next() : CalcTokens.YYToken = {
223 | if (lookahead == null) lookahead = yylex();
224 | var result : CalcTokens.YYToken = lookahead;
225 | lookahead = null;
226 | result
227 | };
228 |
229 | def getLineNumber() : Int = yyline+1;
230 |
231 |
232 |
233 | /**
234 | * Creates a new scanner
235 | * There is also a java.io.InputStream version of this constructor.
236 | *
237 | * @param in the java.io.Reader to read input from.
238 | */
239 |
240 | /**
241 | * Unpacks the compressed character translation table.
242 | *
243 | * @param packed the packed character translation table
244 | * @return the unpacked character translation table
245 | */
246 | private def zzUnpackCMap(packed:String) : Array[Char] = {
247 | val map:Array[Char] = new Array[Char](0x10000);
248 | var i:Int = 0; /* index in packed string */
249 | var j:Int = 0; /* index in unpacked array */
250 | while (i < 34) {
251 | var count:Int = packed.charAt(i); i+= 1;
252 | var value:Char = packed.charAt(i); i+= 1;
253 | do { map(j) = value; j+=1; count-=1; } while (count > 0);
254 | }
255 | return map;
256 | }
257 |
258 |
259 | /**
260 | * Refills the input buffer.
261 | *
262 | * @return false
, iff there was new input.
263 | */
264 | private def zzRefill() : Boolean = {
265 |
266 | /* first: make room (if you can) */
267 | if (zzStartRead > 0) {
268 | System.arraycopy(zzBuffer, zzStartRead,
269 | zzBuffer, 0,
270 | zzEndRead-zzStartRead);
271 |
272 | /* translate stored positions */
273 | zzEndRead-= zzStartRead;
274 | zzCurrentPos-= zzStartRead;
275 | zzMarkedPos-= zzStartRead;
276 | zzStartRead = 0;
277 | }
278 |
279 | /* is the buffer big enough? */
280 | if (zzCurrentPos >= zzBuffer.length) {
281 | /* if not: blow it up */
282 | val newBuffer : Array[Char] = new Array(zzCurrentPos*2);
283 | System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
284 | zzBuffer = newBuffer;
285 | }
286 |
287 | /* finally: fill the buffer with new input */
288 | val numRead : Int = zzReader.read(zzBuffer, zzEndRead,
289 | zzBuffer.length-zzEndRead);
290 |
291 | if (numRead > 0) {
292 | zzEndRead+= numRead;
293 | return false;
294 | }
295 | // unlikely but not impossible: read 0 characters, but not at end of stream
296 | if (numRead == 0) {
297 | val c : Int = zzReader.read();
298 | if (c == -1) {
299 | return true;
300 | } else {
301 | zzBuffer(zzEndRead) = c toChar;
302 | zzEndRead += 1
303 | return false;
304 | }
305 | }
306 |
307 | // numRead < 0
308 | return true;
309 | }
310 |
311 |
312 | /**
313 | * Closes the input stream.
314 | */
315 | def yyclose() : Unit = {
316 | zzAtEOF = true; /* indicate end of file */
317 | zzEndRead = zzStartRead; /* invalidate buffer */
318 |
319 | if (zzReader != null)
320 | zzReader.close();
321 | }
322 |
323 |
324 | /**
325 | * Resets the scanner to read from a new input stream.
326 | * Does not close the old reader.
327 | *
328 | * All internal variables are reset, the old input stream
329 | * cannot be reused (internal buffer is discarded and lost).
330 | * Lexical state is set to ZZ_INITIAL.
331 | *
332 | * @param reader the new input stream
333 | */
334 | def yyreset(reader : java.io.Reader) : Unit = {
335 | zzReader = reader;
336 | zzAtBOL = true;
337 | zzAtEOF = false;
338 | zzEndRead = 0; zzStartRead = 0;
339 | zzCurrentPos = 0; zzMarkedPos = 0;
340 | yyline = 0; yychar = 0; yycolumn = 0;
341 | zzLexicalState = YYINITIAL;
342 | }
343 |
344 |
345 | /**
346 | * Returns the current lexical state.
347 | */
348 | def yystate() : Int = {
349 | zzLexicalState;
350 | }
351 |
352 |
353 | /**
354 | * Enters a new lexical state
355 | *
356 | * @param newState the new lexical state
357 | */
358 | def yybegin(newState : Int) : Unit = {
359 | zzLexicalState = newState;
360 | }
361 |
362 |
363 | /**
364 | * Returns the text matched by the current regular expression.
365 | */
366 | def yytext() : String = {
367 | new String( zzBuffer, zzStartRead, zzMarkedPos-zzStartRead );
368 | }
369 |
370 |
371 | /**
372 | * Returns the character at position pos from the
373 | * matched text.
374 | *
375 | * It is equivalent to yytext().charAt(pos), but faster
376 | *
377 | * @param pos the position of the character to fetch.
378 | * A value from 0 to yylength()-1.
379 | *
380 | * @return the character at position pos
381 | */
382 | def yycharat(pos : Int) : Char = {
383 | zzBuffer(zzStartRead+pos);
384 | }
385 |
386 |
387 | /**
388 | * Returns the length of the matched text region.
389 | */
390 | def yylength() : Int = {
391 | zzMarkedPos-zzStartRead;
392 | }
393 |
394 |
395 | /**
396 | * Reports an error that occured while scanning.
397 | *
398 | * In a wellformed scanner (no or only correct usage of
399 | * yypushback(int) and a match-all fallback rule) this method
400 | * will only be called with things that "Can't Possibly Happen".
401 | * If this method is called, something is seriously wrong
402 | * (e.g. a JFlex bug producing a faulty scanner etc.).
403 | *
404 | * Usual syntax/scanner level error handling should be done
405 | * in error fallback rules.
406 | *
407 | * @param errorCode the code of the errormessage to display
408 | */
409 | private def zzScanError(errorCode:Int) : Unit = {
410 | var message : String = null;
411 | try {
412 | message = ZZ_ERROR_MSG(errorCode);
413 | } catch {
414 | case e:ArrayIndexOutOfBoundsException =>
415 | message = ZZ_ERROR_MSG(ZZ_UNKNOWN_ERROR);
416 | }
417 |
418 | throw new Error(message);
419 | }
420 |
421 |
422 | /**
423 | * Pushes the specified amount of characters back into the input stream.
424 | *
425 | * They will be read again by then next call of the scanning method
426 | *
427 | * @param number the number of characters to be read again.
428 | * This number must not be greater than yylength()!
429 | */
430 | def yypushback(number:Int) : Unit = {
431 | if ( number > yylength() )
432 | zzScanError(ZZ_PUSHBACK_2BIG);
433 |
434 | zzMarkedPos -= number;
435 | }
436 |
437 | /** Nested class to simulate multi-level break */
438 | private case class ZZbreak(name:String) extends Throwable;
439 |
440 | /**
441 | * Resumes scanning until the next regular expression is matched,
442 | * the end of input is encountered or an I/O-Error occurs.
443 | *
444 | * @return the next token
445 | * @exception java.io.IOException if any I/O-Error occurs
446 | */
447 | def yylex() : CalcTokens.YYToken =
448 | {
449 | var zzInput : Int = 0;
450 | var zzAction : Int = 0;
451 |
452 | // cached fields:
453 | var zzCurrentPosL : Int = 0;
454 | var zzMarkedPosL : Int = 0;
455 | var zzEndReadL : Int = zzEndRead;
456 | var zzBufferL : Array[Char] = zzBuffer;
457 | var zzCMapL : Array[Char] = ZZ_CMAP;
458 |
459 | val zzTransL:Array[Int] = ZZ_TRANS;
460 | val zzRowMapL:Array[Int] = ZZ_ROWMAP;
461 | val zzAttrL:Array[Int] = ZZ_ATTRIBUTE;
462 |
463 | while (true) {
464 | zzMarkedPosL = zzMarkedPos;
465 |
466 | var zzR:Boolean = false;
467 | zzCurrentPosL = zzStartRead
468 | while (zzCurrentPosL < zzMarkedPosL) {
469 | (zzBufferL(zzCurrentPosL)) match {
470 | case '\u000B'
471 | |'\u000C'
472 | |'\u0085'
473 | |'\u2028'
474 | |'\u2029' => {
475 | yyline+=1;
476 | zzR = false;
477 | }
478 | case '\r' => {
479 | yyline+=1;
480 | zzR = true;
481 | }
482 | case '\n' => {
483 | if (zzR)
484 | zzR = false;
485 | else {
486 | yyline+=1;
487 | }
488 | }
489 | case _ => {
490 | zzR = false;
491 | }
492 | }
493 | zzCurrentPosL += 1;
494 | }
495 |
496 | if (zzR) {
497 | // peek one character ahead if it is \n (if we have counted one line too much)
498 | var zzPeek:Boolean = false;
499 | if (zzMarkedPosL < zzEndReadL)
500 | zzPeek = zzBufferL(zzMarkedPosL) == '\n';
501 | else if (zzAtEOF)
502 | zzPeek = false;
503 | else {
504 | val eof:Boolean = zzRefill();
505 | zzEndReadL = zzEndRead;
506 | zzMarkedPosL = zzMarkedPos;
507 | zzBufferL = zzBuffer;
508 | if (eof)
509 | zzPeek = false;
510 | else
511 | zzPeek = zzBufferL(zzMarkedPosL) == '\n';
512 | }
513 | if (zzPeek) yyline-= 1;
514 | }
515 | zzAction = -1;
516 |
517 | { val p : Int = zzMarkedPosL;
518 | zzCurrentPosL = p; zzCurrentPos = p; zzStartRead = p;
519 | }
520 |
521 | zzState = ZZ_LEXSTATE(zzLexicalState);
522 |
523 | // set up zzAction for empty match case:
524 | var zzAttributes:Int = zzAttrL(zzState);
525 | if ( (zzAttributes & 1) == 1 ) {
526 | zzAction = zzState;
527 | }
528 |
529 |
530 | /* zzForAction: */ try {
531 | while (true) {
532 |
533 | if (zzCurrentPosL < zzEndReadL) {
534 | zzInput = zzBufferL(zzCurrentPosL);
535 | zzCurrentPosL += 1;
536 | } else if (zzAtEOF) {
537 | zzInput = YYEOF;
538 | throw ZZbreak("zzForAction");
539 | }
540 | else {
541 | // store back cached positions
542 | zzCurrentPos = zzCurrentPosL;
543 | zzMarkedPos = zzMarkedPosL;
544 | val eof:Boolean = zzRefill();
545 | // get translated positions and possibly new buffer
546 | zzCurrentPosL = zzCurrentPos;
547 | zzMarkedPosL = zzMarkedPos;
548 | zzBufferL = zzBuffer;
549 | zzEndReadL = zzEndRead;
550 | if (eof) {
551 | zzInput = YYEOF;
552 | throw ZZbreak("zzForAction");
553 | }
554 | else {
555 | zzInput = zzBufferL(zzCurrentPosL);
556 | zzCurrentPosL += 1;
557 | }
558 | }
559 | val zzNext:Int = zzTransL(zzRowMapL(zzState) + zzCMapL(zzInput));
560 | if (zzNext == -1) throw ZZbreak("zzForAction");
561 | zzState = zzNext;
562 |
563 | zzAttributes = zzAttrL(zzState);
564 | if ( (zzAttributes & 1) == 1 ) {
565 | zzAction = zzState;
566 | zzMarkedPosL = zzCurrentPosL;
567 | if ( (zzAttributes & 8) == 8 ) throw ZZbreak("zzForAction");
568 | }
569 |
570 | }
571 | } catch { case ZZbreak("zzForAction") => () }
572 |
573 | // store back cached position
574 | zzMarkedPos = zzMarkedPosL;
575 |
576 | (if ( zzAction < 0 ) zzAction; else ZZ_ACTION(zzAction)) match {
577 | case 3 => {
578 | {
579 | }
580 | }
581 | case 6 => {}
582 | case 1 => {
583 | { println("Ignored characters: " + yytext);
584 | }
585 | }
586 | case 7 => {}
587 | case 5 => {
588 | { return CalcTokens.NUM(Integer.parseInt(yytext));
589 | }
590 | }
591 | case 8 => {}
592 | case 2 => {
593 | { return CalcTokens.YYCHAR('\n');
594 | }
595 | }
596 | case 9 => {}
597 | case 4 => {
598 | { return CalcTokens.YYCHAR(yytext.charAt(0));
599 | }
600 | }
601 | case 10 => {}
602 | case _ =>
603 | if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
604 | zzAtEOF = true;
605 | {
606 | return CalcTokens.YYEOF();
607 | }
608 | } else {
609 | zzScanError(ZZ_NO_MATCH);
610 | }
611 | }
612 | }
613 | throw new RuntimeException("NOT REACHED");
614 | }
615 |
616 |
617 | }
618 |
--------------------------------------------------------------------------------
/examples/Java.y:
--------------------------------------------------------------------------------
1 | %token Identifier
2 |
3 | %token IntegerLiteral
4 | %token FloatingPointLiteral
5 | %token BooleanLiteral
6 | %token CharacterLiteral
7 | %token StringLiteral
8 | %token NullLiteral
9 |
10 | %token BOOLEAN
11 | %token BYTE SHORT INT LONG CHAR
12 | %token FLOAT DOUBLE
13 |
14 | %token PACKAGE IMPORT CLASS INTERFACE
15 | %token PUBLIC PROTECTED PRIVATE
16 | %token STATIC
17 | %token ABSTRACT FINAL NATIVE SYNCHRONIZED TRANSIENT VOLATILE
18 | %token EXTENDS IMPLEMENTS
19 | %token VOID
20 | %token THROWS
21 |
22 | %token THIS SUPER
23 | %token IF ELSE SWITCH CASE DEFAULT WHILE DO FOR
24 | %token BREAK CONTINUE RETURN THROW
25 | %token TRY CATCH FINALLY
26 | %token NEW NULL INSTANCEOF
27 |
28 | %token PLUSPLUS MINUSMINUS
29 | %token LTLT GTGT GTGTGT LTEQ GTEQ EQEQ BANGEQ
30 | %token ANDAND OROR
31 | %token TIMESEQ DIVEQ MODEQ PLUSEQ MINUSEQ
32 | %token LTLTEQ GTGTEQ GTGTGTEQ ANDEQ XOREQ OREQ
33 | %%
34 |
35 | /* 19.2 Productions from S2.3: The Syntactic Grammar */
36 |
37 | Goal:
38 |
39 | CompilationUnit
40 | ;
41 |
42 | /* 19.3 Productions from S3: Lexical Structure */
43 |
44 | Literal:
45 |
46 | IntegerLiteral|
47 |
48 | FloatingPointLiteral|
49 |
50 | BooleanLiteral|
51 |
52 | CharacterLiteral|
53 |
54 | StringLiteral|
55 |
56 | NullLiteral;
57 |
58 | /* 19.4 Productions from S4: Types, Values, and Variables */
59 |
60 | Type:
61 |
62 | PrimitiveType|
63 |
64 | ReferenceType;
65 |
66 | PrimitiveType:
67 |
68 | NumericType|
69 |
70 | BOOLEAN;
71 |
72 | NumericType:
73 |
74 | IntegralType|
75 |
76 | FloatingPointType ;
77 |
78 | IntegralType:
79 |
80 | BYTE | SHORT | INT | LONG | CHAR;
81 |
82 | FloatingPointType:
83 |
84 | FLOAT | DOUBLE;
85 |
86 | ReferenceType:
87 |
88 | ClassOrInterfaceType|
89 |
90 | ArrayType;
91 |
92 | ClassOrInterfaceType:
93 |
94 | Name;
95 |
96 | ClassType:
97 |
98 | ClassOrInterfaceType;
99 |
100 | InterfaceType:
101 |
102 | ClassOrInterfaceType;
103 |
104 | ArrayType:
105 |
106 | PrimitiveType '[' ']'|
107 |
108 | Name '[' ']'|
109 |
110 | ArrayType '[' ']';
111 |
112 | /* 19.5 Productions from S6: Names */
113 |
114 | Name:
115 |
116 | SimpleName|
117 |
118 | QualifiedName;
119 |
120 | SimpleName:
121 |
122 | Identifier;
123 |
124 | QualifiedName:
125 |
126 | Name '.' Identifier;
127 |
128 | /* 19.6 Productions from S7: Packages */
129 |
130 | CompilationUnit:
131 |
132 | PackageDeclaration ImportDeclarations TypeDeclarations|
133 | PackageDeclaration ImportDeclarations|
134 | PackageDeclaration TypeDeclarations|
135 | PackageDeclaration|
136 | ImportDeclarations TypeDeclarations|
137 | ImportDeclarations|
138 | TypeDeclarations|
139 | ;
140 |
141 | ImportDeclarations:
142 |
143 | ImportDeclaration|
144 |
145 | ImportDeclarations ImportDeclaration;
146 |
147 | TypeDeclarations:
148 |
149 | TypeDeclaration|
150 |
151 | TypeDeclarations TypeDeclaration;
152 |
153 | PackageDeclaration:
154 |
155 | PACKAGE Name ';' ;
156 |
157 | ImportDeclaration:
158 |
159 | SingleTypeImportDeclaration|
160 |
161 | TypeImportOnDemandDeclaration;
162 |
163 | SingleTypeImportDeclaration:
164 |
165 | IMPORT Name ';';
166 |
167 | TypeImportOnDemandDeclaration:
168 |
169 | IMPORT Name '.' '*' ';';
170 |
171 | TypeDeclaration:
172 |
173 | ClassDeclaration|
174 |
175 | InterfaceDeclaration|
176 |
177 | ';';
178 |
179 | /* 19.7 Productions Used Only in the LALR(1) Grammar */
180 |
181 | Modifiers:
182 |
183 | Modifier|
184 |
185 | Modifiers Modifier;
186 |
187 | Modifier:
188 |
189 | PUBLIC| PROTECTED| PRIVATE|
190 |
191 | STATIC|
192 |
193 | ABSTRACT| FINAL| NATIVE| SYNCHRONIZED| TRANSIENT| VOLATILE;
194 |
195 | /* 19.8 Productions from S8: Classes */
196 |
197 | /* 19.8.1 Productions from S8.1: Class Declaration */
198 |
199 | ClassDeclaration:
200 |
201 | Modifiers CLASS Identifier Super Interfaces ClassBody|
202 | Modifiers CLASS Identifier Super ClassBody|
203 | Modifiers CLASS Identifier Interfaces ClassBody|
204 | Modifiers CLASS Identifier ClassBody|
205 | CLASS Identifier Super Interfaces ClassBody|
206 | CLASS Identifier Super ClassBody|
207 | CLASS Identifier Interfaces ClassBody|
208 | CLASS Identifier ClassBody;
209 |
210 | Super:
211 |
212 | EXTENDS ClassType;
213 |
214 | Interfaces:
215 |
216 | IMPLEMENTS InterfaceTypeList;
217 |
218 | InterfaceTypeList:
219 |
220 | InterfaceType|
221 |
222 | InterfaceTypeList ',' InterfaceType;
223 |
224 | ClassBody:
225 |
226 | '{' ClassBodyDeclarations '}'|
227 |
228 | '{' '}';
229 |
230 | ClassBodyDeclarations:
231 |
232 | ClassBodyDeclaration|
233 |
234 | ClassBodyDeclarations ClassBodyDeclaration;
235 |
236 | ClassBodyDeclaration:
237 |
238 | ClassMemberDeclaration|
239 |
240 | StaticInitializer|
241 |
242 | ConstructorDeclaration;
243 |
244 | ClassMemberDeclaration:
245 |
246 | FieldDeclaration|
247 |
248 | MethodDeclaration;
249 |
250 | /* 19.8.2 Productions from S8.3: Field Declarations */
251 |
252 | FieldDeclaration:
253 |
254 | Modifiers Type VariableDeclarators ';'|
255 |
256 | Type VariableDeclarators ';';
257 |
258 | VariableDeclarators:
259 |
260 | VariableDeclarator|
261 |
262 | VariableDeclarators ',' VariableDeclarator;
263 |
264 | VariableDeclarator:
265 |
266 | VariableDeclaratorId|
267 |
268 | VariableDeclaratorId '=' VariableInitializer;
269 |
270 | VariableDeclaratorId:
271 |
272 | Identifier|
273 |
274 | VariableDeclaratorId '[' ']';
275 |
276 | VariableInitializer:
277 |
278 | Expression|
279 |
280 | ArrayInitializer;
281 |
282 | /* 19.8.3 Productions from S8.4: Method Declarations */
283 |
284 | MethodDeclaration:
285 |
286 | MethodHeader MethodBody;
287 |
288 | MethodHeader:
289 |
290 | Modifiers Type MethodDeclarator Throws |
291 | Modifiers Type MethodDeclarator |
292 | Type MethodDeclarator Throws |
293 | Type MethodDeclarator |
294 |
295 | Modifiers VOID MethodDeclarator Throws|
296 | Modifiers VOID MethodDeclarator |
297 | VOID MethodDeclarator Throws|
298 | VOID MethodDeclarator ;
299 |
300 | MethodDeclarator:
301 |
302 | Identifier '(' FormalParameterList ')' |
303 | Identifier '(' ')' |
304 |
305 | MethodDeclarator '[' ']';
306 |
307 | FormalParameterList:
308 |
309 | FormalParameter|
310 |
311 | FormalParameterList ',' FormalParameter;
312 |
313 | FormalParameter:
314 |
315 | Type VariableDeclaratorId;
316 |
317 | Throws:
318 |
319 | THROWS ClassTypeList;
320 |
321 | ClassTypeList:
322 |
323 | ClassType|
324 |
325 | ClassTypeList ',' ClassType;
326 |
327 | MethodBody:
328 |
329 | Block|
330 |
331 | ';';
332 |
333 | /* 19.8.4 Productions from S8.5: Static Initializers */
334 |
335 | StaticInitializer:
336 |
337 | STATIC Block;
338 |
339 | /* 19.8.5 Productions from S8.6: Constructor Declarations */
340 |
341 | ConstructorDeclaration:
342 |
343 | Modifiers ConstructorDeclarator Throws ConstructorBody|
344 | Modifiers ConstructorDeclarator ConstructorBody|
345 | ConstructorDeclarator Throws ConstructorBody|
346 | ConstructorDeclarator ConstructorBody;
347 |
348 | ConstructorDeclarator:
349 |
350 | SimpleName '(' FormalParameterList ')'|
351 | SimpleName '(' ')';
352 |
353 | ConstructorBody:
354 |
355 | '{' ExplicitConstructorInvocation BlockStatements '}'|
356 | '{' ExplicitConstructorInvocation '}'|
357 | '{' BlockStatements '}'|
358 | '{' '}';
359 |
360 | ExplicitConstructorInvocation:
361 |
362 | THIS '(' ArgumentList ')' ';'|
363 | THIS '(' ')' ';'|
364 |
365 | SUPER '(' ArgumentList ')' ';'|
366 | SUPER '(' ')' ';';
367 |
368 |
369 | /* 19.9 Productions from S9: Interfaces */
370 |
371 | /* 19.9.1 Productions from S9.1: Interface Declarations */
372 |
373 | InterfaceDeclaration:
374 |
375 | Modifiers INTERFACE Identifier ExtendsInterfaces InterfaceBody|
376 | Modifiers INTERFACE Identifier InterfaceBody|
377 | INTERFACE Identifier ExtendsInterfaces InterfaceBody|
378 | INTERFACE Identifier InterfaceBody;
379 |
380 | ExtendsInterfaces:
381 |
382 | EXTENDS InterfaceType|
383 |
384 | ExtendsInterfaces ',' InterfaceType;
385 |
386 | InterfaceBody:
387 |
388 | '{' InterfaceMemberDeclarations '}'|
389 | '{' '}';
390 |
391 | InterfaceMemberDeclarations:
392 |
393 | InterfaceMemberDeclaration|
394 |
395 | InterfaceMemberDeclarations InterfaceMemberDeclaration;
396 |
397 | InterfaceMemberDeclaration:
398 |
399 | ConstantDeclaration|
400 |
401 | AbstractMethodDeclaration;
402 |
403 | ConstantDeclaration:
404 |
405 | FieldDeclaration;
406 |
407 | AbstractMethodDeclaration:
408 |
409 | MethodHeader ';';
410 |
411 | /* 19.10 Productions from S10: Arrays */
412 |
413 | ArrayInitializer:
414 |
415 | '{' VariableInitializers ',' '}'|
416 |
417 | '{' VariableInitializers '}'|
418 |
419 | '{' ',' '}'|
420 |
421 | '{' '}';
422 |
423 | VariableInitializers:
424 |
425 | VariableInitializer|
426 |
427 | VariableInitializers ',' VariableInitializer;
428 |
429 | /* 19.11 Productions from S14: Blocks and Statements */
430 |
431 | Block:
432 |
433 | '{' BlockStatements '}'|
434 | '{' '}';
435 |
436 | BlockStatements:
437 |
438 | BlockStatement|
439 |
440 | BlockStatements BlockStatement;
441 |
442 | BlockStatement:
443 |
444 | LocalVariableDeclarationStatement|
445 |
446 | Statement;
447 |
448 | LocalVariableDeclarationStatement:
449 |
450 | LocalVariableDeclaration ';';
451 |
452 | LocalVariableDeclaration:
453 |
454 | Type VariableDeclarators;
455 |
456 | Statement:
457 |
458 | StatementWithoutTrailingSubstatement|
459 |
460 | LabeledStatement|
461 |
462 | IfThenStatement|
463 |
464 | IfThenElseStatement|
465 |
466 | WhileStatement|
467 |
468 | ForStatement;
469 |
470 | StatementNoShortIf:
471 |
472 | StatementWithoutTrailingSubstatement|
473 |
474 | LabeledStatementNoShortIf|
475 |
476 | IfThenElseStatementNoShortIf|
477 |
478 | WhileStatementNoShortIf|
479 |
480 | ForStatementNoShortIf;
481 |
482 | StatementWithoutTrailingSubstatement:
483 |
484 | Block|
485 |
486 | EmptyStatement|
487 |
488 | ExpressionStatement|
489 |
490 | SwitchStatement|
491 |
492 | DoStatement|
493 |
494 | BreakStatement|
495 |
496 | ContinueStatement|
497 |
498 | ReturnStatement|
499 |
500 | SynchronizedStatement|
501 |
502 | ThrowStatement|
503 |
504 | TryStatement;
505 |
506 | EmptyStatement:
507 |
508 | ';';
509 |
510 | LabeledStatement:
511 |
512 | Identifier ':' Statement;
513 |
514 | LabeledStatementNoShortIf:
515 |
516 | Identifier ':' StatementNoShortIf;
517 |
518 | ExpressionStatement:
519 |
520 | StatementExpression ';';
521 |
522 | StatementExpression:
523 |
524 | Assignment|
525 |
526 | PreIncrementExpression|
527 |
528 | PreDecrementExpression|
529 |
530 | PostIncrementExpression|
531 |
532 | PostDecrementExpression|
533 |
534 | MethodInvocation|
535 |
536 | ClassInstanceCreationExpression;
537 |
538 | IfThenStatement:
539 |
540 | IF '(' Expression ')' Statement;
541 |
542 | IfThenElseStatement:
543 |
544 | IF '(' Expression ')' StatementNoShortIf ELSE Statement;
545 |
546 | IfThenElseStatementNoShortIf:
547 |
548 | IF '(' Expression ')' StatementNoShortIf ELSE StatementNoShortIf;
549 |
550 | SwitchStatement:
551 |
552 | SWITCH '(' Expression ')' SwitchBlock;
553 |
554 | SwitchBlock:
555 |
556 | '{' SwitchBlockStatementGroups SwitchLabels '}'|
557 | '{' SwitchLabels '}'|
558 | '{' SwitchBlockStatementGroups '}'|
559 | '{' '}';
560 |
561 |
562 | SwitchBlockStatementGroups:
563 |
564 | SwitchBlockStatementGroup|
565 |
566 | SwitchBlockStatementGroups SwitchBlockStatementGroup;
567 |
568 | SwitchBlockStatementGroup:
569 |
570 | SwitchLabels BlockStatements;
571 |
572 | SwitchLabels:
573 |
574 | SwitchLabel|
575 |
576 | SwitchLabels SwitchLabel;
577 |
578 | SwitchLabel:
579 |
580 | CASE ConstantExpression ':'|
581 |
582 | DEFAULT ':';
583 |
584 | WhileStatement:
585 |
586 | WHILE '(' Expression ')' Statement;
587 |
588 | WhileStatementNoShortIf:
589 |
590 | WHILE '(' Expression ')' StatementNoShortIf;
591 |
592 | DoStatement:
593 |
594 | DO Statement WHILE '(' Expression ')' ';';
595 |
596 | ForStatement:
597 |
598 | FOR '(' ForInit ';' Expression ';' ForUpdate ')'
599 | Statement|
600 | FOR '(' ForInit ';' Expression ';' ')'
601 | Statement|
602 | FOR '(' ForInit ';' ';' ForUpdate ')'
603 | Statement|
604 | FOR '(' ForInit ';' ';' ')'
605 | Statement|
606 | FOR '(' ';' Expression ';' ForUpdate ')'
607 | Statement|
608 | FOR '(' ';' Expression ';' ')'
609 | Statement|
610 | FOR '(' ';' ';' ForUpdate ')'
611 | Statement|
612 | FOR '(' ';' ';' ')'
613 | Statement;
614 |
615 | ForStatementNoShortIf:
616 |
617 | FOR '(' ForInit ';' Expression ';' ForUpdate ')'
618 | StatementNoShortIf|
619 | FOR '(' ForInit ';' Expression ';' ')'
620 | StatementNoShortIf|
621 | FOR '(' ForInit ';' ';' ForUpdate ')'
622 | StatementNoShortIf|
623 | FOR '(' ForInit ';' ';' ')'
624 | StatementNoShortIf|
625 | FOR '(' ';' Expression ';' ForUpdate ')'
626 | StatementNoShortIf|
627 | FOR '(' ';' Expression ';' ')'
628 | StatementNoShortIf|
629 | FOR '(' ';' ';' ForUpdate ')'
630 | StatementNoShortIf|
631 | FOR '(' ';' ';' ')'
632 | StatementNoShortIf;
633 |
634 | ForInit:
635 |
636 | StatementExpressionList|
637 |
638 | LocalVariableDeclaration;
639 |
640 | ForUpdate:
641 |
642 | StatementExpressionList;
643 |
644 | StatementExpressionList:
645 |
646 | StatementExpression|
647 |
648 | StatementExpressionList ',' StatementExpression;
649 |
650 | BreakStatement:
651 |
652 | BREAK Identifier ';'|
653 | BREAK ';';
654 |
655 | ContinueStatement:
656 |
657 | CONTINUE Identifier ';'|
658 | CONTINUE ';';
659 |
660 | ReturnStatement:
661 |
662 | RETURN Expression ';'|
663 | RETURN ';';
664 |
665 | ThrowStatement:
666 |
667 | THROW Expression ';';
668 |
669 | SynchronizedStatement:
670 |
671 | SYNCHRONIZED '(' Expression ')' Block;
672 |
673 | TryStatement:
674 |
675 | TRY Block Catches|
676 |
677 | TRY Block Catches Finally|
678 | TRY Block Finally;
679 |
680 | Catches:
681 |
682 | CatchClause|
683 |
684 | Catches CatchClause;
685 |
686 | CatchClause:
687 |
688 | CATCH '(' FormalParameter ')' Block;
689 |
690 | Finally:
691 |
692 | FINALLY Block;
693 |
694 | /* 19.12 Productions from S15: Expressions */
695 |
696 | Primary:
697 |
698 | PrimaryNoNewArray|
699 |
700 | ArrayCreationExpression;
701 |
702 | PrimaryNoNewArray:
703 |
704 | Literal|
705 |
706 | THIS|
707 |
708 | '(' Expression ')'|
709 |
710 | ClassInstanceCreationExpression|
711 |
712 | FieldAccess|
713 |
714 | MethodInvocation|
715 |
716 | ArrayAccess;
717 |
718 | ClassInstanceCreationExpression:
719 |
720 | NEW ClassType '(' ArgumentList ')'|
721 | NEW ClassType '(' ')';
722 |
723 | ArgumentList:
724 |
725 | Expression|
726 |
727 | ArgumentList ',' Expression;
728 |
729 | ArrayCreationExpression:
730 |
731 | NEW PrimitiveType DimExprs Dims|
732 | NEW PrimitiveType DimExprs |
733 |
734 | NEW ClassOrInterfaceType DimExprs Dims|
735 | NEW ClassOrInterfaceType DimExprs ;
736 |
737 | DimExprs:
738 |
739 | DimExpr|
740 |
741 | DimExprs DimExpr;
742 |
743 | DimExpr:
744 |
745 | '[' Expression ']';
746 |
747 | Dims:
748 |
749 | '[' ']'|
750 |
751 | Dims '[' ']';
752 |
753 | FieldAccess:
754 |
755 | Primary '.' Identifier|
756 |
757 | SUPER '.' Identifier;
758 |
759 | MethodInvocation:
760 |
761 | Name '(' ArgumentList ')'|
762 | Name '(' ')'|
763 |
764 | Primary '.' Identifier '(' ArgumentList ')'|
765 | Primary '.' Identifier '(' ')'|
766 |
767 | SUPER '.' Identifier '(' ArgumentList ')'|
768 | SUPER '.' Identifier '(' ')';
769 |
770 | ArrayAccess:
771 |
772 | Name '[' Expression ']'|
773 |
774 | PrimaryNoNewArray '[' Expression ']';
775 |
776 | PostfixExpression:
777 |
778 | Primary|
779 |
780 | Name|
781 |
782 | PostIncrementExpression|
783 |
784 | PostDecrementExpression;
785 |
786 | PostIncrementExpression:
787 |
788 | PostfixExpression PLUSPLUS;
789 |
790 | PostDecrementExpression:
791 |
792 | PostfixExpression MINUSMINUS;
793 |
794 | UnaryExpression:
795 |
796 | PreIncrementExpression|
797 |
798 | PreDecrementExpression|
799 |
800 | '+' UnaryExpression|
801 |
802 | '-' UnaryExpression|
803 |
804 | UnaryExpressionNotPlusMinus;
805 |
806 | PreIncrementExpression:
807 |
808 | PLUSPLUS UnaryExpression;
809 |
810 | PreDecrementExpression:
811 |
812 | MINUSMINUS UnaryExpression;
813 |
814 | UnaryExpressionNotPlusMinus:
815 |
816 | PostfixExpression|
817 |
818 | '~' UnaryExpression|
819 |
820 | '!' UnaryExpression|
821 |
822 | CastExpression;
823 |
824 | CastExpression:
825 |
826 | '(' PrimitiveType Dims ')' UnaryExpression|
827 | '(' PrimitiveType ')' UnaryExpression|
828 |
829 | '(' Expression ')' UnaryExpressionNotPlusMinus|
830 |
831 | '(' Name Dims ')' UnaryExpressionNotPlusMinus;
832 |
833 | MultiplicativeExpression:
834 |
835 | UnaryExpression|
836 |
837 | MultiplicativeExpression '*' UnaryExpression|
838 |
839 | MultiplicativeExpression '/' UnaryExpression|
840 |
841 | MultiplicativeExpression '%' UnaryExpression;
842 |
843 | AdditiveExpression:
844 |
845 | MultiplicativeExpression|
846 |
847 | AdditiveExpression '+' MultiplicativeExpression|
848 |
849 | AdditiveExpression '-' MultiplicativeExpression;
850 |
851 | ShiftExpression:
852 |
853 | AdditiveExpression|
854 |
855 | ShiftExpression LTLT AdditiveExpression|
856 |
857 | ShiftExpression GTGT AdditiveExpression|
858 |
859 | ShiftExpression GTGTGT AdditiveExpression;
860 |
861 | RelationalExpression:
862 |
863 | ShiftExpression|
864 |
865 | RelationalExpression '<' ShiftExpression|
866 |
867 | RelationalExpression '>' ShiftExpression|
868 |
869 | RelationalExpression LTEQ ShiftExpression|
870 |
871 | RelationalExpression GTEQ ShiftExpression|
872 |
873 | RelationalExpression INSTANCEOF ReferenceType;
874 |
875 | EqualityExpression:
876 |
877 | RelationalExpression|
878 |
879 | EqualityExpression EQEQ RelationalExpression|
880 |
881 | EqualityExpression BANGEQ RelationalExpression;
882 |
883 | AndExpression:
884 |
885 | EqualityExpression|
886 |
887 | AndExpression '&' EqualityExpression;
888 |
889 | ExclusiveOrExpression:
890 |
891 | AndExpression|
892 |
893 | ExclusiveOrExpression '^' AndExpression;
894 |
895 | InclusiveOrExpression:
896 |
897 | ExclusiveOrExpression|
898 |
899 | InclusiveOrExpression '|' ExclusiveOrExpression;
900 |
901 | ConditionalAndExpression:
902 |
903 | InclusiveOrExpression|
904 |
905 | ConditionalAndExpression ANDAND InclusiveOrExpression;
906 |
907 | ConditionalOrExpression:
908 |
909 | ConditionalAndExpression|
910 |
911 | ConditionalOrExpression OROR ConditionalAndExpression;
912 |
913 | ConditionalExpression:
914 |
915 | ConditionalOrExpression|
916 |
917 | ConditionalOrExpression '?' Expression ':' ConditionalExpression;
918 |
919 | AssignmentExpression:
920 |
921 | ConditionalExpression|
922 |
923 | Assignment;
924 |
925 | Assignment:
926 |
927 | LeftHandSide AssignmentOperator AssignmentExpression;
928 |
929 | LeftHandSide:
930 |
931 | Name|
932 |
933 | FieldAccess|
934 |
935 | ArrayAccess;
936 |
937 | AssignmentOperator:
938 |
939 | '='| TIMESEQ | DIVEQ | MODEQ | PLUSEQ | MINUSEQ |
940 | LTLTEQ | GTGTEQ | GTGTGTEQ | ANDEQ | XOREQ | OREQ ;
941 |
942 | Expression:
943 |
944 | AssignmentExpression;
945 |
946 | ConstantExpression:
947 |
948 | Expression;
949 |
950 | %%
951 |
952 | def yyerror(s:String) = println(s);
953 |
--------------------------------------------------------------------------------
/examples/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: all
2 |
3 | all: Calc.class JavaParser.scala
4 |
5 | Calc.class : Calc.scala CalcScanner.scala CalcParser.scala CalcTokens.scala CalcParserbase.scala
6 | scalac Calc.scala CalcScanner.scala CalcParser.scala CalcTokens.scala CalcParserBase.scala
7 |
8 | CalcScanner.scala : Calc.lex
9 | jflex --scala Calc.lex
10 |
11 | CalcParser.scala CalcTokens.scala : Calc.y
12 | ../cmd/scala-bison Calc
13 |
14 | JavaParser.scala : Java.y
15 | ../cmd/scala-bison Java
16 |
17 | clean :
18 | rm -f *.class *Parser.scala *Tokens.scala *~ *.output *.lcoutput *.tab.c
19 |
--------------------------------------------------------------------------------
/examples/README:
--------------------------------------------------------------------------------
1 | Example Uses of ScalaBison
2 |
3 | This directory has two examples using ScalaBison.
4 | The main source includes also a parser for Bison grammars.
5 |
6 | The "Calc" grammar takes an example from the bison manual together with
7 | a scanner implemented using the "--scala" option of JFlex.
8 | The "Calc" object can be used to execute the parser and scanner on standard input.
9 |
10 | The Java grammar is directly from the Java Language Specification.
11 | It is not set up for execution although it will compile.
12 | (There is no scanner).
13 |
14 | The Makefile in this directory allows one to build the various parsers.
15 | It also (because it uses the script ../cmd/scala-bison) creates .lcoutput files
16 | that show the "left corner" parsing tables used.
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/.gitignore:
--------------------------------------------------------------------------------
1 | BisonParser.scala
2 | BisonTokens.scala
3 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/AcceptAction.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class AcceptAction() extends Action {
20 | override def toString() = "accept";
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/AcceptNTAction.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class AcceptNTAction(nt : Nonterminal) extends Action {
20 | override def toString() = "accept " + nt.name;
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Action.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | trait Action {}
20 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/AnnounceAction.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class AnnounceAction(val rule : Rule) extends Action {
20 | override def toString = "announce rule " + rule
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/ArtificialNonterminal.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class ArtificialNonterminal(n : String, ty : String) extends Nonterminal(n,ty) {
20 | }
21 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Bison.y:
--------------------------------------------------------------------------------
1 | %{
2 | package edu.uwm.cs.scalabison;
3 |
4 | import scala.io.Source;
5 |
6 | %}
7 |
8 | %token block piece
19 | %type <(Symbol,Code)> action
20 | %type rev_pieces
21 | %type precedence
22 | %type grammar
23 |
24 | %%
25 |
26 | grammar : declarations BEGIN rules END
27 | { result.addExtra($4); $$ = result; }
28 | ;
29 |
30 | declarations : /* EMPTY */
31 | | declarations { symbol_type = ""; prec = null; } declaration
32 | ;
33 |
34 | declaration
35 | : PROLOGUE_BEGIN rev_pieces PROLOGUE_END
36 | { result.addPrologue($2 .reverse); }
37 | | TOKEN token_names
38 | | precedence { prec = $1; } token_names
39 | | TYPE TYPELIT { symbol_type = $2; } nonterminal_names
40 | | START ID { result.setStart(result.getNT($2)); }
41 | ;
42 |
43 | token_names
44 | : token_names token_name
45 | | token_name
46 | ;
47 |
48 | token_name
49 | : ID { val t : Terminal = result.add(new Terminal($1,symbol_type));
50 | if (prec != null) t.setPrecedence(prec); }
51 | | CHARLIT
52 | { val t : Terminal = result.add(new CharLitTerminal($1));
53 | if (prec != null) t.setPrecedence(prec); }
54 | | TYPELIT
55 | { symbol_type = $1; }
56 | ;
57 |
58 | nonterminal_names
59 | : nonterminal_names nonterminal_name
60 | | nonterminal_name
61 | ;
62 |
63 | nonterminal_name
64 | : ID { result.add(new Nonterminal($1,symbol_type)); }
65 | ;
66 |
67 | precedence
68 | : LEFT { precLevel += 1; $$ = new LeftPrecedence(precLevel); }
69 | | RIGHT { precLevel += 1; $$ = new RightPrecedence(precLevel); }
70 | | NONASSOC { precLevel += 1; $$ = new NonAssocPrecedence(precLevel); }
71 | ;
72 |
73 | rules : /* EMPTY */
74 | | rules rule
75 | ;
76 |
77 | rule : ID ':' rhs action
78 | { currNT = result.getNT($1);
79 | result.addRule(new Rule(genRuleNum(),currNT,$3,getPrec($3,$4._1),$4._2)); }
80 | morerules ';'
81 | ;
82 |
83 | morerules
84 | : /* EMPTY */
85 | | morerules '|' rhs action
86 | { result.addRule(new Rule(genRuleNum(),currNT,$3,getPrec($3,$4._1),$4._2)); }
87 | ;
88 |
89 | rhs : /* EMPTY */ { $$ = Nil; }
90 | | rhs symbol { $$ = $1 ++ ($2 :: Nil); }
91 | | rhs anon symbol { $$ = $1 ++ ($2 :: $3 :: Nil); }
92 | ;
93 |
94 | anon : block
95 | { uniq += 1;
96 | val nt : Nonterminal = result.add(new ArtificialNonterminal("@" + uniq,"unit"));
97 | result.addRule(new Rule(genRuleNum(),nt,Nil,null,$1));
98 | $$ = nt; }
99 | ;
100 |
101 | symbol : ID { $$ = result.get($1); }
102 | | CHARLIT
103 | { $$ = result.getCLT($1); }
104 | ;
105 |
106 | action : block { $$ = (null,$1); }
107 | | PREC symbol block
108 | { $$ = ($2,$3); }
109 | | PREC symbol
110 | { $$ = ($2,NoCode()); }
111 | | /* EMPTY */
112 | { $$ = (null,NoCode()); }
113 | ;
114 |
115 | block : '{' rev_pieces '}'
116 | { $$ = BlockCode($2.reverse); }
117 | ;
118 |
119 | rev_pieces
120 | : /* EMPTY */
121 | { $$ = Nil; }
122 | | rev_pieces piece
123 | { $$ = $2 :: $1; }
124 | ;
125 |
126 | piece : block { $$ = $1; }
127 | | CODE { $$ = LiteralCode($1); }
128 | | VAR { $$ = VariableCode($1); }
129 | ;
130 | %%
131 |
132 | def yyerror(s : String) = {
133 | errorsOccured = true;
134 | println(filename + ":" + scanner.getLineNumber + ":" + s);
135 | }
136 |
137 | var scanner : BisonScanner = null;
138 | var filename : String = "";
139 | var errorsOccured : Boolean = false;
140 | var result : BisonGrammar = new BisonGrammar();
141 | var precLevel : Int = 0;
142 | var prec : Precedence = null;
143 | var symbol_type : String = "";
144 | var uniq : Int = 0;
145 | var currNT : Nonterminal = null;
146 | var rulenum : Int = 0;
147 |
148 | def genRuleNum() : Int = {
149 | rulenum += 1;
150 | rulenum
151 | }
152 |
153 | def getPrec(rhs:List[Symbol], sym : Symbol) : Precedence = {
154 | if (sym != null) return sym.precedence;
155 | for (sym <- rhs.reverse) {
156 | if (sym.precedence != null) return sym.precedence;
157 | }
158 | null
159 | }
160 |
161 | def reset(fn : String, sc : BisonScanner) = {
162 | filename = fn;
163 | scanner = sc;
164 | yyreset(sc);
165 | result = new BisonGrammar();
166 | precLevel = 0;
167 | prec = null;
168 | uniq = 0;
169 | currNT = null;
170 | rulenum = 0;
171 | errorsOccured = false;
172 | }
173 |
174 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/BisonGrammar.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.mutable.Map;
20 | import scala.collection.mutable.ArrayBuffer;
21 | import scala.collection.mutable.HashMap;
22 |
23 | import edu.uwm.cs.util.CharUtil;
24 |
25 | class BisonGrammar() extends Grammar {
26 | val special : Nonterminal = add(ArtificialNonterminal("$accept",""));
27 | val error : Nonterminal = add(ErrorNonterminal());
28 |
29 | var prologue : String = "/* Generated by Scala-Bison version "+Version.version+" */\n";
30 | var extra : String = "";
31 |
32 | def addExtra(x : String) = { extra = x; }
33 |
34 | def addPrologue(x : List[Code]) = {
35 | // Can't get this to work:
36 | // prologue = (prologue /: x)(+)
37 | for (c <- x) {
38 | prologue += (c.toString);
39 | }
40 | }
41 |
42 | def setStart(sym : Nonterminal) = {
43 | _start = sym;
44 | rules += new Rule(0,special,start :: end :: Nil,null,NoCode());
45 | }
46 |
47 | def addRule(new_rule : Rule) = {
48 | if (_start == null) setStart(new_rule.lhs);
49 | rules += new_rule;
50 | }
51 |
52 | override def add[T <: Symbol](name : T) : T = super.add(name)
53 |
54 | def getNT(name : String) : Nonterminal = {
55 | get(name) match {
56 | case x:Nonterminal => x
57 | case _ => throw new GrammarSpecificationError("Not a nonterminal: " + name);
58 | }
59 | }
60 |
61 | def getCLT(ch : Char) : Terminal = {
62 | val name : String = CharUtil.lit(ch);
63 | find(name) match {
64 | case Some(t:Terminal) => t
65 | case None => add(new CharLitTerminal(ch));
66 | case Some(s:Symbol) => throw new GrammarSpecificationError("Not a terminal: " + name);
67 | }
68 | }
69 |
70 | override def find(name : String) : Option[Symbol] = {
71 | val key = if (name.startsWith("$@")) name.substring(1) else name;
72 | super.find(key);
73 | }
74 |
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/BisonParserBase.scala:
--------------------------------------------------------------------------------
1 | package edu.uwm.cs.scalabison
2 |
3 | class BisonParserBase {
4 |
5 | }
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/BisonScanner.scala:
--------------------------------------------------------------------------------
1 | /* Scanner for Scala-Bison files
2 | * John Boyland
3 | * This file may be used, copied and/or modified for any purpose.
4 | * Eventually it might be nice to have this file generated.
5 | */
6 | package edu.uwm.cs.scalabison;
7 |
8 | import scala.collection.Set;
9 | import scala.io.Source;
10 |
11 | class BisonScanner(input : Iterator[Char])
12 | extends Iterator[BisonTokens.YYToken]
13 | {
14 | private val NOCURRENT : Int = -1;
15 | private var current : Int = NOCURRENT;
16 | private var linenumber : Int = 1;
17 |
18 | def getLineNumber : Int = linenumber;
19 |
20 | private def headInput : Char = {
21 | if (current == NOCURRENT) {
22 | if (!input.hasNext) {
23 | throw new GrammarSpecificationError("unexpected EOF");
24 | }
25 | current = (input.next).toInt
26 | }
27 | current.toChar
28 | }
29 | private def nextInput : Unit = {
30 | if (current == '\n') linenumber += 1;
31 | (current = NOCURRENT);
32 | }
33 | private def pushInput(chx : Char) : Unit = {
34 | var ch : Char = chx
35 | if (ch == '\n') ch = ' ';
36 | if (current == NOCURRENT) {
37 | current = ch;
38 | } else {
39 | throw new GrammarSpecificationError("meta error in pushInput");
40 | }
41 | }
42 | private def restInput : String = {
43 | val sb:StringBuilder = new StringBuilder;
44 | if (current != NOCURRENT) sb += (current.toChar);
45 | current = NOCURRENT;
46 | while (input.hasNext) {
47 | sb += (input.next)
48 | }
49 | sb.toString
50 | }
51 |
52 | val whitespace : Set[Char] =
53 | Set.empty + ' ' + '\t' + '\r' + '\n' + '\f' + '\b';
54 |
55 | private def skipWhitespace : Unit = {
56 | if (whitespace contains headInput) {
57 | nextInput
58 | skipWhitespace
59 | }
60 | }
61 |
62 | private def readComment() : String = {
63 | val sb : StringBuilder = new StringBuilder("/");
64 | if (headInput == '/') {
65 | do {
66 | sb += headInput
67 | nextInput
68 | } while (headInput != '\n');
69 | } else if (headInput == '*') {
70 | do {
71 | do {
72 | sb += headInput;
73 | //print("+" + headInput);
74 | nextInput;
75 | } while (headInput != '*');
76 | do {
77 | sb += headInput;
78 | //print("-" + headInput);
79 | nextInput;
80 | } while (headInput == '*');
81 | } while (headInput != '/');
82 | sb += headInput;
83 | nextInput
84 | } else {
85 | throw new GrammarSpecificationError("Meta error in readComment");
86 | }
87 | sb.toString
88 | }
89 |
90 | def isKeyChar(ch : Char) : Boolean = {
91 | ch == '-' || ch == '_' || ch >= 'a' && ch <= 'z' ||
92 | ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9'
93 | }
94 |
95 | object ID {
96 | def unapply(ch : Char) : Boolean = isKeyChar(ch);
97 | }
98 |
99 | def readID() : String = {
100 | val sb : StringBuilder = new StringBuilder();
101 | do {
102 | sb += headInput;
103 | nextInput
104 | } while (isKeyChar(headInput));
105 | sb.toString
106 | }
107 |
108 | def readQuoted(quote : Char) : String = {
109 | val sb : StringBuilder = new StringBuilder();
110 | sb += quote;
111 | nextInput
112 | while (headInput != quote) {
113 | if (headInput == '\\') {
114 | sb += headInput;
115 | nextInput
116 | }
117 | sb += headInput;
118 | nextInput
119 | }
120 | sb += headInput;
121 | nextInput;
122 |
123 | return sb.toString
124 | }
125 |
126 | def readSingleQuoted : String = {
127 | val sb : StringBuilder = new StringBuilder();
128 | sb += '\'';
129 | nextInput
130 | if (headInput == '\\') {
131 | sb += headInput;
132 | nextInput
133 | }
134 | sb += headInput;
135 | nextInput
136 | if (headInput == '\'') {
137 | sb += headInput;
138 | nextInput;
139 | }
140 | return sb.toString
141 | }
142 |
143 | def convert(quoted : String) : String = {
144 | // println("Converting " + quoted);
145 | val sb : StringBuilder = new StringBuilder();
146 | val n : Int = quoted.length() - 1;
147 | var i : Int = 1;
148 | while (i < n) {
149 | val ch : Char = quoted.charAt(i);
150 | sb += {
151 | if (ch == '\\') {
152 | i += 1
153 | quoted.charAt(i) match {
154 | case 'b' => '\b'
155 | case 't' => '\t'
156 | case 'f' => '\f'
157 | case 'n' => '\n'
158 | case 'r' => '\r'
159 | case '0' => '\u0000'
160 | case c => c
161 | }
162 | } else {
163 | ch
164 | }
165 | };
166 | i += 1
167 | }
168 | // println("Result is '" + sb + "'");
169 | sb.toString
170 | }
171 |
172 | abstract class State {
173 | def next : BisonTokens.YYToken;
174 | def hasNext : Boolean;
175 | }
176 |
177 | private var state : State = new InitialState;
178 | private var savedState : State = null;
179 |
180 | /*override*/ def hasNext : Boolean = state != null && state.hasNext;
181 | /*override*/ def next : BisonTokens.YYToken = state.next;
182 |
183 | class InitialState extends State {
184 | override def hasNext : Boolean = {
185 | skipWhitespace
186 | if (headInput == '/') {
187 | nextInput
188 | if (headInput == '/' || headInput == '*') {
189 | readComment
190 | hasNext
191 | } else {
192 | pushInput('/');
193 | true
194 | }
195 | } else true
196 | }
197 |
198 | override def next : BisonTokens.YYToken = {
199 | headInput match {
200 | case '%' => {
201 | nextInput
202 | headInput match {
203 | case '%' => {
204 | nextInput
205 | state = new RuleState;
206 | BisonTokens.BEGIN()
207 | }
208 | case ID() => {
209 | readID match {
210 | case "left" => BisonTokens.LEFT()
211 | case "right" => BisonTokens.RIGHT()
212 | case "nonassoc" => BisonTokens.NONASSOC()
213 | case "token" => BisonTokens.TOKEN()
214 | case "type" => BisonTokens.TYPE()
215 | case "start" => BisonTokens.START()
216 | case "union" => BisonTokens.UNION()
217 | case s:String =>
218 | throw new GrammarSpecificationError("Unknown key %" + s)
219 | }
220 | }
221 | case '{' => {
222 | nextInput
223 | savedState = this
224 | state = new CodeState;
225 | BisonTokens.PROLOGUE_BEGIN()
226 | }
227 | case ch:Char => {
228 | throw new GrammarSpecificationError("Unknown directive %" + ch)
229 | }
230 | }
231 | }
232 |
233 | case ID() => BisonTokens.ID(readID())
234 | case '{' => {
235 | nextInput
236 | savedState = this
237 | state = new CodeState;
238 | BisonTokens.YYCHAR('{')
239 | }
240 | case '<' => {
241 | val sb : StringBuilder = new StringBuilder;
242 | nextInput
243 | while (headInput != '>' && headInput != '\n') {
244 | sb += headInput
245 | nextInput
246 | }
247 | if (headInput != '>') {
248 | throw new GrammarSpecificationError(" BisonTokens.CHARLIT(convert(readQuoted('\'')).charAt(0))
254 | case '"' => BisonTokens.STRINGLIT(convert(readQuoted('"')))
255 | case ch:Char => nextInput; BisonTokens.YYCHAR(ch)
256 | }
257 | }
258 | }
259 |
260 | class CodeState extends State {
261 | var level : Int = 1;
262 | override def hasNext : Boolean = true;
263 | override def next : BisonTokens.YYToken = {
264 | headInput match {
265 | case '{' => {
266 | nextInput
267 | level += 1;
268 | BisonTokens.YYCHAR('{')
269 | }
270 | case '}' => {
271 | nextInput
272 | level -= 1
273 | if (level == 0) state = savedState;
274 | BisonTokens.YYCHAR('}')
275 | }
276 | case '/' => {
277 | nextInput;
278 | if (headInput == '*' || headInput == '/') {
279 | BisonTokens.CODE(readComment())
280 | } else {
281 | BisonTokens.CODE("/")
282 | }
283 | }
284 | case '$' => {
285 | nextInput;
286 | if (headInput == '$') {
287 | nextInput
288 | BisonTokens.VAR(-1)
289 | } else if (headInput >= '0' && headInput <= '9') {
290 | var result : Int = 0
291 | do {
292 | result *= 10;
293 | result += (headInput - '0');
294 | nextInput
295 | } while (headInput >= '0' && headInput <= '9');
296 | BisonTokens.VAR(result)
297 | } else {
298 | throw new GrammarSpecificationError("$ must be followed by int");
299 | }
300 | }
301 | case '%' => {
302 | nextInput
303 | if (headInput == '}') {
304 | nextInput
305 | state = savedState;
306 | BisonTokens.PROLOGUE_END()
307 | } else {
308 | BisonTokens.CODE("%");
309 | }
310 | }
311 | case '\'' => BisonTokens.CODE(readSingleQuoted)
312 | case '"' => BisonTokens.CODE(readQuoted('"'))
313 | case ch:Char => {
314 | var sb : StringBuilder = new StringBuilder
315 | do {
316 | sb += headInput
317 | nextInput
318 | } while (headInput != '$' &&
319 | headInput != '}' &&
320 | headInput != '{' &&
321 | headInput != '%' &&
322 | headInput != '/' &&
323 | headInput != '\'' && headInput != '"')
324 | return BisonTokens.CODE(sb.toString)
325 | }
326 | }
327 | }
328 | }
329 |
330 | class RuleState extends InitialState {
331 | override def next : BisonTokens.YYToken = {
332 | headInput match {
333 | case ID() => BisonTokens.ID(readID())
334 | case '{' => super.next
335 | case '\'' => BisonTokens.CHARLIT(convert(readQuoted('\'')).charAt(0))
336 | case '"' => BisonTokens.STRINGLIT(convert(readQuoted('"')))
337 | case '%' => {
338 | nextInput
339 | headInput match {
340 | case '%' => {
341 | nextInput
342 | state = null
343 | BisonTokens.END(restInput)
344 | }
345 | case ID() => {
346 | readID() match {
347 | case "prec" => BisonTokens.PREC()
348 | case s:String =>
349 | throw new GrammarSpecificationError("Illegal keyword %"+s)
350 | }
351 | }
352 | case ch:Char => {
353 | throw new GrammarSpecificationError("Illegal directive %"+ch)
354 | }
355 | }
356 | }
357 | case ch:Char => nextInput; BisonTokens.YYCHAR(ch);
358 | }
359 | }
360 | }
361 | }
362 |
363 | object BisonScanner {
364 | def main(args : Array[String]) = {
365 | for (s <- args) {
366 | val scanner : BisonScanner = new BisonScanner(Source.fromFile(s))
367 | while (scanner.hasNext) {
368 | println(scanner.next)
369 | }
370 | }
371 | }
372 | }
373 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/BisonTable.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.io.Source
20 | import scala.collection.mutable.Set
21 | import scala.collection.mutable.HashSet;
22 |
23 |
24 | /**
25 | * LALR(1) Parse tables in Bison format
26 | */
27 | class BisonTable(val bison : BisonGrammar) extends Table(bison) {
28 |
29 | def fromFile(filename : String) = {
30 | if (Options.meta_debug) {
31 | println("Reading bison output " + filename);
32 | }
33 | val s : Source = Source.fromFile(filename);
34 | getStates(s);
35 | s.reset();
36 | getActions(Source.fromFile(filename))
37 | }
38 |
39 | private def skipToStates(it : Iterator[String]) : Int = {
40 | for (s <- it) {
41 | if (s.startsWith("state ") || s.startsWith("State ")) {
42 | val rest = s.substring(6,s.length)
43 | if (!rest.contains(':')) {
44 | val stateNum = Integer.parseInt(rest)
45 | return stateNum;
46 | }
47 | }
48 | }
49 | -1
50 | }
51 |
52 | private def getStates(s : Source) = {
53 | val it : Iterator[String] = s.getLines;
54 | while (skipToStates(it) >= 0) {
55 | it.next;
56 | states += getState(it)
57 | }
58 | }
59 |
60 | private def getState(it : Iterator[String]) : State = {
61 | val is : Set[Item] = new HashSet[Item]();
62 | /*if (expectTwoEmpty) {
63 | val first = it.next;
64 | if (!first.equals("\n")) {
65 | println("Unexpected bison output file format: expected blank line: " + first);
66 | System.exit(-1);
67 | }
68 | }*/
69 | for (s <- it) {
70 | if (s.equals("") || s.equals("\n")) {
71 | return new State(states.length,is);
72 | } else {
73 | is += Item.fromLine(grammar,s);
74 | }
75 | }
76 | throw new GrammarSpecificationError("unexpected EOF")
77 | }
78 |
79 | private def getActions(s : Source) = {
80 | val it : Iterator[String] = s.getLines;
81 | var i : Int = 0;
82 | while (skipToStates(it) >= 0) {
83 | // println("Getting actions for state " + i);
84 | it.next;
85 | val state : State = states(i);
86 | val check : State = getState(it);
87 | if (!state.equals(check)) {
88 | throw new GrammarSpecificationError("State mismatch: " + state + " != " + check);
89 | }
90 | getAction(state,it)
91 | // println(state);
92 | i += 1;
93 | }
94 | }
95 |
96 | private def getAction(state : State, it : Iterator[String]) : Unit = {
97 | var empty : Boolean = false;
98 | for (s <- it) {
99 | if (s.equals("\n") || s.equals("")) {
100 | if (empty) return ();
101 | empty = true;
102 | } else {
103 | empty = false;
104 | val pieces : Array[String] = s.substring(4,s.length).split(" +");
105 | if (pieces(1).charAt(0) != '[' ) {
106 | pieces(1) match {
107 | case "shift," => {
108 | val next : Int = Integer.parseInt(pieces(6));
109 | grammar.find(pieces(0)) match {
110 | case Some(nt:ArtificialNonterminal) =>
111 | state.putGoto(nt,states(next))
112 | case Some(t:Terminal) =>
113 | state.putAction(t,ShiftAction(states(next)));
114 | case s => throw new GrammarSpecificationError("Unknown terminal "
115 | +pieces(0));
116 | }
117 | }
118 | case "reduce" => {
119 | val num : Int = Integer.parseInt(pieces(4));
120 | val rule : Rule = grammar.rules(num);
121 | val action : Action = ReduceAction(rule);
122 | if (pieces(0).equals("$default")) {
123 | state.default = action
124 | } else {
125 | grammar.find(pieces(0)) match {
126 | case Some(t:Terminal) => state.putAction(t,action)
127 | case _ => throw new GrammarSpecificationError("Unknown terminal"
128 | +pieces(0));
129 | }
130 | }
131 | }
132 | case "go" => {
133 | val next : Int = Integer.parseInt(pieces(4));
134 | grammar.find(pieces(0)) match {
135 | case Some(nt:Nonterminal) => state.putGoto(nt,states(next))
136 | case _ => throw new GrammarSpecificationError("Unknown nonterm "
137 | +pieces(0));
138 | }
139 | }
140 | case "accept" => {
141 | state.default = AcceptAction();
142 | }
143 | case "error" => {
144 | grammar.find(pieces(0)) match {
145 | case Some(t:Terminal) =>
146 | state.putAction(t,ErrorAction(pieces(2)));
147 | case _ => throw new GrammarSpecificationError("Unknown terminal "
148 | +pieces(0));
149 | }
150 | }
151 | case _ => {
152 | for (s <- pieces) {
153 | println("Piece: " + s);
154 | }
155 | throw new GrammarSpecificationError("Unknown action " + pieces(1) + " in " + pieces);
156 | }
157 | }
158 | }
159 | }
160 | }
161 | }
162 | }
163 |
164 | object BisonTable {
165 | def main(args : Array[String]) = {
166 | for (s <- args) {
167 | val scanner : BisonScanner = new BisonScanner(Source.fromFile(s+".y"))
168 | val parser : BisonParser = new BisonParser();
169 | parser.reset(s+".y",scanner);
170 | if (parser.yyparse()) {
171 | println(parser.result);
172 | val table : BisonTable = new BisonTable(parser.result);
173 | table.fromFile(s+".output");
174 | println(table);
175 | table.setRecognitionPoints();
176 | }
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/BlockCode.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class BlockCode(cl : List[Code]) extends Code {
20 | override def toString : String = {
21 | "{" + (cl foldRight "}")((c:Code,s:String) => (c.toString) + s);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/CharLitTerminal.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 | import edu.uwm.cs.util.CharUtil;
19 |
20 | case class CharLitTerminal(c : Char) extends Terminal(CharUtil.lit(c),"") {
21 | }
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Code.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | class Code { }
20 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/ErrorAction.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class ErrorAction(val reason : String) extends Action {
20 | override def toString = "error " + reason
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/ErrorNonterminal.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | /*
20 | case class ErrorNonterminal() extends ArtificialNonterminal("error","") {
21 | }*/
22 |
23 | object ErrorNonterminal {
24 | def apply() = ArtificialNonterminal("error","");
25 | def unapply(x : Symbol) : Boolean = x match {
26 | case ArtificialNonterminal("error","") => true;
27 | case _ => false
28 | };
29 | }
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/First.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.Set;
20 | import scala.collection.mutable.{HashMap};
21 | import scala.collection.immutable.ListSet;
22 |
23 | class First(grammar : Grammar) extends Function[Any,FirstSet] {
24 |
25 | private val ntmap : HashMap[Nonterminal,FirstSet] = new HashMap;
26 |
27 | // initialize and run to a fixed point
28 | {
29 | for (sym <- grammar.all_symbols) {
30 | sym match {
31 | case nt:Nonterminal => ntmap.put(nt,FirstSet.empty);
32 | case _ => ()
33 | }
34 | }
35 | var done : Boolean = false;
36 | while (!done) {
37 | done = true;
38 | for (sym <- grammar.all_symbols) {
39 | sym match {
40 | case nt:Nonterminal => {
41 | var fs : FirstSet = FirstSet.empty;
42 | for (rule <- nt.rules) {
43 | fs = fs ++ first(rule)
44 | }
45 | if (!(fs.equals(ntmap(nt)))) {
46 | ntmap.put(nt,fs);
47 | // println("getting bigger: FIRST(" + nt.name + ") = " + fs);
48 | done = false;
49 | }
50 | }
51 | case _ => ()
52 | }
53 | }
54 | }
55 | /*
56 | for ((nt,fs) <- ntmap) {
57 | println("FIRST(" + nt.name + ") = " + fs);
58 | }*/
59 | }
60 |
61 | def first(sym : Symbol) : FirstSet = {
62 | sym match {
63 | case nt : Nonterminal => ntmap(nt);
64 | case t : Terminal => new FirstSet(ListSet.empty + t,false)
65 | }
66 | }
67 |
68 | def first(rule : Rule) : FirstSet = first(new Item(rule,0));
69 |
70 | def first(item : Item) : FirstSet = first(item.rule.rhs.drop(item.index));
71 |
72 | def first(l : List[Any]) : FirstSet = {
73 | l match {
74 | case Nil => FirstSet.epsilon
75 | case h::t => apply(h) dot first(t)
76 | }
77 | }
78 |
79 | override def apply(x : Any) : FirstSet = {
80 | x match {
81 | case x:Item => first(x)
82 | case x:Rule => first(x)
83 | case x:List[Any] => first(x)
84 | case x:Symbol => first(x)
85 | case _ => FirstSet.empty
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/FirstSet.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.immutable.Set;
20 | import scala.collection.immutable.ListSet;
21 |
22 | class FirstSet(val set : Set[Terminal], val incEpsilon : Boolean) {
23 | def dot(other : => FirstSet) : FirstSet = {
24 | if (incEpsilon) new FirstSet(set ++ other.set, other.incEpsilon);
25 | else this;
26 | }
27 | def ++(other : FirstSet) : FirstSet = {
28 | if (incEpsilon) new FirstSet(set ++ other.set, true);
29 | else new FirstSet(set ++ other.set, other.incEpsilon);
30 | }
31 | override def equals(x : Any) = {
32 | x match {
33 | case o:FirstSet => set.equals(o.set) && incEpsilon == o.incEpsilon
34 | case _ => false
35 | }
36 | }
37 | override def hashCode() : Int = set.hashCode() + incEpsilon.hashCode();
38 |
39 | override def toString : String = {
40 | if (incEpsilon) set.toString + " + e"
41 | else set.toString
42 | }
43 | }
44 |
45 | object FirstSet {
46 | val empty : FirstSet = new FirstSet(ListSet.empty,false);
47 | val epsilon : FirstSet = new FirstSet(ListSet.empty,true);
48 | }
49 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Follow.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.Set;
20 | import scala.collection.mutable.{HashMap};
21 | import scala.collection.immutable.ListSet;
22 |
23 |
24 | class Follow(grammar : Grammar, first : First)
25 | extends Function[Nonterminal,Set[Terminal]]
26 | {
27 | private val ntfol : HashMap[Nonterminal,scala.collection.immutable.Set[Terminal]] = new HashMap;
28 |
29 | { // initialize the follow set
30 | for (sym <- grammar.all_symbols) {
31 | sym match {
32 | case nt:Nonterminal =>
33 | ntfol.put(nt,scala.collection.immutable.Set.empty);
34 | case _ => ()
35 | }
36 | }
37 | }
38 |
39 | private var done : Boolean = false;
40 |
41 | {
42 | // standard "code until done" loop:
43 | while (!done) {
44 | done = true;
45 | for (rule <- grammar.rules) {
46 | setFollow(rule.rhs,ntfol(rule.lhs));
47 | }
48 | }
49 | }
50 |
51 | private def setFollow(l : List[Symbol], fol : scala.collection.immutable.Set[Terminal]) : Unit = {
52 | l match {
53 | case (nt:Nonterminal)::t => {
54 | val oldFol : scala.collection.immutable.Set[Terminal] = ntfol(nt);
55 | val newFol : Set[Terminal] = follow(t,fol);
56 | if (!(newFol subsetOf oldFol)) {
57 | ntfol.put(nt,oldFol ++ newFol);
58 | done = false;
59 | }
60 | }
61 | case _ => ()
62 | }
63 | l match {
64 | case Nil => ();
65 | case _::t => setFollow(t,fol);
66 | }
67 | }
68 |
69 | def apply(item : Item) : Set[Terminal] = {
70 | follow(item.rule.rhs.drop(item.index),ntfol(item.rule.lhs))
71 | }
72 |
73 | private def follow(t : List[Symbol], fol : scala.collection.immutable.Set[Terminal]) : Set[Terminal] = {
74 | (first(t) dot new FirstSet(fol,false)).set
75 | }
76 |
77 | def apply(nt : Nonterminal) : Set[Terminal] = ntfol(nt);
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Generator.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.io.Source
20 | import java.io._
21 | import scala.collection.Set
22 | import scala.collection.immutable.ListSet
23 | import scala.collection.mutable._
24 | import edu.uwm.cs.util.CharUtil
25 |
26 | /** Generate recursive-ascent-descent parser for the given tables.
27 | * This technique is inspired by Nigel Horspool's paper
28 | * on the same topic with a number of sloppy shortcuts.
29 | * Any errors are strictly my own (John Boyland).
30 | */
31 | class Generator(prefix : String, table : BisonTable)
32 | {
33 | val lctable : LeftCornerTable = new LeftCornerTable(table);
34 |
35 | def writeFiles() = {
36 | if (Options.verbose > 0) writeOutput();
37 | writeTokens();
38 | writeParser();
39 | }
40 |
41 | def writeOutput() : Unit = {
42 | var fw : Writer = new FileWriter(prefix + ".lcoutput")
43 | val pw : PrintWriter = new PrintWriter(fw);
44 | pw.println("Recognition points");
45 | pw.println();
46 | pw.println(table.grammar.toString(true));
47 | pw.println();
48 | pw.println(lctable.toString(true)); // was false
49 | pw.close();
50 | }
51 |
52 | def writeTokens() : Unit = {
53 | var fw : Writer = new FileWriter(prefix + "Tokens.scala")
54 | val pw : PrintWriter = new PrintWriter(fw);
55 |
56 | pw.println(table.bison.prologue);
57 | pw.println("object " + prefix + "Tokens {");
58 | pw.println(" class YYSymbol;")
59 | pw.println();
60 | writeTerminals(pw);
61 | pw.println("}");
62 | pw.close();
63 | }
64 |
65 | def writeParser() : Unit = {
66 | var fw : Writer = new FileWriter(prefix + "Parser.scala")
67 | val pw : PrintWriter = new PrintWriter(fw);
68 |
69 | pw.println(table.bison.prologue);
70 | pw.println("/** Generated LALR(1) recursive-ascent-descent parser */");
71 | pw.println("class " + prefix + "Parser extends " + prefix + "ParserBase {");
72 | writeNonterminals(pw);
73 | pw.println();
74 | /*
75 | pw.println(" private class YYGoto;");
76 | pw.println(" private case class YYBase(yy : YYNonterminal) extends YYGoto");
77 | pw.println(" private case class YYNested(yy : YYGoto) extends YYGoto");
78 | */
79 | pw.println(" private var yynt : YYNonterminal = null;");
80 | pw.println();
81 | pw.println(" case class YYError(s:String) extends Exception(s);");
82 | pw.println();
83 | pw.println(" // boilerplate");
84 | pw.println();
85 | pw.println(" var yydebug : Boolean = false;");
86 | pw.println(" private var yyinput : Iterator["+prefix+"Tokens.YYToken] = null;");
87 | pw.println(" private var yycur : "+prefix+"Tokens.YYToken = null;");
88 | pw.println();
89 | pw.println(" private def yynext() = {");
90 | pw.println(" yycur = {");
91 | pw.println(" if (yyinput.hasNext) {");
92 | pw.println(" yyinput.next");
93 | pw.println(" } else {");
94 | pw.println(" "+prefix+"Tokens.YYEOF();");
95 | pw.println(" }");
96 | pw.println(" }");
97 | if (Options.debug)
98 | pw.println(" if (yydebug) println(\"Current token now is \" + yycur);");
99 | pw.println(" }");
100 | pw.println("");
101 | pw.println(" private def yypanic(test : ("+prefix+"Tokens.YYToken) => Boolean) = {");
102 | pw.println(" while (!test(yycur)) {");
103 | if (Options.debug)
104 | pw.println(" if (yydebug) println(\"Discarding current token\");");
105 | pw.println(" yynext;");
106 | pw.println(" if (yycur == "+prefix+"Tokens.YYEOF()) throw new YYError(\"Giving up\")");
107 | pw.println(" }");
108 | pw.println(" }");
109 | pw.println("");
110 | pw.println(" def yyreset(input : Iterator["+prefix+"Tokens.YYToken]) = {");
111 | pw.println(" yyinput = input;");
112 | pw.println(" yynt = null;"); // No YYGoto
113 | pw.println(" yynext");
114 | pw.println(" }");
115 | pw.println("");
116 | pw.println(" def yyparse() : Boolean = {");
117 | pw.println(" try {");
118 | pw.println(" parse_"+table.grammar.start.name+"()");
119 | pw.println(" parse_YYEOF()");
120 | pw.println(" true");
121 | pw.println(" } catch {");
122 | pw.println(" case YYError(s) => yyerror(s); false");
123 | pw.println(" }");
124 | pw.println(" }");
125 | pw.println("");
126 | /*
127 | pw.println(" private def yynest(nx:Int,g: YYNonterminal) : YYGoto = {");
128 | //pw.println(" try {");
129 | pw.println(" var n : Int = nx;");
130 | pw.println(" var yygoto : YYGoto = YYBase(g)");
131 | pw.println(" while (n > 0) {");
132 | pw.println(" yygoto = YYNested(yygoto)");
133 | pw.println(" n -= 1");
134 | pw.println(" }");
135 | pw.println(" yygoto");
136 | //pw.println(" } catch {");
137 | //pw.println(" case YYError(s) => YYBase(YYNTerror(s))");
138 | //pw.println(" }");
139 | pw.println(" }");
140 | pw.println("");
141 | */
142 | pw.println(" def parse_YYCHAR(yy:Char) : Unit = {");
143 | pw.println(" yycur match {");
144 | pw.println(" case " + prefix +"Tokens.YYCHAR(`yy`) => yynext; ()");
145 | pw.println(" case _ => throw new YYError(\"Expected '\"+yy+\"'\");");
146 | pw.println(" }");
147 | pw.println(" }");
148 | pw.println("");
149 | pw.println(" // generated parser");
150 | pw.println();
151 | for (sym <- table.grammar.all_symbols) {
152 | sym match {
153 | case _:CharLitTerminal => ()
154 | case t:Terminal => {
155 | pw.println(" def parse_" + t.name + "() : " + t.getType() + " = {")
156 | pw.println(" yycur match {");
157 | pw.print(" case " + prefix + "Tokens." + t.name);
158 | if (t.typed) {
159 | pw.println("(yy) => yynext; yy");
160 | } else {
161 | pw.println("() => yynext; ()");
162 | }
163 | pw.println(" case _ => throw new YYError(\"Expected '" + t.name + "'\");");
164 | pw.println(" }");
165 | pw.println(" }\n");
166 | }
167 | case _ => ()
168 | }
169 | }
170 |
171 | for ((nt,state) <- lctable.NTstate) {
172 | pw.print(" def parse_" + code(nt) + "()")
173 | pw.print(" : " + nt.getType)
174 | pw.println(" = {");
175 | if (Options.debug)
176 | pw.println(" if (yydebug) println(\"Parsing "+nt.name+"\");");
177 | /* YYGoto:
178 | pw.println(" yystate" + state.number + "() match {");
179 | pw.println(" case YYBase(YYNT" + (code(nt)) + "(yy)) => yy");
180 | pw.println(" case YYBase(YYNTerror(s)) => throw new YYError(s)");
181 | if (Options.debug)
182 | pw.println(" case _ => throw new YYError(\"internal parser error\")");
183 | pw.println(" }");
184 | */
185 | if (Options.debug) {
186 | pw.println(" if (yystate" + state.number + "() != 0)");
187 | pw.println(" throw new YYError(\"internal parse error\");");
188 | } else {
189 | pw.println(" yystate" + state.number + "();");
190 | }
191 | pw.println(" yynt match {");
192 | if (nt.typed) {
193 | pw.println(" case YYNT" + (code(nt)) + "(yy) => yy");
194 | } else {
195 | pw.println(" case YYNT" + (code(nt)) + "() => ()");
196 | }
197 | pw.println(" case YYNTerror(s) => throw new YYError(s)");
198 | if (Options.debug)
199 | pw.println(" case _ => throw new YYError(\"internal parser error\")");
200 | pw.println(" }");
201 | /* end removal of YYGoto */
202 | pw.println(" }\n");
203 | }
204 |
205 | for (rule <- table.grammar.rules) {
206 | writeRule(pw,rule);
207 | }
208 |
209 | for ((_,state) <- lctable.NTstate) {
210 | writeState(pw,state);
211 | }
212 | pw.println(table.bison.extra);
213 |
214 | if (Options.gen_lalr_table) {
215 | writeLALRTable(pw);
216 | }
217 | pw.println("}");
218 | pw.close();
219 | }
220 |
221 | private def writeTerminals(pw : PrintWriter) = {
222 | pw.println(" class YYToken extends YYSymbol;\n");
223 | pw.println(" case class YYCHAR(yy: Char) extends YYToken {");
224 | pw.println(" override def toString() : String = \"'\" + yy + \"'\";");
225 | pw.println(" }");
226 | for (symbol <- table.grammar.all_symbols) {
227 | symbol match {
228 | case _:CharLitTerminal => ()
229 | case t:Terminal => {
230 | pw.print(" case class " + t.name + "(");
231 | if (t.typed) {
232 | pw.print("yy: " + t.getType())
233 | }
234 | pw.println(") extends YYToken;");
235 | }
236 | case _ => ()
237 | }
238 | }
239 | }
240 |
241 | private def writeNonterminals(pw : PrintWriter) = {
242 | pw.println(" class YYNonterminal extends " + prefix + "Tokens.YYSymbol;\n");
243 | pw.println(" case class YYNTerror(yy : String) extends YYNonterminal;");
244 | for (symbol <- table.grammar.all_symbols) {
245 | symbol match {
246 | case _:ArtificialNonterminal => ()
247 | case nt:Nonterminal => {
248 | pw.print(" case class YYNT" + code(nt) + "(");
249 | if (nt.typed) {
250 | pw.print("yy: " + nt.getType())
251 | }
252 | pw.println(") extends YYNonterminal;");
253 | }
254 | case _ => ()
255 | }
256 | }
257 | if (Options.gen_lalr_table) {
258 | pw.println(" case class YYNT(num : Int) extends YYNonterminal;");
259 | }
260 | }
261 |
262 | private val usedAfterRecognition : Map[Symbol,Item] = new HashMap();
263 |
264 | private def writeRule(pw: PrintWriter, rule : Rule) : Unit = {
265 | if (rule.lhs.isInstanceOf[ArtificialNonterminal]) return;
266 | // write the rescurive descent part after the recognition point
267 | pw.println();
268 | pw.println(" /** Recursive descent parser after recognition point");
269 | pw.println(" * " + new Item(rule,rule.recognitionPoint))
270 | pw.println(" */");
271 | pw.print(" private def yyrule" + rule.number + "(");
272 | var noargs : Boolean = true;
273 | var i : Int = 0;
274 | var recognized : Boolean = false;
275 | for (symbol <- rule.rhs) {
276 | if (i == rule.recognitionPoint) {
277 | finishRuleHeader(pw,rule);
278 | recognized = true;
279 | }
280 | i += 1;
281 | if (recognized) {
282 | pw.print(" ");
283 | symbol match {
284 | case CharLitTerminal(ch) => {
285 | pw.println("parse_YYCHAR("+ toLit(ch) +");");
286 | }
287 | case nt:ArtificialNonterminal => {
288 | if (nt.name.charAt(0) == '@') {
289 | pw.println(nt.rules(0).action);
290 | } else {
291 | sys.error("Unknown artificial nonterminal " + nt);
292 | }
293 | }
294 | case _ => {
295 | usedAfterRecognition.put(symbol,new Item(rule,i-1));
296 | if (symbol.typed) {
297 | pw.print("val yyarg" + i + " : " + symbol.getType() + " = ");
298 | }
299 | pw.println("parse_" + code(symbol) + "();");
300 | }
301 | }
302 | } else {
303 | // not yet recognized
304 | if (symbol.typed) {
305 | if (noargs) {
306 | noargs = false;
307 | } else {
308 | pw.print(", ");
309 | }
310 | pw.print("yyarg" + i + " : " + symbol.getType());
311 | }
312 | }
313 | }
314 | if (!recognized) finishRuleHeader(pw,rule);
315 | rule.action match {
316 | case NoCode() => {
317 | if (rule.lhs.typed) {
318 | pw.println(" yyresult = yyarg1;");
319 | }
320 | }
321 | case _ => {
322 | pw.println(" " + rule.action);
323 | }
324 | }
325 | if (rule.lhs.typed) {
326 | pw.println(" yyresult");
327 | }
328 | pw.println(" }");
329 | }
330 |
331 | private def finishRuleHeader(pw : PrintWriter, rule : Rule) = {
332 | pw.print(") ");
333 | if (rule.lhs.typed) {
334 | pw.println(": " + rule.lhs.getType() + " = {");
335 | pw.println(" var yyresult : " + rule.lhs.getType() +
336 | " = " + defaultInitial(rule.lhs.getType()) + ";");
337 | } else {
338 | pw.println(": Unit = {");
339 | }
340 | if (Options.debug)
341 | pw.println(" if (yydebug) println(\"Announcing rule "+rule.number+"\");");
342 | }
343 |
344 | private def defaultInitial(t : String) : String = {
345 | t match {
346 | case "Boolean" => "false";
347 | case "Int" => "0";
348 | case "Double" => "0";
349 | case "Float" => "0";
350 | case "Char" => "0";
351 | case "Byte" => "0";
352 | case "Short" => "0";
353 | case _ => "null";
354 | }
355 | }
356 |
357 | private def toLit(ch : Char) : String = CharUtil.lit(ch);
358 |
359 | private def code(s : Symbol) : String = s.name;
360 |
361 | private val stateWritten : HashSet[Int] = new HashSet;
362 |
363 | private def writeState(pw : PrintWriter, state : LeftCornerState) : Unit = {
364 | if (stateWritten contains (state.number)) return;
365 | stateWritten += state.number;
366 | // println("Writing state " + state.number);
367 |
368 | // we cache everything into a string builder first,
369 | // to avoid intermixing states
370 | val sb : StringBuilder = new StringBuilder();
371 |
372 | // the "longest" item
373 | val longest : Item = state.longestItem;
374 | var nextIndex : Int = 1;
375 | if (longest != null) nextIndex = longest.index+1;
376 | val nextarg : String = "yyarg" + nextIndex;
377 |
378 | sb.append("\n private def yystate" + state.number + "(");
379 | var noargs : Boolean = true;
380 | var i : Int = 0;
381 | if (longest != null) {
382 | for (symbol <- (longest.rule.rhs.slice(0,longest.index))) {
383 | i += 1;
384 | if (symbol.typed) {
385 | if (noargs) {
386 | noargs = false;
387 | } else {
388 | sb.append(", ");
389 | }
390 | sb.append("yyarg" + i + ": " + symbol.getType());
391 | }
392 | }
393 | } else if (state.nonterminal != null && !state.atStart) {
394 | // for fake item:
395 | if (state.nonterminal.typed) {
396 | sb.append("yyarg1: " + state.nonterminal.getType())
397 | }
398 | }
399 | /*YYGoto
400 | sb.append(") : YYGoto = {\n")
401 | */
402 | sb.append(") : Int = {\n") // No YYGoto
403 | if (Options.debug)
404 | sb append " if (yydebug) println(\"Entering state "+ state.number+"\")\n";
405 | /* YYGoto
406 | sb append " var yygoto : YYGoto = null;\n";
407 | */
408 | sb append " var yygoto : Int = 0;\n"; // No YYGoto
409 |
410 | if (state.gotos contains (ErrorNonterminal())) {
411 | sb append " try {\n";
412 | }
413 |
414 | sb append " yycur match {\n";
415 | for ((t,action) <- state.actions) {
416 | sb append " case ";
417 | sb append prefix
418 | sb append "Tokens."
419 | t match {
420 | case CharLitTerminal(ch) => {
421 | sb append "YYCHAR(" + toLit(ch) + ")";
422 | }
423 | case _ => {
424 | sb append (t.name);
425 | sb append '(';
426 | if (t.typed) {
427 | action match {
428 | case ShiftAction(_) => sb append nextarg
429 | case _ => sb append "_"
430 | }
431 | }
432 | sb append ')'
433 | }
434 | }
435 | sb append " => ";
436 | action match {
437 | case AnnounceAction(r) => {
438 | appendRuleCall(sb,longest,r);
439 | }
440 | case AcceptNTAction(nt) => {
441 | appendAcceptNT(sb,nt);
442 | }
443 | case ShiftAction(s) => {
444 | sb append "yynext; ";
445 | writeState(pw,s.asInstanceOf[LeftCornerState]);
446 | appendGoto(sb,longest,s);
447 | }
448 | case ErrorAction(s) => {
449 | /* YYGoto
450 | sb append "yygoto = YYBase(YYNTerror(\"";
451 | sb append s
452 | sb append "\"));\n"
453 | */
454 | sb append "yynt = YYNTerror(\"";
455 | sb append s
456 | sb append "\");\n"
457 | }
458 | }
459 | }
460 | sb append " case _ => "
461 | state.default match {
462 | case null =>
463 | /* YYGoto
464 | sb append "yygoto = YYBase(YYNTerror(\"syntax error\"));\n";
465 | */
466 | sb append "yynt = YYNTerror(\"syntax error\");\n";
467 | case AnnounceAction(r) =>
468 | appendRuleCall(sb,longest,r)
469 | case AcceptNTAction(nt) =>
470 | appendAcceptNT(sb,nt);
471 | case AcceptAction() =>
472 | appendRuleCall(sb,longest,table.grammar.rules(0));
473 | }
474 | sb append " }\n";
475 |
476 | if (state.gotos contains ErrorNonterminal()) {
477 | sb append " } catch {\n";
478 | /* YYGoto
479 | sb append " case YYError(s) => yygoto = YYBase(YYNTerror(s));\n";
480 | */
481 | sb append " case YYError(s) => yynt = YYNTerror(s);\n";
482 | sb append " }\n";
483 | }
484 |
485 | /* YYGoto:
486 | sb append " while (true) {\n";
487 | sb append " yygoto match {\n";
488 | sb append " case YYNested(g) => return g;\n";
489 | */
490 | sb append " while (yygoto == 0) {\n";
491 | if (state.gotos contains (ErrorNonterminal())) {
492 | sb append " try {\n";
493 | }
494 |
495 | sb append " yynt match {\n";
496 |
497 | for ((nt,next) <- state.gotos) {
498 | writeState(pw,next.asInstanceOf[LeftCornerState]);
499 | if (nt == ErrorNonterminal()) {
500 | /* YYGoto
501 | sb append " case YYBase(YYNTerror(s)) => \n"
502 | */
503 | sb append " case YYNTerror(s) => \n"
504 | sb append " if (yycur == "+prefix+"Tokens.YYEOF()) return 0;"
505 | sb append " yyerror(s)\n"
506 | if (Options.debug)
507 | sb append " if (yydebug) println(\"Recovering in state "+ state.number+"\")\n";
508 | var panic : scala.collection.immutable.Set[Terminal] =
509 | scala.collection.immutable.Set.empty;
510 | for (item <- next.core) {
511 | panic ++= lctable.follow(item);
512 | }
513 | sb append " yypanic({ t:"
514 | sb append prefix
515 | sb append "Tokens.YYToken => t match {\n";
516 | for (t <- panic) {
517 | sb append " case ";
518 | sb append prefix
519 | sb append "Tokens.";
520 | t match {
521 | case CharLitTerminal(ch) => {
522 | sb append "YYCHAR("
523 | sb append toLit(ch)
524 | sb append ")"
525 | }
526 | case _ => {
527 | sb append (t.name)
528 | sb append "("
529 | if (t.typed) sb append "_"
530 | sb append ")"
531 | }
532 | }
533 | sb append " => true\n"
534 | }
535 | sb append " case _ => false\n";
536 | sb append " }})\n";
537 | sb append " ";
538 | } else {
539 | /* YYGoto:
540 | sb append (" case YYBase(YYNT" + code(nt) + "(");
541 | sb append nextarg;
542 | sb append ")) => ";
543 | */
544 | sb append (" case YYNT" + code(nt) + "(");
545 | if (nt.typed) {
546 | sb append nextarg;
547 | }
548 | sb append ") => ";
549 | }
550 | appendGoto(sb,longest,next);
551 | }
552 | // The following won't happen any more
553 | if (state.nonterminal != null &&
554 | !(state.gotos isDefinedAt(state.nonterminal))) {
555 | /* YYGoto:
556 | sb append " case x@YYBase(_:YYNT" + code(state.nonterminal) +
557 | ") => return x;\n";
558 | */
559 | sb append " case _:YYNT" + code(state.nonterminal) +
560 | " => return 0;\n";
561 | }
562 | if (!(state.gotos isDefinedAt ErrorNonterminal())) {
563 | /* YYYGoto:
564 | sb append " case e@YYBase(_:YYNTerror) => return e\n";
565 | */
566 | sb append " case _:YYNTerror => return 0;\n";
567 | }
568 |
569 | if (Options.debug) {
570 | /* YYGoto:
571 | sb append " case _ => return YYBase(YYNTerror(\"internal parser error\"));\n";
572 | */
573 | sb append " case _ => yynt = YYNTerror(\"internal parser error\"); return 0;\n";
574 | }
575 | sb append " }\n";
576 | if (state.gotos contains ErrorNonterminal()) {
577 | sb append " } catch {\n";
578 | /* YYGoto
579 | sb append " case YYError(s) => yygoto = YYBase(YYNTerror(s));\n";
580 | */
581 | sb append " case YYError(s) => yynt = YYNTerror(s);\n";
582 | sb append " }\n";
583 | }
584 | sb append " }\n";
585 | sb append " yygoto-1\n"; // YYGoto omits "-1"
586 | sb append " }\n";
587 | pw.append(sb.toString);
588 | }
589 |
590 | private def appendAcceptNT(sb : StringBuilder, nt : Nonterminal) : Unit = {
591 | /* YYGoto
592 | sb append "yygoto = YYNested(YYNested(YYBase(YYNT"+code(nt)+"(";
593 | if (nt.typed) sb.append("yyarg1");
594 | else sb.append("()");
595 | sb append "))));\n";
596 | */
597 | sb append "yynt = YYNT"+code(nt)+"(";
598 | if (nt.typed) {
599 | sb.append("yyarg1");
600 | }
601 | sb append "); yygoto = 2;\n"
602 | }
603 |
604 | private def appendRuleCall(sb : StringBuilder,
605 | longest : Item,
606 | rule : Rule) = {
607 | // YYGOTO: This routine must be rewritten to use yynest.
608 | val rp = rule.getRecognitionPoint;
609 | var li : Int = 0;
610 | if (longest != null) li = longest.index;
611 | if (rule.lhs.typed) {
612 | sb append "yynt = " // No YYGoto
613 | sb append "YYNT"
614 | sb append code(rule.lhs)
615 | sb append "(yyrule";
616 | sb append rule.number;
617 | sb append "(";
618 | appendActuals(sb,li-rp,rule.rhs.slice(0,rp))
619 | sb append ")); ";
620 | } else {
621 | sb append "yyrule";
622 | sb append rule.number;
623 | sb append "(";
624 | appendActuals(sb,li-rp,rule.rhs.slice(0,rp))
625 | sb append "); yynt = YYNT";
626 | sb append code(rule.lhs);
627 | sb append "(); ";
628 | }
629 | sb append "yygoto = "
630 | sb append rp;
631 | sb append "\n";
632 | }
633 |
634 | private def appendGoto(sb : StringBuilder, longest : Item, target : State) = {
635 | val nextlongest = target.longestItem;
636 | var li : Int = 0;
637 | if (longest != null) li = longest.index;
638 | sb append "yygoto = yystate";
639 | sb append target.number;
640 | sb append "(";
641 | if (nextlongest != null) {
642 | appendActuals(sb,li-nextlongest.index+1,
643 | nextlongest.rule.rhs.slice(0,nextlongest.index));
644 | } else if (target.asInstanceOf[LeftCornerState].nonterminal.typed) {
645 | sb append "yyarg1";
646 | }
647 | sb append ");\n";
648 | }
649 |
650 | private def appendActuals(sb : StringBuilder,
651 | offset : Int,
652 | syms :scala.collection.Seq[Symbol]) : Boolean = {
653 | var nonempty : Boolean = false;
654 | var i : Int = offset;
655 | for (sym <- syms) {
656 | i += 1;
657 | if (sym.typed) {
658 | if (nonempty) {
659 | sb append ',';
660 | } else {
661 | nonempty = true
662 | }
663 | sb append "yyarg";
664 | sb append i;
665 | }
666 | }
667 | nonempty;
668 | }
669 |
670 | private def writeLALRTable(pw : PrintWriter) = {
671 | pw.print(""" abstract class YYAction;
672 | case class YYAshift(state : Int) extends YYAction;
673 | case class YYAreduce(rule : Int, nt:YYNonterminal, size : Int) extends YYAction;
674 | case class YYAerror(reason : String) extends YYAction;
675 | case class YYAaccept() extends YYAction;
676 |
677 | private var table : Array[Function[CoolTokens.YYSymbol,YYAction]] = Array(""");
678 | var started : Boolean = false;
679 | for (state <- table.states) {
680 | if (started) pw.print(","); else started = true;
681 | pw.println("\n (x => x match {");
682 | for ((t,action) <- state.actions) {
683 | pw.print(" case " + prefix + "Tokens.");
684 | t match {
685 | case CharLitTerminal(ch) => pw.print("YYCHAR(" + toLit(ch) + ")");
686 | case _ => pw.print(t.name + (if (t.typed) "(_)" else "()"));
687 | }
688 | pw.print(" => ");
689 | writeAction(pw,action);
690 | pw.println();
691 | }
692 | for ((nt,st) <- state.gotos) {
693 | val nts =
694 | if (nt.name.startsWith("@")) "(" + nt.name.substring(1) + ")"
695 | else if (nt.typed) nt.name + "(_)"
696 | else if (nt.name == "error") nt.name + "(_)";
697 | else nt.name + "()";
698 | pw.println(" case YYNT" + nts + " => YYAshift(" + st.number + ")");
699 | }
700 | pw.print(" case _ => ");
701 | var defAction : Action = state.default;
702 | if (defAction == null) defAction = ErrorAction("parse error");
703 | writeAction(pw,defAction);
704 | pw.print("})");
705 | }
706 | pw.println(");\n");
707 | pw.println(" val MAX_STATE = table.length-1;\n");
708 | pw.println(" def getAction(state : Int, s : " + prefix + "Tokens.YYSymbol) : YYAction = table(state)(s);");
709 | }
710 |
711 | private def writeAction(pw: PrintWriter, action: Action): Unit = {
712 | action match {
713 | case AcceptAction() => pw.print("YYAaccept()");
714 | case ErrorAction(reason) => pw.print("YYAerror(\"" + reason + "\")");
715 | case ShiftAction(target) => {
716 | val st = target.number;
717 | pw.print("YYAshift(" + st + ")");
718 | }
719 | case ReduceAction(rule) => {
720 | val nt = rule.lhs;
721 | val nts =
722 | if (nt.name.startsWith("@")) "(" + nt.name.substring(1) + ")"
723 | else if (nt.getType() == "Boolean") nt.name + "(false)"
724 | else if (nt.getType() == "Int") nt.name + "(0)"
725 | else if (nt.typed) nt.name + "(null)"
726 | else nt.name + "()";
727 | pw.print("YYAreduce(" + rule.number + ", YYNT" + nts + ", " + rule.rhs.length + ")");
728 | }
729 | }
730 | }
731 | }
732 |
733 | object RunGenerator {
734 | def main(args : Array[String]) : Unit = {
735 | for (s <- args) {
736 | if (s == "-v" || s == "--verbose") {
737 | Options.verbose += 1;
738 | } else if (s == "-V" || s == "--version") {
739 | println("ScalaBison version " + Version.version);
740 | return;
741 | } else if (s == "-h" || s == "--help") {
742 | println("ScalaBison version " + Version.version);
743 | println("Generates LAXLC(1) parsers in Scala from bison input and output files.");
744 | println();
745 | println("Usage: scala-bison [OPTION]... GRAMMARFILE...\n");
746 | println("Options: ");
747 | println(" -v \n --verbose");
748 | println("\tGenerate XXX.lcoutput file");
749 | println(" -V \n --version");
750 | println("\tPrint version and exit");
751 | println(" -t \n --debug");
752 | println("\tGenerate debugging code that can be turned on using yydebug.");
753 | println(" -h \n --help");
754 | println("\tPrint this message, and exit.");
755 | } else if (s == "-t" || s == "--debug") {
756 | Options.debug = true;
757 | } else if (s == "-T" || s == "--meta-debug") {
758 | Options.meta_debug = true;
759 | } else if (s == "-d" || s == "--lalr-table") {
760 | Options.gen_lalr_table = true;
761 | } else if (s.startsWith("-")) {
762 | println("Unknown option " + s + "; use --help to get legal options");
763 | System.exit(-1);
764 | } else {
765 | try {
766 | val scanner : BisonScanner = new BisonScanner(Source.fromFile(s))
767 | val parser : BisonParser = new BisonParser();
768 | val sep : Int = s.lastIndexOf(File.separatorChar);
769 | val filename = if (sep < 0) s; else s.substring(sep+1);
770 | val dot : Int = filename.lastIndexOf('.');
771 | val prefix : String =
772 | if (dot < 0) filename; else filename.substring(0,dot);
773 | if (Options.meta_debug) {
774 | println("Parsing " + filename);
775 | }
776 | parser.reset(s,scanner);
777 | if (Options.meta_debug) {
778 | parser.yydebug = true;
779 | }
780 | if (parser.yyparse()) {
781 | // println(parser.result);
782 | val table : BisonTable = new BisonTable(parser.result);
783 | table.fromFile(prefix+".output");
784 | // println(table);
785 | if (table.states.isEmpty) {
786 | println("Error: didn't find any states in the bison outfile file.\nPerhaps this is a bison version SCalaBison doesn't understand.");
787 | System.exit(-1);
788 | }
789 | val gen : Generator = new Generator(prefix,table);
790 | gen.writeFiles();
791 | } else {
792 | println("Could not parse "+filename);
793 | System.exit(-1);
794 | }
795 | } catch {
796 | case e:java.io.IOException => {
797 | println("Problem with input/output files: " + e);
798 | System.exit(-1);
799 | }
800 | }
801 | }
802 | }
803 | }
804 | }
805 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Grammar.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.mutable.Map;
20 | import scala.collection.mutable.ArrayBuffer;
21 | import scala.collection.mutable.HashMap;
22 |
23 | class Grammar {
24 | protected val symbolmap : Map[String,Symbol] = new HashMap;
25 | protected val symbols : ArrayBuffer[Symbol] = new ArrayBuffer;
26 |
27 | protected var _start : Nonterminal = null;
28 | def start : Nonterminal = _start;
29 |
30 | val end : Terminal = new Terminal("YYEOF","");
31 |
32 | def all_symbols : Iterable[Symbol] = symbols;
33 |
34 | def find(name : String) : Option[Symbol] = symbolmap.get(name);
35 |
36 | protected def add[T <: Symbol](symbol : T) : T = {
37 | if (symbolmap.contains(symbol.name)) {
38 | return symbolmap.apply(symbol.name).asInstanceOf[T];
39 | }
40 | symbols += symbol;
41 | symbolmap.put(symbol.name,symbol); symbol
42 | }
43 |
44 | def get(name : String) : Symbol = {
45 | find(name) match {
46 | case Some(s) => s;
47 | case None => add(new Nonterminal(name,""));
48 | }
49 | }
50 |
51 | // add(start);
52 | // add(epsilon);
53 | add(end);
54 | symbolmap.put("$end",end); // another name
55 |
56 | val rules : ArrayBuffer[Rule] = new ArrayBuffer[Rule]();
57 |
58 | override def toString : String = toString(false);
59 |
60 | def toString(showRecognition : Boolean) : String = {
61 | val sb : StringBuilder = new StringBuilder("Grammar\n");
62 | var lastNT : Nonterminal = null;
63 | var i : Int = 0;
64 | for (rule <- rules) {
65 | val nt : Nonterminal = rule.lhs;
66 | if (nt != lastNT) sb append '\n';
67 | if (i < 10000) sb append ' ';
68 | if (i < 1000) sb append ' ';
69 | if (i < 100) sb append ' ';
70 | if (i < 10) sb append ' ';
71 | sb append i;
72 | i += 1;
73 | sb append ' ';
74 | if (nt == lastNT) {
75 | for (_ <- (0 until nt.name.length)) {
76 | sb append ' ';
77 | }
78 | sb append '|';
79 | } else {
80 | sb append (nt.name);
81 | sb append ':';
82 | lastNT = nt;
83 | }
84 | if (rule.rhs == Nil) {
85 | if (showRecognition) sb append " .";
86 | sb append " /* empty */";
87 | } else {
88 | var rp : Int = rule.recognitionPoint;
89 | for (sym <- rule.rhs) {
90 | if (showRecognition && rp == 0) { sb append " ."; }
91 | rp -= 1
92 | sb append ' ';
93 | sb append (sym.name);
94 | }
95 | if (showRecognition && rp == 0) { sb append " ."; }
96 | }
97 | sb append '\n';
98 | }
99 | sb.toString
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/GrammarSpecificationError.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | class GrammarSpecificationError(s : String) extends Exception(s) { }
20 |
21 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Item.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.immutable.Set;
20 |
21 | class Item(val rule : Rule, val index : Int) {
22 |
23 | def symbol : Symbol = {
24 | if (index == rule.length) null;
25 | else rule.rhs(index);
26 | }
27 |
28 | def next() : Item = new Item(rule,index+1);
29 |
30 | /** Ready for recognition */
31 | def ready : Boolean = index == rule.getRecognitionPoint();
32 |
33 | override def equals(o : Any) : Boolean = {
34 | o match {
35 | case i:Item => rule == i.rule && index == i.index;
36 | case _ => false
37 | }
38 | }
39 |
40 | override def hashCode() : Int = rule.hashCode() + index;
41 |
42 | override def toString : String = {
43 | val sb : StringBuilder = new StringBuilder( rule.lhs.name );
44 | sb append ":";
45 | var i : Int = 0;
46 | for (symbol <- rule.rhs) {
47 | if (index == i) {
48 | sb append " .";
49 | }
50 | sb append ' '
51 | sb append symbol.name
52 | i += 1
53 | }
54 | if (index == i) {
55 | sb append " .";
56 | }
57 | sb.toString
58 | }
59 |
60 | }
61 |
62 | object Item {
63 | def fromLine(grammar : Grammar, line : String) : Item = {
64 | val rulenum : Int = Integer.parseInt(line.substring(0,5).trim);
65 | val rule : Rule = grammar.rules(rulenum);
66 | val itemtext : String = line.substring(6).trim;
67 | val parts : Array[String] = itemtext.split(" ");
68 | if (!parts(0).equals("|") && !parts(0).equals(rule.lhs.name + ":")) {
69 | throw new GrammarSpecificationError("Expected rule " + rulenum +
70 | " to have lhs = " + parts(0) +
71 | " not " + rule.lhs.name);
72 | }
73 | for (i <- 1 until (parts.length)) {
74 | if (parts(i).equals(".") || parts(i).equals("•")) {
75 | val item : Item = new Item(rule,i-1);
76 | /*
77 | if (!itemtext.equals(item.toString())) {
78 | throw new GrammarSpecificationError("sanity check failed: " +
79 | item + " != " + itemtext);
80 | }
81 | */
82 | return item
83 | }
84 | }
85 | throw new GrammarSpecificationError("Couldn't find . in " + itemtext);
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/LeftCornerFollow.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.Set;
20 | import scala.collection.mutable.{HashMap};
21 | import scala.collection.immutable.ListSet;
22 |
23 | import scala.io.Source;
24 |
25 | /**
26 | * A restriction of the Follow Set that
27 | * applies to left corner parsing:
28 | * this is the set of tokens that can follow a NT
29 | * during town-down parsing.
30 | *
31 | * This code is copied almost verbatim from Follow.scala.
32 | */
33 | class LeftCornerFollow(val grammar : Grammar,
34 | val first : First, val follow : Follow)
35 | {
36 | private val ntfol : HashMap[Nonterminal,scala.collection.immutable.Set[Terminal]] = new HashMap;
37 |
38 | { // initialize the follow set
39 | for (sym <- grammar.all_symbols) {
40 | sym match {
41 | case nt:Nonterminal =>
42 | ntfol.put(nt,scala.collection.immutable.Set.empty);
43 | case _ => ()
44 | }
45 | }
46 | }
47 |
48 | {
49 | for (rule <- grammar.rules) {
50 | val rp : Int = rule.getRecognitionPoint();
51 | setFollow(rule.rhs.drop(rp),follow(rule.lhs));
52 | }
53 |
54 | /*for ((nt,fs) <- ntfol) {
55 | println("FFollow(" + nt + ") = " + fs);
56 | }*/
57 | }
58 |
59 | private def setFollow(l : List[Symbol], fol : Set[Terminal]) : Unit = {
60 | /*println("Calling setFollow(" + l + "," + fol + ")");*/
61 | l match {
62 | case (nt:Nonterminal)::t => {
63 | val oldFol : scala.collection.immutable.Set[Terminal] = ntfol(nt);
64 | val newFol : Set[Terminal] = computeFollow(t,fol);
65 | if (!(newFol subsetOf oldFol)) {
66 | ntfol.put(nt,oldFol ++ newFol);
67 | }
68 | }
69 | case _ => ()
70 | }
71 | l match {
72 | case Nil => ();
73 | case _::t => setFollow(t,fol);
74 | }
75 | }
76 |
77 | def apply(item : Item) : Set[Terminal] = {
78 | computeFollow(item.rule.rhs.drop(item.index),follow(item.rule.lhs))
79 | }
80 |
81 | private def computeFollow(t : List[Symbol], fol : Set[Terminal]) : Set[Terminal] = {
82 | /*println("Calling computeFollow(" + t + "," + fol + ")");*/
83 | (first(t) dot new FirstSet(scala.collection.immutable.Set.empty[Terminal]++fol,false)).set
84 | }
85 |
86 | def apply(nt : Nonterminal) : Set[Terminal] = ntfol(nt);
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/LeftCornerState.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.Set;
20 | import scala.collection.immutable.ListSet;
21 | import scala.collection.mutable.HashMap;
22 | import scala.collection.mutable.ArrayBuffer;
23 | import scala.collection.mutable.HashSet;
24 |
25 | import scala.io.Source;
26 |
27 | /**
28 | * A state used for left corner parsing. We build the states
29 | * from existing LALR(1) states, and these are passed to the constructor.
30 | * This new state will have a subset of the items and a modified
31 | * subset of the actions -- some of the shift actions and all of
32 | * the ReduceActions are converted into AnnounceActions.
33 | *
34 | * Since we are building our states from existing LALR(1) states,
35 | * we distinguish three kinds of states:
36 | * - A state with the implicit item S -> |- . NT (empty core)
37 | *
- A state with the implicit item S -> |- NT .
38 | *
- A state with no implicit items.
39 | */
40 | class LeftCornerState(n : Int,
41 | val nonterminal : Nonterminal,
42 | val atStart : Boolean,
43 | val state : State,
44 | c : Set[Item]) extends State(n,c)
45 | {
46 | def this(n : Int, nt : Nonterminal, st : State) = this(n,nt,true,st,Set.empty);
47 | def this(n : Int, st : State, c : Set[Item]) = this(n,null,false,st,c);
48 |
49 | override def hashCode() : Int = {
50 | if (nonterminal == null) c.hashCode();
51 | else nonterminal.hashCode() + atStart.hashCode() + c.hashCode();
52 | }
53 | override def equals(a : Any) : Boolean = {
54 | a match {
55 | case o : LeftCornerState =>
56 | (nonterminal == o.nonterminal &&
57 | atStart == o.atStart &&
58 | core.equals(o.core))
59 | case _ => false
60 | }
61 | }
62 |
63 | override def appendHeader(sb : StringBuilder) : Unit = {
64 | sb append "state ";
65 | sb append number
66 | sb append " ( based on state "
67 | sb append state.number
68 | sb append " )\n\n"
69 | if (nonterminal != null) {
70 | sb append " _: \u22a2 ";
71 | if (atStart) { sb append ". "; }
72 | sb append nonterminal.name
73 | if (!atStart) { sb append " ."; }
74 | sb append "\n";
75 | }
76 | }
77 |
78 | override protected def complete() : Set[Item] = {
79 | /*
80 | println("Completing LC state " + number + ":");
81 | if (nonterminal != null) {
82 | println(" _: |- . " + nonterminal.name);
83 | }
84 | for (item <- core) {
85 | println(" " + item);
86 | }
87 | println();
88 | */
89 | var completion : HashSet[Item] = new HashSet;
90 | completion ++= core;
91 | var addedNT : ListSet[Nonterminal] = ListSet.empty;
92 | if (nonterminal != null && atStart) {
93 | // force the fake rule:
94 | addedNT += nonterminal;
95 | for (rule <- nonterminal.rules) {
96 | val nitem : Item = new Item(rule,0);
97 | // println("Adding implicit item " + nitem);
98 | completion += nitem;
99 | }
100 | }
101 | var added : List[Item] = Nil ++ completion;
102 | while (added.length > 0) {
103 | val temp : List[Item] = added;
104 | added = Nil
105 | for (item <- temp) {
106 | if (!item.ready) {
107 | // not yet reached recognition point
108 | item.symbol match {
109 | case nt:Nonterminal =>
110 | if (!(addedNT contains nt)) {
111 | addedNT += nt;
112 | for (rule <- nt.rules) {
113 | val nitem : Item = new Item(rule,0);
114 | // println("Adding item " + nitem);
115 | completion += nitem;
116 | added ::= nitem;
117 | }
118 | }
119 | case _ => ()
120 | }
121 | }
122 | }
123 | }
124 | completion
125 | }
126 |
127 | private var inited : Boolean = false;
128 |
129 | def init(first : First, lcfollow : LeftCornerFollow,
130 | states : HashSet[LeftCornerState]) : Unit = {
131 | if (inited) return;
132 | inited = true;
133 | val ignored = completion;
134 | //println("Initializing " + this.toString(true));
135 |
136 | val gotoItems = new HashMap[Symbol,ListSet[Item]]();
137 | val recogActions : HashMap[Terminal,Rule] = new HashMap[Terminal,Rule];
138 |
139 | // force the artificial state transition
140 | if (nonterminal != null && atStart) {
141 | gotoItems.put(nonterminal,ListSet.empty);
142 | }
143 | for (item <- completion) {
144 | if (item.ready) {
145 | for (t <- first(item).set) {
146 | recogActions.put(t,item.rule);
147 | }
148 | } else {
149 | gotoItems.get(item.symbol) match {
150 | case None => gotoItems.put(item.symbol,ListSet.empty + item.next());
151 | case Some(s) => gotoItems.put(item.symbol,s + item.next());
152 | }
153 | }
154 | }
155 |
156 | for ((token,action) <- state.actions) {
157 | action match {
158 | case ReduceAction(r) => {
159 | if (completion contains new Item(r,r.length)) {
160 | if (r.recognitionPoint != r.length) {
161 | throw new GrammarSpecificationError("assertion error: " + r);
162 | }
163 | putAction(token,AnnounceAction(r));
164 | } else {
165 | val rule : Rule = getAnnouncedRule(r.lhs);
166 | if (rule != null)
167 | putAction(token,AnnounceAction(rule));
168 | }
169 | }
170 | case ShiftAction(state) => {
171 | // only if this shift is relevant, do we use it
172 | if (gotoItems isDefinedAt token) {
173 | val newState = makeState(first,lcfollow,states,state,gotoItems(token));
174 | putAction(token,new ShiftAction(newState));
175 | } else {
176 | val rule : Rule = getAnnouncedRule(token);
177 |
178 | // println("On token " + token + ", action is " + action + ", rule = " + rule);
179 | if (rule != null) {
180 | putAction(token,AnnounceAction(rule));
181 | } else if (nonterminal != null && !atStart) {
182 | putAction(token,AcceptNTAction(nonterminal));
183 | }
184 | }
185 | }
186 | case ErrorAction(s) => {
187 | putAction(token,action)
188 | }
189 | }
190 | }
191 | state.default match {
192 | case null => { }
193 | case ReduceAction(r) => {
194 | if (completion contains new Item(r,r.length)) {
195 | if (r.recognitionPoint != r.length) {
196 | throw new GrammarSpecificationError("assertion error: " + r);
197 | }
198 | default = AnnounceAction(r);
199 | } else {
200 | val rule : Rule = getAnnouncedRule(r.lhs);
201 | if (rule != null)
202 | default = AnnounceAction(rule);
203 | }
204 | }
205 | }
206 |
207 | if (nonterminal != null && atStart) {
208 | var special : Action = null;
209 | for (rule <- nonterminal.rules) {
210 | if (first(rule).incEpsilon) {
211 | if (special == null)
212 | special = AnnounceAction(rule);
213 | else
214 | println("Warning: announce conflict in state " + number);
215 | }
216 | }
217 | if (special != null) {
218 | //println("Generated announce action " + special);
219 | val sp = special;
220 | for (token <- lcfollow(nonterminal)) {
221 | actions.get(token) match {
222 | case Some(`sp`) =>
223 | // everything is fine
224 | case Some(_) =>
225 | println("Warning: announce conflict in state " + number + " on "
226 | + token)
227 | case None =>
228 | putAction(token,special)
229 | }
230 | }
231 | }
232 | }
233 |
234 | if (nonterminal != null && !atStart) {
235 | val special = AcceptNTAction(nonterminal)
236 | for (token <- lcfollow(nonterminal)) {
237 | actions.get(token) match {
238 | case Some(AcceptNTAction(`nonterminal`)) =>
239 | // everything is fine
240 | case Some(x) =>
241 | println("Warning: accept conflict in state " + number + " on "
242 | + token + ", conflicts with " + x)
243 | case None =>
244 | putAction(token,special)
245 | }
246 | }
247 | }
248 |
249 | for ((nt,state) <- state.gotos) {
250 | if (gotoItems isDefinedAt nt) {
251 | var next : LeftCornerState = null;
252 | if (nonterminal == nt && atStart) {
253 | next = cacheState(first,lcfollow,states,
254 | new LeftCornerState(states.size,
255 | nonterminal,false,state,
256 | gotoItems(nt)));
257 | } else {
258 | next = makeState(first,lcfollow,states,state,gotoItems(nt));
259 | }
260 | putGoto(nt,next);
261 | }
262 | }
263 | }
264 |
265 | private var announcedRule : HashMap[Symbol,Rule] = new HashMap[Symbol,Rule];
266 | // private var debuglevel : Int = 0;
267 |
268 | protected def getAnnouncedRule(sym : Symbol) : Rule = {
269 | /*if (debuglevel == 0) {
270 | print("st. " + debuglevel);
271 | }
272 | print("\t");
273 | for (i <- 0 upto debuglevel) {
274 | print(" ");
275 | }
276 | print("announced(" + sym + ") = ");*/
277 | announcedRule.get(sym) match {
278 | case Some(r) => return r;
279 | case None => announcedRule.put(sym,null);
280 | }
281 | for (item <- completion) {
282 | if (item.symbol == sym) {
283 | if (item.ready) {
284 | //println("inferred ready rule for " + sym + " is " + item.rule);
285 | announcedRule.put(sym,item.rule);
286 | return item.rule;
287 | }
288 | }
289 | }
290 | //println("no ready rules");
291 | var rule : Rule = null;
292 | for (item <- state.completion) {
293 | if (item.index == 0 && item.symbol == sym) {
294 | //println("Found extra rule that can handle " + sym + ": " + item);
295 | val xrule : Rule = getAnnouncedRule(item.rule.lhs);
296 | if (rule == null)
297 | rule = xrule;
298 | else if (xrule != null && xrule != rule)
299 | throw new AssertionError("different: " + rule + " != " + xrule +
300 | " for " + sym + " in " + this.toString(true));
301 | }
302 | }
303 | announcedRule.put(sym,rule);
304 | rule
305 | }
306 |
307 | protected def makeState(first : First, lcfollow : LeftCornerFollow,
308 | states : HashSet[LeftCornerState],
309 | state : State,
310 | newcore : Set[Item])
311 | : LeftCornerState = {
312 | cacheState(first,lcfollow,
313 | states,new LeftCornerState(states.size,state,newcore));
314 | }
315 |
316 | protected def cacheState(first : First, lcfollow : LeftCornerFollow,
317 | states : HashSet[LeftCornerState],
318 | newState : LeftCornerState) : LeftCornerState = {
319 | states.find(_ == newState) match {
320 | case Some(s) => s;
321 | case None => {
322 | states += newState;
323 | newState.init(first,lcfollow,states);
324 | newState
325 | }
326 | }
327 | }
328 | }
329 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/LeftCornerTable.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.mutable.HashSet;
20 |
21 | import scala.collection.Set;
22 | import scala.collection.mutable.{HashMap,ArrayBuffer};
23 | import scala.io.Source;
24 |
25 | /**
26 | * LeftCorner parser tables built from LALR(1) Parse tables
27 | */
28 | class LeftCornerTable(val table : Table) {
29 | protected val _states : HashSet[LeftCornerState] = new HashSet;
30 | def states : Set[LeftCornerState] = _states;
31 | private var _startState : LeftCornerState = null;
32 | def startState : LeftCornerState = _startState;
33 |
34 | val NTstate : HashMap[Nonterminal,LeftCornerState] = new HashMap;
35 |
36 | def grammar : Grammar = table.grammar;
37 |
38 | override def toString : String = toString(true);
39 |
40 | def toString(showAll : Boolean) : String = {
41 | val sb : StringBuilder = new StringBuilder();
42 | val a : Array[LeftCornerState] = new Array(states.size);
43 | for (state <- states) {
44 | a(state.number) = state;
45 | }
46 | for (state <- a) {
47 | sb append (state.toString(showAll))
48 | }
49 | sb.toString
50 | }
51 |
52 | val first : First = new First(grammar);
53 | val follow : Follow = new Follow(grammar,first);
54 |
55 | {
56 | table.setRecognitionPoints();
57 | }
58 |
59 | val lcfollow : LeftCornerFollow = new LeftCornerFollow(grammar,first,follow);
60 | // compute the states:
61 | {
62 | // get the start state
63 | _startState = new LeftCornerState(0,grammar.start,table.states(0));
64 | _states += startState;
65 | startState.init(first,lcfollow,_states);
66 | NTstate.put(grammar.start,startState);
67 | // for all rules, make sure we have NT states:
68 | for (rule <- grammar.rules) {
69 | var n : Int = rule.recognitionPoint; // NB: n is changed in loop
70 | for (symbol <- rule.rhs.drop(n)) {
71 | symbol match {
72 | case _:ArtificialNonterminal => ()
73 | case nt:Nonterminal => {
74 | if (!(NTstate isDefinedAt nt)) {
75 | NTstate.put(nt,makeNTstate(nt,new Item(rule,n)));
76 | }
77 | }
78 | case _ => ()
79 | }
80 | n += 1;
81 | }
82 | }
83 | for (symbol <- grammar.all_symbols) {
84 | symbol match {
85 | case _:ArtificialNonterminal => ()
86 | case nt:Nonterminal => {
87 | if (Options.verbose > 1 && !(NTstate isDefinedAt nt)) {
88 | println("Warning: Nonterminal " + nt.name +
89 | " never used in unambiguous context.");
90 | }
91 | }
92 | case _ => ()
93 | }
94 | }
95 | }
96 |
97 | protected def makeNTstate(nt : Nonterminal, item : Item) : LeftCornerState = {
98 | // println("Building NT state for " + nt.name);
99 | for (state <- table.states) {
100 | if (state.completion contains item) {
101 | // println("Found state " + state.number + " to include " + item);
102 | val newState : LeftCornerState =
103 | new LeftCornerState(_states.size,nt,state);
104 | _states += (newState);
105 | newState.init(first,lcfollow,_states);
106 | return newState;
107 | }
108 | }
109 | throw new GrammarSpecificationError("No state found for item " + item);
110 | }
111 | }
112 |
113 | object LeftCornerTable {
114 | def main(args : Array[String]) = {
115 | for (s <- args) {
116 | val scanner : BisonScanner = new BisonScanner(Source.fromFile(s+".y"))
117 | val parser : BisonParser = new BisonParser();
118 | parser.yydebug = true;
119 | parser.reset(s+".y",scanner);
120 | if (parser.yyparse()) {
121 | println(parser.result);
122 | val table : BisonTable = new BisonTable(parser.result);
123 | table.fromFile(s+".output");
124 | val table2 : LeftCornerTable = new LeftCornerTable(table);
125 | println(table2);
126 | }
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/LeftPrecedence.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | class LeftPrecedence(l : Int) extends Precedence(l) {}
20 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/LiteralCode.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class LiteralCode(s : String) extends Code {
20 | override def toString : String = s;
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/NoCode.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class NoCode() extends Code {
20 | override def toString : String = ""
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/NonAssocPrecedence.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | class NonAssocPrecedence(l : Int) extends Precedence(l) {}
20 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Nonterminal.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.Set;
20 | import scala.collection.immutable.ListSet;
21 | import scala.collection.mutable.{ArrayBuffer,HashSet};
22 |
23 | class Nonterminal(s : String, t : String) extends Symbol(s,t) {
24 | val rules : ArrayBuffer[Rule] = new ArrayBuffer();
25 |
26 | def addRule(r : Rule) : Unit = rules += r;
27 | }
28 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Options.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | object Options {
20 | var verbose : Int = 0;
21 | var debug : Boolean = false;
22 | var meta_debug : Boolean = false;
23 | var gen_lalr_table : Boolean = false;
24 | }
25 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Precedence.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | abstract class Precedence(val level : Int) {}
20 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/ReduceAction.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class ReduceAction(val rule : Rule) extends Action {
20 | override def toString = "reduce using rule " + rule
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/RightPrecedence.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | class RightPrecedence(l : Int) extends Precedence(l) {}
20 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Rule.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.Set;
20 |
21 | class Rule(val number : Int, val lhs : Nonterminal, val rhs : List[Symbol],
22 | val precedence : Precedence, val action : Code)
23 | {
24 | {
25 | lhs.addRule(this);
26 | }
27 |
28 | def this(number : Int, lhs:Nonterminal, rhs:List[Symbol],
29 | precedence : Precedence, action:Code,
30 | ignored : Boolean) = this(number,lhs,rhs.reverse,precedence,action);
31 |
32 | def length : Int = rhs.length;
33 |
34 | var recognitionPoint : Int = rhs.length;
35 |
36 | def getRecognitionPoint() = recognitionPoint;
37 |
38 | def setRecognitionPoint(nonfree : Set[Item]) : Unit = {
39 | recognitionPoint = 0; // optimistic
40 | for (i <- 0 until length) {
41 | if (precedence != null || // precedence forces using LALR parsing
42 | (nonfree contains new Item(this,i)) ||
43 | (rhs(i) == ErrorNonterminal())) {
44 | recognitionPoint = i+1; // oops! must be later than we hoped!
45 | }
46 | }
47 | // println("Recognition Point is " + new Item(this,recognitionPoint));
48 | }
49 |
50 | override def toString = {
51 | val sb : StringBuffer = new StringBuffer(lhs.name);
52 | sb.append(':');
53 | if (rhs.isEmpty) sb.append(" /* empty */");
54 | else {
55 | for (sym <- rhs) {
56 | sb.append(' ');
57 | sb.append(sym.name);
58 | }
59 | }
60 | sb.toString
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/ShiftAction.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class ShiftAction(target : State) extends Action {
20 | override def toString = "shift, and go to " + (target.number)
21 | }
22 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/State.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.mutable.Map
20 | import scala.collection.Set
21 | import scala.collection.immutable.ListSet
22 | import scala.collection.mutable.HashMap
23 | import scala.collection.mutable.HashSet
24 | import scala.collection.mutable.ArrayBuffer
25 | import edu.uwm.cs.util.Dominator
26 | import edu.uwm.cs.util.Reach
27 |
28 |
29 | class State(val number : Int, val core : Set[Item]) {
30 | // Scala 2.7 dosn't permit super.x any more for some unspecified reason,
31 | // so I have to fake the getter as a def.
32 | private val _actions : Map[Terminal,Action] = new HashMap();
33 | def actions : scala.collection.Map[Terminal,Action] = _actions;
34 | def putAction(t : Terminal, a : Action) = _actions.put(t,a);
35 |
36 | private val _gotos : Map[Nonterminal,State] = new HashMap();
37 | def gotos : scala.collection.Map[Nonterminal,State] = _gotos;
38 | def putGoto(n : Nonterminal, s : State) = _gotos.put(n,s);
39 |
40 | private var _default : Action = null;
41 | def default : Action = _default;
42 | def default_=(a : Action) : Unit = {
43 | _default = a;
44 | }
45 |
46 | override def equals(a : Any) : Boolean = {
47 | a match {
48 | case o:State => core.equals(o.core);
49 | case _ => false
50 | }
51 | }
52 |
53 | override def hashCode() : Int = core.hashCode();
54 |
55 | private var cachedCompletion : Set[Item] = null;
56 | def completion : Set[Item] = {
57 | if (cachedCompletion == null) {
58 | cachedCompletion = complete();
59 | }
60 | cachedCompletion
61 | }
62 |
63 | protected def complete() : Set[Item] = {
64 | /*
65 | println("Completing state " + number + ":");
66 | for (item <- core) {
67 | println(" " + item);
68 | }
69 | println();
70 | */
71 | var completion : HashSet[Item] = new HashSet;
72 | completion ++= core;
73 | var addedNT : ListSet[Nonterminal] = ListSet.empty;
74 | var added : List[Item] = Nil ++ completion;
75 | while (added.length > 0) {
76 | val temp : List[Item] = added;
77 | added = Nil
78 | for (item <- temp) {
79 | item.symbol match {
80 | case nt:Nonterminal =>
81 | if (!(addedNT contains nt)) {
82 | addedNT += nt;
83 | for (rule <- nt.rules) {
84 | val nitem : Item = new Item(rule,0);
85 | // println("Adding item " + nitem);
86 | completion += nitem;
87 | added ::= nitem;
88 | }
89 | }
90 | case _ => ()
91 | }
92 | }
93 | }
94 | completion
95 | }
96 |
97 | def addNonFree(nonfree : scala.collection.mutable.Set[Item]) : Unit = {
98 | // create a graph
99 | // 1. first the nodes
100 | val actionset : HashSet[Action] = new HashSet();
101 | val nodes : ArrayBuffer[Any] = new ArrayBuffer();
102 | val index : Map[Any,Int] = new HashMap();
103 | nodes += (null);
104 | nodes += (null);
105 | for (item <- completion) {
106 | val n : Int = nodes.size;
107 | nodes += (item);
108 | index.put(item,n);
109 | }
110 | val firstAction : Int = nodes.size;
111 | for ((_,action) <- actions) {
112 | actionset += action;
113 | }
114 | if (default != null) actionset += default;
115 | for (action <- actionset) {
116 | val n : Int = nodes.size;
117 | nodes += (action);
118 | index.put(action,n);
119 | }
120 | // 2. then the successor relation
121 | val succ : PartialFunction[Int,scala.collection.Set[Int]] = {
122 | i:Int => i match {
123 | case 1 => {
124 | var s : ListSet[Int] = ListSet.empty;
125 | for (item <- core) {
126 | s = s + index(item)
127 | }
128 | s
129 | }
130 | case _ =>
131 | nodes(i) match {
132 | case _:Action => ListSet.empty
133 | case item:Item => {
134 | item.symbol match {
135 | case t:Terminal => {
136 | actions.get(t) match {
137 | case Some(a:ShiftAction) => ListSet.empty + index(a);
138 | case Some(a:ErrorAction) => ListSet.empty + index(a);
139 | case _ => ListSet.empty
140 | }
141 | }
142 | case nt:Nonterminal => {
143 | var s : ListSet[Int] = ListSet.empty;
144 | for (rule <- nt.rules) {
145 | s = s + index(new Item(rule,0));
146 | }
147 | s
148 | }
149 | case null => {
150 | val red : ReduceAction = ReduceAction(item.rule);
151 | if (actionset contains red)
152 | ListSet.empty + index(red)
153 | else if (_default == AcceptAction())
154 | ListSet.empty + index(AcceptAction())
155 | else
156 | ListSet.empty
157 | }
158 | }
159 | }
160 | }
161 | }
162 | };
163 | if (Options.meta_debug) {
164 | println("Graph of state (for computing free positions)");
165 | for (i <- 1 until nodes.size) {
166 | print(" " + i + ": ");
167 | nodes(i) match {
168 | case null => println("[INIT]")
169 | case x => println(x);
170 | }
171 | print(" ->");
172 | for (j <- succ(i)) {
173 | print(" " + j);
174 | }
175 | println();
176 | }
177 | }
178 | // 3. now compute reachability and domination:
179 | val reach : Reach = new Reach(nodes.size-1,succ);
180 | val dominator : Dominator = new Dominator(nodes.size-1,succ,1);
181 | // 4. now for every item, check that it dosn't reach itself:
182 | for (item <- completion) {
183 | val i : Int = index(item);
184 | if (reach(i) contains i) {
185 | if (Options.verbose > 1) {
186 | println("Item is forbidden: " + item);
187 | }
188 | nonfree += item;
189 | }
190 | }
191 | // 5. check that every item dominates every action it can reach:
192 | for (item <- completion) {
193 | val i : Int = index(item);
194 | for (action <- actionset) {
195 | val a : Int = index(action);
196 | if ((reach(i) contains a) && !dominator.dominates(i,a)) {
197 | if (Options.verbose > 1) {
198 | println("Item is dependent: " + item);
199 | }
200 | nonfree += item;
201 | }
202 | }
203 | }
204 | }
205 |
206 | def longestItem : Item = {
207 | var longest : Item = null;
208 | for (item <- core) {
209 | if (longest == null || item.index > longest.index) {
210 | longest = item;
211 | }
212 | }
213 | longest
214 | }
215 |
216 | /** A rough-and-ready way to say the state doesn't need
217 | * to be implemented in a Left-corner parser. Even
218 | * if it is not past recognition, it may still be useless,
219 | * but it's harder to detect.
220 | */
221 | def pastRecognition : Boolean = {
222 | for (item <- core) {
223 | if (item.index > item.rule.recognitionPoint) return true;
224 | }
225 | return false;
226 | }
227 |
228 | protected def appendHeader(sb : StringBuilder) : Unit = {
229 | sb append "state ";
230 | sb append number
231 | sb append '\n'
232 | sb append '\n'
233 | }
234 |
235 | override def toString : String = toString(true);
236 |
237 | def toString(showAll : Boolean) : String = {
238 | val sb : StringBuilder = new StringBuilder();
239 | appendHeader(sb)
240 | for (item <- (showAll match { case true => completion;
241 | case false => core})) {
242 | sb append " "
243 | sb append item
244 | sb append '\n'
245 | }
246 | sb append '\n'
247 | for ((token,action) <- actions) {
248 | sb append " "
249 | sb append (token.name)
250 | sb append '\t'
251 | sb append action
252 | sb append '\n'
253 | }
254 | if (default != null) {
255 | sb append " $default\t"
256 | sb append default
257 | sb append '\n'
258 | }
259 | sb append '\n'
260 | for ((nt,state) <- gotos) {
261 | sb append " "
262 | sb append (nt.name)
263 | sb append "\tgo to state "
264 | sb append (state.number)
265 | sb append '\n'
266 | }
267 | if (gotos.size > 0) {
268 | sb append '\n'
269 | }
270 | sb append '\n'
271 | sb.toString
272 | }
273 | }
274 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Symbol.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.Set;
20 |
21 | abstract class Symbol(val name : String, val resultType : String) {
22 | def getType() : String = if (typed) resultType else "Unit";
23 | def typed : Boolean = (!resultType.equals(""))
24 | var precedence : Precedence = null;
25 | def setPrecedence(p : Precedence) = {
26 | if (precedence == null) {
27 | precedence = p;
28 | } else {
29 | throw new GrammarSpecificationError("precedence for " + name + " already specified");
30 | }
31 | }
32 |
33 | override def toString = name;
34 | }
35 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Table.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.mutable.ArrayBuffer;
20 | import scala.collection.Set;
21 | import scala.collection.mutable.HashSet;
22 |
23 | /**
24 | * LALR(1) Parse tables
25 | */
26 | class Table(val grammar : Grammar) {
27 | val states : ArrayBuffer[State] = new ArrayBuffer;
28 |
29 | override def toString : String = toString(true);
30 |
31 | def toString(showAll : Boolean) : String = {
32 | val sb : StringBuffer = new StringBuffer();
33 | for (state <- states) {
34 | sb append (state.toString(showAll))
35 | }
36 | sb.toString
37 | }
38 |
39 | private var nonfree : HashSet[Item] = null;
40 |
41 | def getNonFree() : Set[Item] = {
42 | if (nonfree != null) return nonfree;
43 | nonfree = new HashSet;
44 | for (state <- states) {
45 | // println("Getting nonfree for " + state);
46 | state.addNonFree(nonfree);
47 | }
48 | nonfree
49 | }
50 |
51 | def setRecognitionPoints() : Unit = {
52 | val nonfree : Set[Item] = getNonFree();
53 | for (rule <- grammar.rules) {
54 | rule.setRecognitionPoint(nonfree);
55 | }
56 | }
57 |
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Terminal.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | import scala.collection.immutable.ListSet;
20 | import scala.collection.Set;
21 |
22 | class Terminal(s : String, t : String) extends Symbol(s,t) {
23 | }
24 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/VariableCode.scala:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2011 University of Wisconsin, Milwaukee
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package edu.uwm.cs.scalabison;
18 |
19 | case class VariableCode(i : Int) extends Code {
20 | override def toString : String = {
21 | if (i == -1) "yyresult";
22 | else "yyarg" + i;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/scalabison/Version.scala:
--------------------------------------------------------------------------------
1 | package edu.uwm.cs.scalabison;
2 |
3 | object Version {
4 | val version : String = "1.1";
5 | }
6 |
7 | // History:
8 | // 0.76: More debugging information on errors
9 | // 0.77: Catch ALL exceptions, not just in shifts
10 | // 0.78: Don't add any default actions.
11 | // 0.79: use simple name of file, defaultInitial not Integer
12 | // 0.791: don't try recovery when at EOF
13 | // 0.792: Bug introduced in 0.78: need to handle followset too
14 | // 0.793: Fixed announce conflicts & shadowing for accept actions
15 | // 0.794: Fixed bug (identifiers could not include digits)
16 | // 0.8: Updated for Scala 2.9.1, re-bootstrapped
17 | // 0.81: No longer generates "Unit" values for untyped nonterminals (caused warnings)
18 | // 0.82: More support for '\x' terminals, primitive type nonterminals
19 | // 0.83: added support for bison 2.6.2, re-bootstrapped
20 | // 0.84: Updated for Scala 2.10
21 | // 0.99: Updated for Scala 2.11 and Release candidate 1
22 | // 1.0: Handle conflicts in grammars
23 | // 1.1: Added back "-d" option from 2010 (used for CS 854 at UWM).
24 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/util/CharUtil.scala:
--------------------------------------------------------------------------------
1 | package edu.uwm.cs.util
2 |
3 | object CharUtil {
4 | def lit(ch : Char) : String = ch match {
5 | case '\'' => "'\\''";
6 | case '\n' => "'\\n'";
7 | case '\t' => "'\\t'";
8 | case '\f' => "'\\f'";
9 | case '\r' => "'\\r'";
10 | case '\b' => "'\\b'";
11 | case 0 => "'\\0'";
12 | case _ => {
13 | if (ch < 32 || ch > 126) String.format("'\\u%04x'",new java.lang.Integer(ch)) else "'" + ch + "'";
14 | }
15 | }
16 |
17 | def main(args : Array[String]) = { println ("lit('\u00fc') = "+lit('\u00fc')); }
18 | }
--------------------------------------------------------------------------------
/src/edu/uwm/cs/util/Cycle.scala:
--------------------------------------------------------------------------------
1 | /* Determining which nodes are in cycles in a graph.
2 | * John Boyland
3 | * This file may be used, copied and/or modified for any purpose.
4 | */
5 | package edu.uwm.cs.util;
6 |
7 | import scala.collection.immutable.Set;
8 | import scala.collection.immutable.ListSet;
9 | import scala.collection.mutable.BitSet;
10 |
11 | /**
12 | * Cycle computation of graph represented by vertices 1..max
13 | * (Not 0 .. (max-1) !). The result returns whether the given node
14 | * is involved in a cycle.
15 | */
16 | class Cycle(max : Int, val succ : PartialFunction[Int,Set[Int]])
17 | extends PartialFunction[Int,Boolean]
18 | {
19 | private val reachable : Array[BitSet] = new Array(max+1);
20 |
21 | {
22 | for (i <- 1 to max) {
23 | reachable(i) = new BitSet(max+1);
24 | for (j <- succ(i)) {
25 | reachable(i) += j
26 | if (j < i) reachable(i) ++= reachable(j);
27 | }
28 | }
29 | var done : Boolean = false;
30 | while (!done) {
31 | done = true;
32 | for (i <- 1 to max) {
33 | val is : BitSet = reachable(i);
34 | for (j <- is.clone) {
35 | val js : BitSet = reachable(j);
36 | if (!(js subsetOf is)) {
37 | is ++= js;
38 | done = false;
39 | }
40 | }
41 | }
42 | }
43 | }
44 |
45 | override def isDefinedAt(n : Int) = n >= 1 && n <= max;
46 |
47 | override def apply(n : Int) = reachable(n) contains n;
48 | }
49 |
50 | object TestCycle extends App {
51 | val e : Set[Int] = ListSet.empty;
52 | val c : Cycle =
53 | new Cycle(13, { i => i match {
54 | case 13 => e + 1 + 2 + 3 + 13 // The +13 is new to this test
55 | case 1 => e + 4
56 | case 2 => e + 4 + 1 + 5
57 | case 3 => e + 7+6
58 | case 4 => e + 12
59 | case 5 => e + 8
60 | case 6 => e + 9
61 | case 7 => e + 9+10
62 | case 8 => e + 5+11
63 | case 9 => e + 11
64 | case 10 => e + 9
65 | case 11 => e + 9 // formerly + 13
66 | case 12 => e + 8
67 | }});
68 |
69 | def name(i:Int) : String = {
70 | if (i == 0) "
";
71 | else ((i - 1 + 'A').toChar).toString();
72 | }
73 |
74 | {
75 | for (i <- 1 to 13) {
76 | if (c(i)) println(name(i) + " is cyclic");
77 | }
78 | }
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/util/Dominator.scala:
--------------------------------------------------------------------------------
1 | /* Dominator computation from Langauer and Tarjan (TOPLAS 1:1)
2 | * John Boyland
3 | * This file may be used, copied and/or modified for any purpose.
4 | */
5 | package edu.uwm.cs.util;
6 |
7 | import scala.collection.Set;
8 | import scala.collection.immutable.ListSet;
9 |
10 | /**
11 | * Dominator computation of graph represented by vertices 1..max
12 | * (Not 0 .. (max-1) !). The result returns the immediate dominator of any
13 | * node or 0 for a node without any dominator.
14 | */
15 | class Dominator(max : Int, val succ : PartialFunction[Int,Set[Int]], root : Int)
16 | extends PartialFunction[Int,Int] {
17 | private val parent : Array[Int] = new Array(max+1);
18 | private val ancestor : Array[Int] = new Array(max+1);
19 | private val child : Array[Int] = new Array(max+1);
20 | private val vertex : Array[Int] = new Array(max+1);
21 | private val label : Array[Int] = new Array(max+1);
22 | private val semi : Array[Int] = new Array(max+1);
23 | private val size : Array[Int] = new Array(max+1);
24 | private val dom : Array[Int] = new Array(max+1);
25 |
26 | private val pred : Array[ListSet[Int]] = new Array(max+1);
27 | private val bucket : Array[ListSet[Int]] = new Array(max+1);
28 |
29 | var n : Int = 0; // NB: In paper, n is also used for "max"
30 |
31 | private def dfs(v : Int) : Unit = {
32 | n += 1;
33 | semi(v) = n;
34 | label(v) = v;
35 | vertex(n) = v;
36 | ancestor(v) = 0;
37 | child(v) = 0;
38 | size(v) = 1;
39 | for (w <- succ(v)) {
40 | if (semi(w) == 0) {
41 | parent(w) = v; dfs(w)
42 | }
43 | pred(w) += v;
44 | }
45 | }
46 |
47 | private def compress(v : Int) : Unit = {
48 | if (ancestor(ancestor(v)) != 0) {
49 | compress(ancestor(v));
50 | if (semi(label(ancestor(v))) < semi(label(v))) {
51 | label(v) = label(ancestor(v));
52 | }
53 | ancestor(v) = ancestor(ancestor(v));
54 | }
55 | }
56 |
57 | private def evalX(v : Int) : Int = {
58 | if (ancestor(v) == 0) {
59 | v;
60 | } else {
61 | compress(v);
62 | label(v);
63 | }
64 | }
65 |
66 | private def eval(v : Int) : Int = {
67 | if (ancestor(v) == 0) {
68 | label(v)
69 | } else {
70 | compress(v);
71 | if (semi(label(ancestor(v))) >= semi(label(v))) {
72 | label(v)
73 | } else {
74 | label(ancestor(v));
75 | }
76 | }
77 | }
78 |
79 | private def linkX(v : Int, w : Int) = {
80 | ancestor(w) = v;
81 | }
82 |
83 | private def link(v : Int, w : Int) = {
84 | var s : Int = w;
85 | while (semi(label(w)) < semi(label(child(s)))) {
86 | if (size(s) + size(child(child(s))) >= 2 * size(child(s))) {
87 | ancestor(child(s)) = s;
88 | child(s) = child(child(s));
89 | } else {
90 | size(child(s)) = size(s);
91 | ancestor(s) = child(s);
92 | s = ancestor(s);
93 | }
94 | }
95 | label(s) = label(w);
96 | size(v) = size(v) + size(w);
97 | if (size(v) < 2 * size(w)) {
98 | val tmp = child(v);
99 | child(v) = s;
100 | s = tmp;
101 | }
102 | while (s != 0) {
103 | ancestor(s) = v;
104 | s = child(s)
105 | }
106 | }
107 |
108 | // Step 1:
109 | {
110 | for (v <- 1 to max) {
111 | pred(v) = ListSet.empty;
112 | bucket(v) = ListSet.empty;
113 | semi(v) = 0;
114 | }
115 | n = 0;
116 | dfs(root);
117 | if (n != max) {
118 | throw new Exception("Assertion failed");
119 | }
120 | size(0) = 0;
121 | label(0) = 0;
122 | semi(0) = 0;
123 | for (i <- n to 2 by -1) { // NB: vertex(1) = root always
124 | val w : Int = vertex(i);
125 |
126 | // step 2
127 | for (v <- pred(w)) {
128 | val u : Int = eval(v);
129 | if (semi(u) < semi(w)) {
130 | semi(w) = semi(u);
131 | }
132 | }
133 | bucket(vertex(semi(w))) += w;
134 | link(parent(w),w)
135 |
136 | // step 3
137 | val bucketcopy : Set[Int] = bucket(parent(w));
138 | bucket(parent(w)) = ListSet.empty;
139 | for (v <- bucketcopy) {
140 | val u : Int = eval(v);
141 | dom(v) = {
142 | if (semi(u) < semi(v)) u else parent(w)
143 | }
144 | }
145 | }
146 |
147 | // step 4
148 | for (i <- 2 to n) {
149 | val w : Int = vertex(i);
150 | if (dom(w) != vertex(semi(w))) {
151 | dom(w) = dom(dom(w))
152 | }
153 | }
154 | dom(root) = 0;
155 | }
156 |
157 | override def isDefinedAt(n : Int) = n >= 1 && n <= max;
158 |
159 | override def apply(n : Int) = dom(n);
160 |
161 | def dominates(i : Int, j : Int) : Boolean = {
162 | j != 0 && (i == j || dominates(i,apply(j)))
163 | }
164 | }
165 |
166 | object TestDominator extends App {
167 | val e : ListSet[Int] = ListSet.empty;
168 | val d : Dominator =
169 | new Dominator(13, { i => i match {
170 | case 13 => e + 1 + 2 + 3
171 | case 1 => e + 4
172 | case 2 => e + 4 + 1 + 5
173 | case 3 => e + 7+6
174 | case 4 => e + 12
175 | case 5 => e + 8
176 | case 6 => e + 9
177 | case 7 => e + 9+10
178 | case 8 => e + 5+11
179 | case 9 => e + 11
180 | case 10 => e + 9
181 | case 11 => e + 9+13
182 | case 12 => e + 8
183 | }}, 13);
184 |
185 | def name(i:Int) : String = {
186 | if (i == 0) "";
187 | else ((i - 1 + 'A').toChar).toString();
188 | }
189 |
190 | {
191 | for (i <- 1 to 13) {
192 | println(name(i) + " is dominated by " + name(d(i)));
193 | }
194 | }
195 | }
196 |
197 |
--------------------------------------------------------------------------------
/src/edu/uwm/cs/util/Reach.scala:
--------------------------------------------------------------------------------
1 | /* Reachability computation of nodes in a graph.
2 | * John Boyland
3 | * This file may be used, copied and/or modified for any purpose.
4 | */
5 | package edu.uwm.cs.util;
6 |
7 | import scala.collection.Set;
8 | import scala.collection.immutable.ListSet;
9 | import scala.collection.mutable.BitSet;
10 |
11 | /**
12 | * Reaching computation of graph represented by vertices 1..max
13 | * (Not 0 .. (max-1) !). The result returns all nodes reachable
14 | * from the given node.
15 | */
16 | class Reach(max : Int, val succ : PartialFunction[Int,Set[Int]])
17 | extends PartialFunction[Int,Set[Int]]
18 | {
19 | private val reachable : Array[BitSet] = new Array(max+1);
20 |
21 | {
22 | for (i <- 1 to max) {
23 | reachable(i) = new BitSet(max+1);
24 | for (j <- succ(i)) {
25 | reachable(i) += j
26 | if (j < i) reachable(i) ++= reachable(j);
27 | }
28 | }
29 | var done : Boolean = false;
30 | while (!done) {
31 | done = true;
32 | for (i <- 1 to max) {
33 | val is : BitSet = reachable(i);
34 | for (j <- is.clone) {
35 | val js : BitSet = reachable(j);
36 | if (!(js subsetOf is)) {
37 | is ++= js;
38 | done = false;
39 | }
40 | }
41 | }
42 | }
43 | }
44 |
45 | override def isDefinedAt(n : Int) = n >= 1 && n <= max;
46 |
47 | override def apply(n : Int) = reachable(n);
48 | }
49 |
50 | object TestReach extends App {
51 | val e : ListSet[Int] = ListSet.empty;
52 | val c : Reach =
53 | new Reach(13, { i => i match {
54 | case 13 => e + 1 + 2 + 3 + 13 // The +13 is new to this test
55 | case 1 => e + 4
56 | case 2 => e + 4 + 1 + 5
57 | case 3 => e + 7+6
58 | case 4 => e + 12
59 | case 5 => e + 8
60 | case 6 => e + 9
61 | case 7 => e + 9+10
62 | case 8 => e + 5+11
63 | case 9 => e + 11
64 | case 10 => e + 9
65 | case 11 => e + 9 // formerly + 13
66 | case 12 => e + 8
67 | }});
68 |
69 | def name(i:Int) : String = {
70 | if (i == 0) "";
71 | else ((i - 1 + 'A').toChar).toString();
72 | }
73 |
74 | {
75 | for (i <- 1 to 13) {
76 | print(name(i) + " reaches");
77 | for (j <- c(i)) {
78 | print(" "+name(j));
79 | }
80 | println();
81 | }
82 | }
83 | }
84 |
85 |
--------------------------------------------------------------------------------