Created
November 26, 2018 22:38
-
-
Save kleczkowski/52a3ee350317b545d8d6c7324e325790 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
grammar SimpleImperativeLanguage; | |
@lexer::header { | |
package com.github.repaj.glang; | |
} | |
@parser::header { | |
package com.github.repaj.glang; | |
import java.lang.*; | |
import com.github.repaj.glang.ir.*; | |
import com.github.repaj.glang.ir.symtab.*; | |
import com.github.repaj.glang.report.*; | |
} | |
@parser::members { | |
private SymbolTable table; | |
private ErrorLogger log; | |
} | |
program | |
returns [BasicBlock entry] | |
: 'DECLARE' decl* 'IN' stmts 'END' EOF | |
{ | |
$entry = $stmts.code; | |
$stmts.last.add(new Halt()); | |
} | |
; | |
stmts | |
returns [BasicBlock code, BasicBlock last] | |
locals [BasicBlock recent] | |
: hd=stmt | |
{ | |
$code = $hd.code; | |
$last = $hd.last; | |
} | |
(stmt | |
{ | |
$last.meld($stmt.code); | |
$last = $stmt.last; | |
} | |
)* | |
; | |
stmt | |
returns [BasicBlock code, BasicBlock last] | |
: assignStmt ';' | |
{ | |
$code = $assignStmt.code; | |
$last = $assignStmt.last; | |
} | |
| ifStmt | |
{ | |
$code = $ifStmt.code; | |
$last = $ifStmt.last; | |
} | |
| whileStmt | |
{ | |
$code = $whileStmt.code; | |
$last = $whileStmt.last; | |
} | |
| doWhileStmt | |
{ | |
$code = $doWhileStmt.code; | |
$last = $doWhileStmt.last; | |
} | |
| forStmt | |
{ | |
$code = $forStmt.code; | |
$last = $forStmt.last; | |
} | |
| readStmt ';' | |
{ | |
$code = $readStmt.code; | |
$last = $readStmt.last; | |
} | |
| writeStmt ';' | |
{ | |
$code = $writeStmt.code; | |
$last = $writeStmt.last; | |
} | |
; | |
assignStmt | |
returns [BasicBlock code, BasicBlock last] | |
: variableSymbol ':=' expr | |
{ | |
$last = $code = new BasicBlock(); | |
$code.addAll($expr.code); | |
$code.add(new StoreVariable($variableSymbol.info, $expr.place)); | |
} | |
| arraySymbol '(' arrayIdx ')' ':=' expr | |
{ | |
$last = $code = new BasicBlock(); | |
$code.addAll($expr.code); | |
$code.addAll($arrayIdx.code); | |
$code.add(new StoreArray($arraySymbol.info, $arrayIdx.place, $expr.place)); | |
} | |
; | |
readStmt | |
returns [BasicBlock code, BasicBlock last] | |
: 'READ' variableSymbol | |
{ | |
$last = $code = new BasicBlock(); | |
$code.add(new ReadVariable($variableSymbol.info)); | |
} | |
| 'READ' arraySymbol '(' arrayIdx ')' | |
{ | |
$last = $code = new BasicBlock(); | |
$code.addAll($arrayIdx.code); | |
$code.add(new ReadArray($arraySymbol.info, $arrayIdx.place)); | |
} | |
; | |
writeStmt | |
returns [BasicBlock code, BasicBlock last] | |
: 'WRITE' value | |
{ | |
$last = $code = new BasicBlock(); | |
$code.addAll($value.code); | |
$code.add(new Write($value.place)); | |
} | |
; | |
ifStmt | |
returns [BasicBlock code, BasicBlock last] | |
: 'IF' condition 'THEN' ifTrue=stmts ('ELSE' ifFalse=stmts)? 'ENDIF' | |
{ | |
$code = new BasicBlock(); | |
$last = new BasicBlock(); | |
$code.addAll($condition.code); | |
if ($ifFalse.ctx != null) { | |
$code.add(new JumpIf($condition.place, $ifTrue.code, $ifFalse.code)); | |
$code.addSuccessor($ifTrue.code); | |
$code.addSuccessor($ifFalse.code); | |
$ifTrue.last.add(new Jump($last)); | |
$ifTrue.last.addSuccessor($last); | |
$ifFalse.last.add(new Jump($last)); | |
$ifFalse.last.addSuccessor($last); | |
} else { | |
$code.add(new JumpIf($condition.place, $ifTrue.code, $last)); | |
$code.addSuccessor($ifTrue.code); | |
$code.addSuccessor($last); | |
$ifTrue.last.add(new Jump($last)); | |
$ifTrue.last.addSuccessor($last); | |
} | |
} | |
; | |
whileStmt | |
returns [BasicBlock code, BasicBlock last] | |
: 'WHILE' condition 'DO' body=stmts 'ENDWHILE' | |
{ | |
$code = new BasicBlock(); | |
$last = new BasicBlock(); | |
$code.addAll($condition.code); | |
$code.add(new JumpIf($condition.place, $body.code, $last)); | |
$code.addSuccessor($body.code); | |
$code.addSuccessor($last); | |
$body.last.add(new Jump($code)); | |
$body.last.addSuccessor($code); | |
} | |
; | |
doWhileStmt | |
returns [BasicBlock code, BasicBlock last] | |
: 'DO' body=stmts 'WHILE' condition 'ENDDO' | |
{ | |
$code = $body.code; | |
$last = new BasicBlock(); | |
$body.last.addAll($condition.code); | |
$body.last.add(new JumpIf($condition.place, $body.code, $last)); | |
$body.last.addSuccessor($body.code); | |
$body.last.addSuccessor($last); | |
} | |
; | |
forStmt | |
returns [BasicBlock code, BasicBlock last] | |
locals [Insturction ld, Instruction tmp1] | |
: 'FOR' forIterator 'DO' body=stmts 'ENDFOR' | |
{ | |
$code = $forIterator.code; | |
$last = new BasicBlock(); | |
$forIterator.cmpCode.add(new JumpIf($forIterator.cmp, $body.code, $last)); | |
$forIterator.cmpCode.addSuccessor($body.code); | |
$forIterator.cmpCode.addSuccessor($last); | |
$body.last.add($ld = new LoadVariable($forIterator.info)); | |
if (!$forIterator.downTo) { | |
$body.last.add($tmp1 = new Inc($ld)); | |
} else { | |
$body.last.add($tmp1 = new Dec($ld)); | |
} | |
$body.last.add(new StoreVariable($ld, $tmp1)); | |
$body.last.add(new Jump($forIterator.cmpCode)); | |
$body.last.addSuccessor($forIterator.cmpCode); | |
table = table.exitContext(); | |
} | |
; | |
forIterator | |
returns [BasicBlock code, BasicBlock cmpCode, Instruction cmp, VariableSymbolInfo info, boolean downTo] | |
: { | |
table = table.enterContext(); | |
} | |
variableDecl[true] | |
forIteratorRange[$variableDecl.info] | |
{ | |
$info = $variableDecl.info; | |
$downTo = $forIteratorRange.downTo; | |
$code = $forIteratorRange.code; | |
$cmpCode = $forIteratorRange.last; | |
$cmp = $forIteratorRange.cmp; | |
} | |
; | |
forIteratorRange [VariableSymbolInfo info] | |
returns [BasicBlock code, Instruction cmp, BasicBlock last, boolean downTo] | |
locals [Instruction ld] | |
: 'FROM' low=value ('TO' { $downTo = false; } | 'DOWNTO' { $downTo = true; }) hi=value | |
{ | |
$code = new BasicBlock(); | |
$last = new BasicBlock(); | |
$code.addAll($low.code); | |
$code.addAll($hi.code); | |
if (!$downTo) { | |
$code.add(new StoreVariable($info, $low.place)); | |
$code.add(new Jump($last)); | |
$code.addSuccessor($last); | |
$last.add($ld = new LoadVariable($info)); | |
$last.add($cmp = new Le($ld, $hi.place)); | |
} else { | |
$code.add(new StoreVariable($info, $hi.place)); | |
$code.add(new Jump($last)); | |
$code.addSuccessor($last); | |
$last.add($ld = new LoadVariable($info)); | |
$last.add($cmp = new Ge($ld, $low.place)); | |
} | |
} | |
; | |
expr | |
returns [Instruction place, BasicBlock code] | |
: l=value '+' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Add($l.place, $r.place)); | |
} | |
| l=value '-' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Sub($l.place, $r.place)); | |
} | |
| l=value '*' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Mul($l.place, $r.place)); | |
} | |
| l=value '/' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Div($l.place, $r.place)); | |
} | |
| l=value '%' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Mod($l.place, $r.place)); | |
} | |
| value | |
{ | |
$place = $value.place; | |
$code = $value.code; | |
} | |
; | |
condition | |
returns [Instruction place, BasicBlock code] | |
: l=value '=' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Eq($l.place, $r.place)); | |
} | |
| l=value '!=' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Ne($l.place, $r.place)); | |
} | |
| l=value '<=' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Le($l.place, $r.place)); | |
} | |
| l=value '>=' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Ge($l.place, $r.place)); | |
} | |
| l=value '<' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Lt($l.place, $r.place)); | |
} | |
| l=value '>' r=value | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($l.code); | |
$code.addAll($r.code); | |
$code.add($place = new Gt($l.place, $r.place)); | |
} | |
; | |
value | |
returns [Instruction place, BasicBlock code] | |
: variableSymbol | |
{ | |
$code = new BasicBlock(); | |
$code.add($place = new LoadVariable($variableSymbol.info)); | |
} | |
| arraySymbol '(' arrayIdx ')' | |
{ | |
$code = new BasicBlock(); | |
$code.addAll($arrayIdx.code); | |
$code.add($place = new LoadVariable($arraySymbol.info, $arrayIdx.place)); | |
} | |
| constantSymbol | |
{ | |
$code = new BasicBlock(); | |
$code.add($place = new LoadConst($constantSymbol.info)); | |
} | |
; | |
arrayIdx | |
returns [Instruction place, BasicBlock code] | |
: constantSymbol | |
{ | |
$code = new BasicBlock(); | |
$code.add($place = new LoadConst($constantSymbol.info)); | |
} | |
| variableSymbol | |
{ | |
$code = new BasicBlock(); | |
$code.add($place = new LoadVariable($variableSymbol.info)); | |
} | |
; | |
decl | |
: arrayDecl | |
| variableDecl[false] | |
; | |
variableDecl[boolean immutable] | |
returns [VariableSymbolInfo info] | |
: symbol | |
{ | |
$info = new VariableSymbolInfo(Location.fromContext($ctx), $immutable); | |
if (table.lookup($symbol.symb) != null) { | |
log.error(Location.fromContext($ctx), "redefinition of symbol {0}", | |
$symbol.symb.getUniqueName()); | |
return; | |
} | |
table.insert($symbol.symb, $info); | |
} | |
; | |
arrayDecl | |
locals [ArraySymbolInfo info] | |
: symbol '(' low=rawNumber ':' high=rawNumber ')' | |
{ | |
if ($low.val > $high.val) { | |
log.error(Location.fromContext($ctx), "declaring array {0} with invalid bounds", | |
$symbol.symb.getUniqueName()); | |
return; | |
} | |
$info = new ArraySymbolInfo(Location.fromContext($ctx), $low.val, $high.val); | |
if (table.lookup($symbol.symb) != null) { | |
log.error(Location.fromContext($ctx), "redefinition of symbol {0}", | |
$symbol.symb.getUniqueName()); | |
return; | |
} | |
table.insert($symbol.symb, $info); | |
} | |
; | |
arraySymbol | |
returns [ArraySymbolInfo info] | |
locals [SymbolInfo rawInfo] | |
: symbol | |
{ | |
$rawInfo = table.lookup($symbol.symb); | |
if ($rawInfo == null) { | |
log.error(Location.fromContext($ctx), "{0} is not defined", $symbol.symb.getUniqueName()); | |
return; | |
} else if (!$rawInfo.isArray()) { | |
log.error(Location.fromContext($ctx), "{0} is not an array", $symbol.symb.getUniqueName()); | |
return; | |
} | |
$info = $rawInfo.asArray(); | |
} | |
; | |
variableSymbol | |
returns [VariableSymbolInfo info] | |
locals [SymbolInfo rawInfo] | |
: symbol | |
{ | |
$rawInfo = table.lookup($symbol.symb); | |
if ($rawInfo == null) { | |
log.error(Location.fromContext($ctx), "{0} is not defined", $symbol.symb.getUniqueName()); | |
return; | |
} else if (!$rawInfo.isVariable()) { | |
log.error(Location.fromContext($ctx), "{0} is not a variable", $symbol.symb.getUniqueName()); | |
return; | |
} | |
$info = $rawInfo.asVariable(); | |
} | |
; | |
constantSymbol | |
returns [ConstantSymbolInfo info] | |
: rawNumber | |
{ | |
$info = table.lookup(Long.toString($rawNumber.val)); | |
if ($info == null) table.insert(Long.toString($rawNumber.val), new ConstantSymbolInfo($rawNumber.val)); | |
} | |
; | |
symbol | |
returns [Symbol symb] | |
: Identifier | |
{ | |
$symb = new Symbol(null, $Identifier.text); | |
} | |
; | |
rawNumber | |
returns [long val] | |
: Number | |
{ | |
try { | |
$val = Long.parseLong($Number.text); | |
} catch (NumberFormatException e) { | |
log.error(Location.fromContext($ctx), "{0} is not valid 64-bit integer", $Number.text); | |
} | |
} | |
; | |
Identifier | |
: ('a' .. 'z' | '_')+ | |
; | |
Number | |
: '0' | [1-9][0-9]* | |
; | |
Ws | |
: (' ' | '\n' | '\r' | '\t')+ | |
; | |
Comment | |
: '[' .*? ']' | |
; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment