Statistics: |
|
|
000002|
000003| (**
000004|
000005| This program is free software; you can redistribute it and / or modify
000006| it under the terms of the GNU General Public License as published by
000007| the Free Software Foundation; version 3 of the License.
000008|
000009| This program is distributed in the hope that it will be useful,
000010| but WITHOUT ANY WARRANTY; without even the implied warranty of
000011| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
000012| GNU General Public License for more details.
000013|
000014| Jtemplate parser
000015| expression parsing adapted from ECMA-262
000016| http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf
000017|
000018| @author Tony BenBrahim < tony.benbrahim at gmail.com >
000019|
000020| *)
000021|
000022| open Ast
000023|
000024| let parse_error s =
000025| let pos = Parsing.symbol_start_pos() in
000026| print_string ("in file " ^ (Filename.basename pos.Lexing.pos_fname) ^ ": "^ s^" at line ");
000027| print_int pos.Lexing.pos_lnum;
000028| print_string " at columns ";
000029| print_int (Parsing.symbol_start() - pos.Lexing.pos_bol);
000030| print_string("-");
000031| print_int (Parsing.symbol_end() - pos.Lexing.pos_bol);
000032| print_string "\n";
000033| flush stdout
000034|
000035| let get_env ()=
000036| let pos=Parsing.symbol_start_pos() in
000037| (pos.Lexing.pos_fname,pos.Lexing.pos_lnum)
000038|
000039|
000040| let resolve_import (filename, library, (inp_file, _))=
000041| Filename_util.resolve_filename (Filename.dirname inp_file) filename
000042|
000043| let extract_stmt_list=function
000044| | StatementBlock(lst) -> lst
000045| | _ -> raise ( RuntimeError.InternalError "expected statement block" )
000046| %}
000047|
000048| %token<string> ID
000049| %toke(*[0]*)n <int> INT
000051| %token <(*[0]*)float> REAL
000055| %token (*[0]*)<bool> IMPORT
000057| %token FOREACH WHIL(*[0]*)E IF FOR ELSE TEMPLATE INSTRUCTIO(*[0]*)NS FUNCTION CONTINUE BREAK
000058| %token RETURN IN ONCE WHEN VAR EOF(*[0]*) LBRACE RBRACE LPAREN RP(*[0]*)AREN LBRACKET RBRACKET
000059| %token COMMA SEMICOLON COLON DOTDOTD(*[0]*)OT DOT EQUALS NOT QUESTI(*[0]*)ON PLUS MINUS TIMES
000060| %token DIVIDE MODULO AND (*[1386]*)OR VOID SWITCH CASE DEFAULT PLUSEQUALS MINUS(*[1386]*)EQUALS
000061| %token TIMESEQUALS DIVEQUALS MODEQUALS PLUSPLUS MINUSMINUS AT TRY CATCH THROW
000062| %token FINALLY PROTOTYPE OUT(*[18]*)OFRANGENUMBER
000063|
000064|
000065| %start program
000066| %type <Ast.statement> program
000067|
000068| /* resolve shift/reduce conflict for ELSE */
000069| %nonassoc LOWER_THAN_ELSE
(*[346]*)
000070| %nonassoc ELSE
(*[0]*)
000072| /* resolve shift/reduce conflict for {} (map) and {} (empty block) */
000073| %nonassoc MAP
000074| %nonassoc EMPTYBLOCK
000075|
000076| %right PLUSEQUALS MINUSEQUALS
000077| %right TIMESEQUALS DIVEQUALS MODEQUALS
000078| %right EQUALS
000079| %right COLON
000080| %right QUESTION
000081| %left OR
000082| %left AND
000083| %left COMPOP
000084| %left PLUS MINUS
000085| %left TIMES DIVIDE MODULO
000086| %right NOT
000087| %right UMINUS
000088| %right PREFIX_INCDEC
000089| %left POSTFIX_INCDEC
000090| %left ARR_INDEX
000091|
000092| %%
000093| program:
000094| | opt_statements EOF { Program($1) }
000095| ;
000096| statements:
000097| | statement { [$1] }
000098| | statement statements { $1::$2 }
000099| ;
000100| opt_statements:
000101| | statements { $1 }
000102| | /*nothing*/ { [] }
000103| ;
000104| statement_block:
000105| | LBRACE statements RBRACE { StatementBlock($2) }
000106| | empty_statement_block { $1 }
000107| ;
000108| empty_statement_block:
000109| | LBRACE RBRACE { StatementBlock([]) }
000110| ;
000111| else_clause:
000112| | ELSE statement { $2 }
000113| | %prec LOWER_THAN_ELSE { Noop }
000114| ;
000115| statement:
000116| | IF LPAREN expression RPAREN statement else_clause { If($3,$5,$6,get_env()) }
000117| | expression SEMICOLON { ExpressionStatement($1, get_env()) }
000118| | SEMICOLON { Noop }
000119| | statement_block { $1 }
000120| | FOREACH LPAREN ID IN expression RPAREN statement { ForEach($3,$5,$7,get_env()) }
000121| | WHILE LPAREN expression RPAREN statement { For(Value(Void),$3,Value(Void),$5,get_env()) }
000122| | CONTINUE SEMICOLON { Continue(get_env())}
000123| | BREAK SEMICOLON { Break(get_env())}
000124| | RETURN opt_expression SEMICOLON { Return($2,get_env()) }
000125| | IMPORT STRING SEMICOLON { Import(resolve_import($2,$1,get_env()),get_env()) }
000126| | TEMPLATE ID LBRACE template_specs RBRACE { TemplateDef($2, $4,get_env()) }
000127| | INSTRUCTIONS FOR ID LPAREN arglist RPAREN LBRACE instruction_specs RBRACE
000128| { Instructions($3,$5,$8,get_env()) }
000129| | SWITCH LPAREN expression RPAREN LBRACE switch_statements RBRACE
000130| { Switch($3,$6, get_env()) }
000131| | FOR LPAREN opt_expression SEMICOLON
000132| opt_expression SEMICOLON
000133| opt_expression RPAREN statement { For($3,$5,$7,$9,get_env()) }
000134| | TRY statement_block CATCH LPAREN ID RPAREN statement_block { TryCatch($2,$5,$7, get_env()) }
000135| | TRY statement_block FINALLY statement_block { TryFinally($2,$4,get_env()) }
000136| | THROW expression SEMICOLON { Throw($2, get_env()) }
000137| ;
000138| switch_statement:
000139| | CASE expression COLON { Case(Some $2,get_env()) }
000140| | DEFAULT COLON { Case(None,get_env()) }
000141| | statement { $1 }
000142| ;
000143| switch_statements:
000144| | switch_statement { [$1] }
000145| | switch_statement switch_statements { $1::$2 }
000146| ;
000147| opt_expression:
000148| | expression { $1 }
000149| | empty_expression { Value(Void) }
000150| ;
000151| empty_expression:
000152| | /*nothing */ { Value(Void) }
000153| ;
000154| atom_expr:
000155| | INT { Value(IntegerValue($1)) }
000156| | REAL { Value(FloatValue($1)) }
000157| | STRING { Value(StringValue($1)) }
000158| | BOOLEAN { Value(BooleanValue($1)) }
000159| | VOID { Value(Void) }
000160| | LBRACKET expr_list RBRACKET { ArrayExpr($2) }
000161| | LBRACE prop_list RBRACE { MapExpr($2) }
000162| | ID { Id($1) }
000163| | LPAREN expression RPAREN { $2 }
000164| ;
000165| member_expr:
000166| | atom_expr {$1}
000167| | FUNCTION LPAREN arglist RPAREN statement_block { Value(FunctionValue($3,extract_stmt_list($5))) }
000168| | member_expr LBRACKET expression RBRACKET { MemberExpr($1,$3) }
000169| | member_expr DOT ID { MemberExpr($1,Value(StringValue($3))) }
000170| ;
000171| call_expr:
000172| | member_expr LPAREN fexpr_list RPAREN { FunctionCall($1,$3) }
000173| | call_expr LPAREN fexpr_list RPAREN { FunctionCall($1,$3) }
000174| | call_expr LBRACKET expression RBRACKET { MemberExpr($1,$3) }
000175| | call_expr DOT ID { MemberExpr($1,Value(StringValue($3))) }
000176| ;
000177| lhs_expr:
000178| | member_expr {$1}
000179| | call_expr {$1}
000180| ;
000181| unary_expr:
000182| | lhs_expr { $1 }
000183| | %prec PREFIX_INCDEC PLUSPLUS lhs_expr { Assignment($2,BinaryOp($2,Plus,Value(IntegerValue(1)))) }
000184| | %prec PREFIX_INCDEC MINUSMINUS lhs_expr { Assignment($2,BinaryOp($2,Minus,Value(IntegerValue(1)))) }
000185| | %prec POSTFIX_INCDEC lhs_expr PLUSPLUS { PostFixSum($1,1) }
000186| | %prec POSTFIX_INCDEC lhs_expr MINUSMINUS { PostFixSum($1,-1) }
000187| ;
000188| op_expr:
000189| | unary_expr {$1}
000190| | op_expr PLUS op_expr { BinaryOp($1,Plus,$3) }
000191| | op_expr MINUS op_expr { BinaryOp($1,Minus,$3) }
000192| | op_expr TIMES op_expr { BinaryOp($1,Times,$3) }
000193| | op_expr DIVIDE op_expr { BinaryOp($1,Divide,$3) }
000194| | op_expr MODULO op_expr { BinaryOp($1,Modulo,$3) }
000195| | op_expr COMPOP op_expr { CompOp($1,$2,$3) }
000196| | NOT lhs_expr { Not($2) }
000197| | op_expr AND op_expr { BinaryOp($1,And,$3) }
000198| | op_expr OR op_expr { BinaryOp($1,Or,$3) }
000199| | %prec UMINUS MINUS op_expr { BinaryOp(Value(IntegerValue(0)),Minus,$2) }
000200| ;
000201| cond_expr:
000202| | op_expr {$1}
000203| | expression QUESTION expression COLON expression
000204| { TernaryCond($1,$3,$5) }
000205| ;
000206| expression:
000207| | cond_expr {$1}
000208| | lhs_expr EQUALS expression { Assignment($1,$3) }
000209| | lhs_expr EQUALS empty_statement_block { Assignment($1,MapExpr([])) }
000210| | VAR lhs_expr EQUALS expression { Declaration($2,$4) }
000211| | VAR lhs_expr EQUALS empty_statement_block { Declaration($2,MapExpr([])) }
000212| | lhs_expr TIMESEQUALS expression { Assignment($1,(BinaryOp($1,Times,$3))) }
000213| | lhs_expr MODEQUALS expression { Assignment($1,(BinaryOp($1,Modulo,$3))) }
000214| | lhs_expr DIVEQUALS expression { Assignment($1,(BinaryOp($1,Divide,$3))) }
000215| | lhs_expr PLUSEQUALS expression { Assignment($1,(BinaryOp($1,Plus,$3))) }
000216| | lhs_expr MINUSEQUALS expression { Assignment($1,(BinaryOp($1,Minus,$3))) }
000217| ;
000218| arglist:
000219| | ID { [$1] }
000220| | ID DOTDOTDOT { ["["^$1] }
000221| | ID COMMA arglist { $1::$3 }
000222| | /* nothing */ { [] }
000223| ;
000224| expr_list:
000225| | expression { [$1] }
000226| | empty_statement_block { [MapExpr([])] }
000227| | expression COMMA expr_list { $1::$3 }
000228| | /*nothing*/ { [] }
000229| ;
000230| fexpr:
000231| | expression { $1 }
000232| | empty_statement_block { MapExpr([]) }
000233| | AT ID { UnboundVar($2) }
000234| | AT ID DOTDOTDOT { UnboundVar("["^$2) }
000235| ;
000236| fexpr_list:
000237| | fexpr { [$1] }
000238| | fexpr COMMA fexpr_list { $1::$3 }
000239| | /*nothing*/ { [] }
000240| ;
000241| property:
000242| | ID COLON expression { ($1,$3) }
000243| | ID COLON empty_statement_block { ($1,MapExpr([])) }
000244| ;
000245| prop_list:
000246| | property { [$1] }
000247| | property COMMA prop_list { $1::$3 }
000248| ;
000249| template_spec:
000250| | label TEXT { (Some $1,$2 ^ "\n") }
000251| | TEXT { (None, $1 ^ "\n") }
000252| ;
000253| template_specs:
000254| | template_spec { [$1] }
000255| | template_spec template_specs { $1::$2 }
000256| ;
000257| instruction_spec:
000258| | label repl_condition COLON replacement_list SEMICOLON { ($1,$2,$4) }
000259| | label repl_condition SEMICOLON { ($1,$2,[]) }
000260| ;
000261| repl_condition:
000262| | ONCE { Once }
000263| | WHEN LPAREN expression RPAREN { When($3) }
000264| | FOREACH LPAREN ID IN expression RPAREN { Loop($3,$5) }
000265| | FOREACH LPAREN ID IN expression RPAREN WHEN LPAREN expression RPAREN
000266| { CondLoop($9,$3,$5) }
000267| ;
000268| replacement:
000269| | ID EQUALS expression { ($1,$3) }
000270| ;
000271| replacement_list:
000272| | /* nothing */ { [] }
000273| | replacement { [$1] }
000274| | replacement COMMA replacement_list { $1::$3 }
000275| ;
000276| instruction_specs:
000277| | instruction_spec { [$1] }
000278| | instruction_spec instruction_specs { $1::$2 }
000279| ;
000280| label:
000281| | ID { $1 }
000282| | INT { string_of_int($1) }
000283| ;
000284| %%