学习Language Implementation Patterns 一书过程中,结合python 把promote 样例代码重新写了一下
语法代码如下:
Cymbol.g:
- grammar Cymbol;
- options {
- language=Python;
- output = AST; // build trees
- ASTLabelType = CymbolAST; // use custom tree nodes
- }
- tokens {
- METHOD_DECL; // function definition
- ARG_DECL; // parameter
- BLOCK;
- VAR_DECL;
- FIELD_DECL;
- CALL;
- ELIST; // expression list
- EXPR; // root of an expression
- UNARY_MINUS;
- UNARY_NOT;
- ASSIGN='=';
- INDEX;
- }
- compilationUnit
- @after {$tree.setUnknownTokenBoundaries();} // (liunote $tree =>CymbolAST tree) For every node in this subtree, make sure it's start/stop token's are set. (set => startIndex ,stopIndex )
- : ( // hard to distinguish alts from left edge so backtrack
- options {backtrack=true;}
- : structDeclaration | methodDeclaration | varDeclaration
- )+
- ;
- structDeclaration
- : 'struct' ID '{' structMember+ '}' ';' -> ^('struct' ID structMember+)
- ;
- structMember
- : type ID ';' -> ^(FIELD_DECL type ID)
- | type ID '[]' ';' -> ^(FIELD_DECL ^('[]' type) ID)
- | structDeclaration
- ;
- // START: method
- methodDeclaration
- : type ID '(' formalParameters? ')' block
- -> ^(METHOD_DECL type ID formalParameters? block)
- ;
- // END: method
- formalParameters
- : parameter (',' parameter)* -> parameter+
- ;
- parameter
- : type ID -> ^(ARG_DECL type ID)
- | type ID '[]' -> ^(ARG_DECL ^('[]' type) ID)
- ;
- type: primitiveType
- | 'struct' ID -> ID
- ;
- primitiveType
- : 'float'
- | 'int'
- | 'char'
- | 'boolean'
- | 'void'
- ;
- // START: block
- block
- : '{' statement* '}' -> ^(BLOCK statement*)
- ;
- // END: block
- // START: var
- varDeclaration
- : type ID ('=' expression)? ';' -> ^(VAR_DECL type ID expression?)
- | type ID '[]' ('=' expression)? ';' -> ^(VAR_DECL ^('[]' type) ID expression?)
- ;
- // END: var
- statement
- options {backtrack=true;} // hard to distinguish struct from var from left
- : block
- | structDeclaration
- | varDeclaration
- | 'if' '(' expression ')' s=statement ('else' e=statement)? // liunote see Definitive P193 improve
- -> ^('if' expression $s $e?)
- | 'return' expression? ';' -> ^('return' expression?)
- | lhs '=' expression ';' -> ^('=' lhs expression) // liunote handles 1. array item asignment link a[1]=5; 2.struct item asignment like a.i =1;
- | a=postfixExpression ';' // handles function calls like f(i);
- -> ^(EXPR postfixExpression)
- ;
- lhs : postfixExpression -> ^(EXPR postfixExpression)
- ;
- // liunote expressionList used by call f(i+1, c, a.i)
- expressionList
- : expr (',' expr)* -> ^(ELIST expr+)
- | -> ELIST
- ;
- expression
- : expr -> ^(EXPR expr)
- ;
- /* liunote a infer method for expr rule (according priority) !!! */
- expr: equalityExpression
- ;
- equalityExpression
- : relationalExpression (('!='^ | '=='^) relationalExpression)*
- ;
- relationalExpression
- : additiveExpression
- ( ( ( '<'^
- | '>'^
- | '<='^
- | '>='^
- )
- additiveExpression
- )*
- )
- ;
- additiveExpression
- : multiplicativeExpression (('+'^ | '-'^) multiplicativeExpression)*
- ;
- multiplicativeExpression
- : unaryExpression (('*'^ | '/'^) unaryExpression)*
- ;
- // unary (one meta)
- unaryExpression
- : op='-' unaryExpression -> ^(UNARY_MINUS[$op] unaryExpression) /* definitive P189 ,UNARY_NOT,UNARY_MINUS => token name */
- | op='!' unaryExpression -> ^(UNARY_NOT[$op] unaryExpression)
- | postfixExpression
- ;
- // START: call
- postfixExpression
- : primary
- (
- ( r='('^ expressionList ')'! {$r.setType(CALL);} // liunote (TokenRewriteStream)Token.setType
- | r='['^ expr ']'! {$r.setType(INDEX);}
- | r='.'^ ID
- )
- )*
- ;
- // END: call
- primary
- : ID
- | INT
- | FLOAT
- | CHAR
- | 'true'
- | 'false'
- | '(' expression ')' -> expression
- ;
- // LEXER RULES
- ID : LETTER (LETTER | '0'..'9')* //{ self.setText('myid'); print self.getText()}
- ;
- fragment
- LETTER
- : ('a'..'z' | 'A'..'Z')
- ;
- CHAR: '\'' . '\'' ;
- //STRING: '\"' STR_CHARS '\"' {realc = str(int($STR_CHARS.text,8)); self.setText(realc);} //{setText($STR_CHARS.text);} ;
- //fragment STR_CHARS : ~'"'* ;
- INT : '0'..'9'+ ;
- //fragment
- //NONZERODIGIT
- // : '1'..'9'
- // ;
- //fragment
- //DIGIT
- // : '0'..'9' {print $INT.text}
- // ;
- //INT
- // : NONZERODIGIT (DIGIT)* // base-10
- // ( '.' (DIGIT)*
- // ( (('e' | 'E') ('+' | '-')? (DIGIT)+) {$type=FLOAT;} /* liunote $setType ???,lexer class no,token has*/
- // | ('d' | 'D')! {$type=FLOAT;}
- // | {$type=FLOAT;}
- // )
- // | ('e' | 'E') ('+' | '-')? (DIGIT)+ {$type=FLOAT;} /*1.55e+22, 1.55e-22*/
- // | ('d' | 'D')! {$type=FLOAT;}
- // )?
- // ;
- FLOAT
- : INT '.' INT* {$type=FLOAT;}
- | '.' INT+
- ;
- //FLOAT
- // : '.' (DIGIT)+
- // ;
- // ( ('e' | 'E') ('+' | '-')? (DIGIT)+
- // | ('d' | 'D')! /*{self.setType(FIXED);}*/
- // )?
- // ;
- WS : (' '|'\r'|'\t'|'\n') {$channel=HIDDEN;}
- ;
- SL_COMMENT
- : '//' ~('\r'|'\n')* '\r'? '\n' {$channel=HIDDEN;}
- ;
Def.g:
- // START: header
- tree grammar Def;
- options {
- language=Python;
- tokenVocab = Cymbol;
- ASTLabelType = CymbolAST;
- //filter = true;
- superClass=MyTreeFilter;
- }
- // liunote ???
- @header{
- from MyTreeFilter import MyTreeFilter
- from SymbolTable import SymbolTable;
- from ArrayType import ArrayType;
- from StructSymbol import StructSymbol;
- from MethodSymbol import MethodSymbol;
- from LocalScope import LocalScope;
- from VariableSymbol import VariableSymbol;
- from CymbolAST import CymbolAST;
- }
- /*
- @members{
- SymbolTable symtab;
- Scope currentScope;
- MethodSymbol currentMethod;
- public Def(TreeNodeStream input, SymbolTable symtab) {
- this(input);
- this.symtab = symtab;
- currentScope = symtab.globals;
- }
- }
- */
- @init {
- #//self.symtab = SymbolTable();
- #//self.currentScope = Scope();
- self.currentMethod = None #//MethodSymbol();
- }
- @members {
- def def_init2(self, symtab): # //liunote Def is Def tree class 's construct func
- #//self.__init__(input); # this(input) # do by Def class's init
- self.symtab = symtab
- self.currentScope = symtab.globals
- }
- // END: header
- //downup : topdown ( bottomup );
- topdown
- : enterBlock
- | enterMethod
- | enterStruct
- | atoms
- | varDeclaration
- | ret
- ;
- bottomup
- : exitBlock
- | exitMethod
- | exitStruct
- ;
- // S C O P E S
- enterBlock
- : BLOCK {self.currentScope = LocalScope(self.currentScope);} //{currentScope = new LocalScope(currentScope);} // push scope
- ;
- exitBlock
- : BLOCK
- {
- #//System.out.println("locals: "+currentScope);
- #//currentScope = currentScope.getEnclosingScope(); # pop scope
- self.currentScope = self.currentScope.getEnclosingScope(); #// pop scope
- }
- ;
- // START: struct
- enterStruct
- : ^('struct' ID .+)
- {
- #//System.out.println("line "+str($ID.getLine())+": def struct "+$ID.text);
- #//StructSymbol ss = new StructSymbol($ID.text, currentScope);
- ss = StructSymbol($ID.text, self.currentScope);
- #//ss = StructSymbol();
- #//ss.StructSymbol_init($ID.text, self.currentScope);
- ss.cymbolast_def = $ID;
- $ID.symbol = ss;
- #//currentScope.define(ss); # def struct in current scope
- self.currentScope.define(ss); # //def struct in current scope
- self.currentScope = ss; # //set current scope to struct scope
- }
- ;
- // liunote why 'struct' match exitStruct ,because , if find struct string when downup walk up struct !!! ,downup walk is down to down to down only leaf up ,says depth-first
- exitStruct
- : 'struct'
- {
- #//System.out.println("fields: "+currentScope);
- self.currentScope = self.currentScope.getEnclosingScope(); #// pop scope
- }
- ;
- // END: struct
- enterMethod
- : ^(METHOD_DECL type ID .*) // match method subtree with 0-or-more args
- {
- #//System.out.println("line "+$ID.getLine()+": def method "+$ID.text);
- #//MethodSymbol ms = new MethodSymbol($ID.text,$type.type,currentScope);
- ms = MethodSymbol($ID.text,$type.type,self.currentScope); # //liunote ID.getText => CommTree.getText => self.token.text
- self.currentMethod = ms;
- ms.cymbolast_def = $ID; # //track AST location of def's ID
- $ID.symbol = ms; # track in AST
- self.currentScope.define(ms); # def method in globals
- self.currentScope = ms; # set current scope to method scope
- }
- ;
- /** Track method associated with this return. */
- ret : ^('return' .) {$ret.start.symbol = self.currentMethod;} //$ret.start => ret tree node start child node ???
- ;
- exitMethod
- : METHOD_DECL
- {
- self.currentScope = self.currentScope.getEnclosingScope(); #// pop arg scope
- }
- ;
- // D e f i n e s y m b o l s
- // START: atoms
- /** Set scope for any identifiers in expressions or assignments */
- atoms
- @init {t = self.input.LT(1);} // liunote err =>{t = CymbolAST(self.input.LT(1)); print type(self.input.LT(1));} //{CymbolAST t = (CymbolAST)input.LT(1);} // liunote ??? CommonTreeNodeStream LT ->Get tree node at current input pointer + i ahead where i=1 is next node.
- : {t.hasAncestor(EXPR) or t.hasAncestor(ASSIGN)}? ID // liunote hasAncestor: Walk upwards looking for ancestor with this token type
- {t.scope = self.currentScope;}
- ;
- //END: atoms
- // START: var
- varDeclaration // global, parameter, or local variable
- : ^((FIELD_DECL|VAR_DECL|ARG_DECL) type ID .?)
- {
- #//System.out.println("line "+$ID.getLine()+": def "+$ID.text);
- #// liutst def out
- print ("line "+ str($ID.getLine())+": def "+$ID.text);
- #//VariableSymbol vs = new VariableSymbol($ID.text,$type.type);
- vs = VariableSymbol($ID.text,$type.type);
- #//track AST location of def's ID
- vs.cymbolast_def = $ID;
- $ID.symbol = vs; # //track in AST
- self.currentScope.define(vs);
- }
- ;
- // END: field
- // Actions at the start of alternative are in node discovery position.
- // Actions at the end of an alternative are in node finishing position.
- // Actions embedded within the alternative happen in between node discovery and finishing
- /** Not included in tree pattern matching directly. Needed by declarations */
- type returns [type] //[Type type] liunote type rule name same as return name ???
- : ^('[]' typeElement) {$type = ArrayType($typeElement.type);} //{$type = new ArrayType($typeElement.type);}
- | typeElement {$type = $typeElement.type;}
- ;
- typeElement returns [type] //[Type type]
- @init {t = self.input.LT(1); } // {t = CymbolAST(self.input.LT(1)); print type(self.input.LT(1));} //{CymbolAST t = (CymbolAST)input.LT(1);} //liunote ???
- @after {
- t.symbol = self.currentScope.resolve(t.getText()); # // return Type
- t.scope = self.currentScope;
- #//$type = (Type)t.symbol;
- $type = (t.symbol) #Type_init(t.symbol);
- }
- : 'float'
- | 'int'
- | 'char'
- | 'boolean'
- | 'void'
- | ID // struct name
- ;
Types.g:
- // START: header
- tree grammar Types;
- options {
- language=Python;
- tokenVocab = Cymbol;
- ASTLabelType = CymbolAST;
- //filter = true;
- superClass=MyTreeFilter;
- }
- // liunote ???
- @header{
- from MyTreeFilter import MyTreeFilter
- from SymbolTable import SymbolTable
- from ArrayType import ArrayType
- from StructSymbol import StructSymbol
- from MethodSymbol import MethodSymbol
- from LocalScope import LocalScope
- from VariableSymbol import VariableSymbol
- }
- /*
- @members {
- SymbolTable symtab;
- public Types(TreeNodeStream input, SymbolTable symtab) {
- this(input);
- this.symtab = symtab;
- }
- }
- */
- @members {
- def Types_init2(self,symtab):
- self.symtab = symtab;
- }
- // END: header
- bottomup // match subexpressions innermost to outermost
- : exprRoot
- | decl
- | ret
- | assignment
- ;
- // START: datatransfer
- decl: ^(VAR_DECL . ID (init=.)?) // call declinit if we have init expr
- /*{if ( $init!=null && $init.evalType!=null )
- symtab.declinit($ID, $init);}
- *//* liunote $init=>CymbolAST */
- {if $init != None and $init.evalType != None:
- self.symtab.declinit($ID, $init);
- }
- ;
- ret : ^('return' v=.) {self.symtab.ret($start.symbol, $v);} //{symtab.ret((MethodSymbol)$start.symbol, $v);} liunote $ret.start ???
- ;
- assignment // don't walk exprs, just examine types; '.' is wildcard
- : ^('=' lhs=. rhs=.) {self.symtab.assign($lhs, $rhs);}
- ;
- // END: datatransfer
- exprRoot // invoke type computation rule after matching EXPR
- : ^(EXPR expr) {$EXPR.evalType = $expr.type;} // annotate AST
- ;
- expr returns [type] //[Type type]
- @after { $start.evalType = $type; }
- : 'true' {$type = SymbolTable._boolean;} // liunote : _boolean is class SymbolTable static var
- | 'false' {$type = SymbolTable._boolean;}
- | CHAR {$type = SymbolTable._char;}
- | INT {$type = SymbolTable._int;}
- | FLOAT {$type = SymbolTable._float;}
- | ID /*{VariableSymbol s=(VariableSymbol)$ID.scope.resolve($ID.text);
- $ID.symbol = s; $type = s.type;}*/ /* liunote CymbolAST =>$ID */ /* no use cast ,because python return no type*/
- {
- s=$ID.scope.resolve($ID.text);
- $ID.symbol = s;
- $type = s.type;
- } // liunote $type is expr returns [type]
- | ^(UNARY_MINUS a=expr) {$type=self.symtab.uminus($a.start);}
- | ^(UNARY_NOT a=expr) {$type=self.symtab.unot($a.start);}
- | member {$type = $member.type;}
- | arrayRef {$type = $arrayRef.type;}
- | call {$type = $call.type;}
- | binaryOps {$type = $binaryOps.type;}
- ;
- binaryOps returns [type] //[Type type]
- @after { $start.evalType = $type; } /* => ((CymbolAST)retval.start).evalType = retval.type; */
- : ( ^(bop a=expr b=expr) {$type=self.symtab.bop($a.start, $b.start);}
- | ^(relop a=expr b=expr) {$type=self.symtab.relop($a.start, $b.start);}
- | ^(eqop a=expr b=expr) {$type=self.symtab.eqop($a.start, $b.start);}
- )
- ;
- arrayRef returns [type] //[Type type]
- : ^(INDEX ID expr)
- {
- $type = self.symtab.arrayIndex($ID, $expr.start);
- $start.evalType = $type;
- }
- ;
- call returns [type] //[Type type]
- @init {args = [];}//{List args = new ArrayList();}
- : ^(CALL ID ^(ELIST (expr {args.append($expr.start);})*))
- {
- $type = self.symtab.call($ID, args);
- $start.evalType = $type;
- }
- ;
- member returns [type] //[Type type]
- : ^('.' expr ID)
- {
- $type = self.symtab.member($expr.start, $ID);
- $start.evalType = $type;
- }
- ;
- bop : '+' | '-' | '*' | '/' ;
- relop: '<' | '>' | '<=' | '>=' ;
- eqop: '!=' | '==' ;
阅读(1064) | 评论(0) | 转发(0) |