WirthのCompiler Constructionを読んでOberon-0のパーサを作ることにしました。セマンティックは無しです。
grammarファイルはEBNFを正規表現で書き換えて、以下のようになりました。ちなみにスタートはmoduleからです。
grammar oberon0;
ident : ID;
integer : INT;
selector: (('.' ident|'[' expression ']') )*;
factor : ident selector | integer |'('expression')' |'~' factor;
term : factor(('*'|'DIV'|'MOD'|'&') factor)*;
simpleexpression
: ('+'|'-')? term (('+'|'-'|'OR') term)*;
expression
: simpleexpression (('='|'#'|'<'|'<='|'>'|'>=') simpleexpression)?;
assignment
: ident selector ':=' expression;
actualparameters
: '('(expression(',' expression)*)?')';
procedurecall
: ident(actualparameters)?;
ifstatement
: 'IF' expression 'THEN' statementsequence
('ELSIF' expression 'THEN' statementsequence)*
('ELSE' statementsequence)? 'END';
whilestatement
: 'WHILE' expression 'DO' statementsequence 'END';
statement
: (assignment|procedurecall|ifstatement|whilestatement)?;
statementsequence
: statement(';' statement)*;
identlist
: ident(',' ident)*;
arraytype
: 'ARRAY' expression 'OF' type;
fieldlist
: (identlist ':'type)?;
recordtype
: 'RECORD' fieldlist (';' fieldlist)* 'END';
type : ident | arraytype | recordtype;
fpsection
: ('VAR')? identlist ':' type;
formalparameters
: '(' (fpsection (';' fpsection)*)? ')';
procedureheading
: 'PROCEDURE' ident(formalparameters)?;
procedurebody
: declarations ('BEGIN' statementsequence)? 'END';
proceduredeclaration
: procedureheading ';' procedurebody ident;
declarations
: ('CONST' (ident '=' expression ';')*)?
('TYPE' (ident '=' type ';')*)?
('VAR' (identlist ':' type ';')*)?
(proceduredeclaration ';')*;
module : 'MODULE' ident ';' declarations
('BEGIN' statementsequence)? 'END' ident '.';
ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
;
INT : '0'..'9'+
;
FLOAT
: ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
| '.' ('0'..'9')+ EXPONENT?
| ('0'..'9')+ EXPONENT
;
COMMENT
: '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
| '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
;
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
STRING
: '"' ( ESC_SEQ | ~('\\'|'"') )* '"'
;
CHAR: '\'' ( ESC_SEQ | ~('\''|'\\') ) '\''
;
fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
fragment
ESC_SEQ
: '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
| UNICODE_ESC
| OCTAL_ESC
;
fragment
OCTAL_ESC
: '\\' ('0'..'3') ('0'..'7') ('0'..'7')
| '\\' ('0'..'7') ('0'..'7')
| '\\' ('0'..'7')
;
fragment
UNICODE_ESC
: '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
;
MODULE Sample;
PROCEDURE Multiply;
VAR x,y,z: INTEGER;
BEGIN Read(x);Read(y);z:=0;
WHILE x > 0 DO
IF x MOD 2 = 1 THEN z := z + y END;
y :=2*y; x:=x DIV 2
END;
Write(x);Write(y);Write(z);WriteLn
END Multiply;
PROCEDURE Divide;
VAR x,y,r,q,w:INTEGER;
BEGIN Read(x);Read(y);r :=x;q:=0;w:=y;
WHILE w <=r DO w:=2*w END;
WHILE w > y DO
q:=2*q;w:=w DIV 2;
IF w <= r THEN r:=r-w;q:=q+1 END
END;
Write(x);Write(y);Write(q);Write(r);WriteLn
END Divide;
PROCEDURE BinSearch;
VAR i,j,k,n,x:INTEGER;
a: ARRAY 32 OF INTEGER;
BEGIN Read(n); k := 0;
WHILE k < n DO Read(a[k]);k:=k+1 END;
Read(x);i:=0;j:=n;
WHILE i < j DO
k := (i+j) DIV 2;
IF x < a[k] THEN j:=k ELSE i:=k+1 END
END;
Write(i);Write(j);Write(a[j]);WriteLn
END BinSearch;
END Sample.