Hej devs, here is the patch for the grammar and the tree-grammar.
Marc On Thursday 29 May 2008 17:57:30 Alex Boisvert wrote: > Hi Marc, > > Yes, you're right about the cardinality issue in the grammar. A patch > would be greatly appreciated! > > alex > > On Thu, May 29, 2008 at 8:23 AM, Marc Bischof <[EMAIL PROTECTED]> wrote: > > Hello devs, > > > > I'am a student at the IAAS and working on a BPEL2SimPEL translator. > > > > I looked at the SimPEL-Grammar and I think you've missed something when > > modeling non-empty lists. > > > > I also propose that the rewrite-rules should be correct in the grammar > > so the translation into tree-grammar would be clearer and less error > > prone. > > > > Here a short example: > > > > In the param_block-rule you've modeled an optional ID-list. But in the > > rewrite-rule this is missing. So I think that there should be $in* (in > > general this should be a $in+, but in this special case the complete list > > is > > optional). > > When this was done in the proposed way in the grammar, it would also > > affect the tree-grammar. There, the param-block-rule is currently modeled > > with $ID+ > > instead of $ID*. > > > > So I went over the grammar and looked for these errors (changes in > > tree-grammar analog): > > > > * param_block : '{' ('|' in+=ID (',' in+=ID)* '|')? proc_stmt+ '}' -> > > ^(SEQUENCE $in proc_stmt+); > > > > > param_block : '{' ('|' in+=ID (',' in+=ID)* '|')? proc_stmt+ '}' -> > > > > ^(SEQUENCE $in* proc_stmt+); > > > > * flow : 'parallel' b+=body ('and' b+=body)* -> ^(FLOW $b); > > > > > flow : 'parallel' b+=body ('and' b+=body)* -> ^(FLOW $b+); > > > > * join : 'join' '(' k+=ID (',' k+=ID)* (',' expr)? ')' -> ^(JOIN $k > > expr?); > > > > > join : 'join' '(' k+=ID (',' k+=ID)* (',' expr)? ')' -> ^(JOIN $k+ > > > > expr?); > > > > * with_ex : 'with' '(' wm+=with_map (',' wm+=with_map)* ')' body -> > > ^(WITH $wm* body); > > > > > with_ex : 'with' '(' wm+=with_map (',' wm+=with_map)* ')' body -> > > > > ^(WITH > > $wm+ body); > > > > * partner_link : 'partnerLink' pl+=ID (',' pl+=ID)* -> ^(PARTNERLINK > > $pl); > > > > > partner_link : 'partnerLink' pl+=ID (',' pl+=ID)* -> ^(PARTNERLINK > > > > $pl+); > > > > * correlation : '{' corr_mapping (',' corr_mapping)* '}' -> ^(CORRELATION > > corr_mapping*); > > > > > correlation : '{' corr_mapping (',' corr_mapping)* '}' -> > > > > ^(CORRELATION > > corr_mapping+); > > > > * path_expr : pelmt+=ns_id ('.' pelmt+=ns_id)* -> ^(PATH $pelmt); > > > > > path_expr : pelmt+=ns_id ('.' pelmt+=ns_id)* -> ^(PATH $pelmt+); > > > > Do you think, I'm right. Should I file a patch? > > > > Kind regards > > Marc Bischof
grammar SimPEL; options { output=AST; language=Java; ASTLabelType=LinkedListTree; } tokens { ROOT; PROCESS; PICK; SEQUENCE; FLOW; IF; ELSEIF; ELSE; WHILE; UNTIL; FOREACH; FORALL; INVOKE; RECEIVE; REPLY; ASSIGN; THROW; WAIT; EXIT; TIMEOUT; TRY; CATCH; CATCH_ALL; SCOPE; EVENT; ALARM; COMPENSATION; COMPENSATE; CORRELATION; CORR_MAP; PARTNERLINK; VARIABLE; BLOCK_PARAM; SIGNAL; JOIN; WITH; MAP; EXPR; EXT_EXPR; XML_LITERAL; CALL; NAMESPACE; NS; PATH; } @parser::header { package org.apache.ode.simpel.antlr; import uk.co.badgersinfoil.e4x.antlr.LinkedListTokenStream; import uk.co.badgersinfoil.e4x.antlr.LinkedListTree; import uk.co.badgersinfoil.e4x.E4XHelper; import org.apache.ode.simpel.ErrorListener; import org.apache.ode.simpel.util.JSHelper; } @lexer::header { package org.apache.ode.simpel.antlr; import org.apache.ode.simpel.ErrorListener; } @lexer::members { private ErrorListener el; public void setErrorListener(ErrorListener el) { this.el = el; } public void displayRecognitionError(String[] tokenNames, RecognitionException e) { el.reportRecognitionError(tokenNames, e.line, getErrorMessage(e, tokenNames), e); } } @parser::members { public static final int CHANNEL_PLACEHOLDER = 999; private SimPELLexer lexer; private CharStream cs; private ErrorListener el; public void setInput(SimPELLexer lexer, CharStream cs) { this.lexer = lexer; this.cs = cs; } public void setErrorListener(ErrorListener el) { this.el = el; } /** Handle 'island grammar' for embeded XML-literal elements. */ private LinkedListTree parseXMLLiteral() throws RecognitionException { return E4XHelper.parseXMLLiteral(lexer, cs, (LinkedListTokenStream)input); } /** Handle 'island grammar' for embeded JavaScript-literal elements. */ private LinkedListTree parseJSLiteral() throws RecognitionException { return JSHelper.parseJSLiteral(lexer, cs, (LinkedListTokenStream)input); } public void displayRecognitionError(String[] tokenNames, RecognitionException e) { el.reportRecognitionError(tokenNames, e.line, getErrorMessage(e, tokenNames), e); } public String getErrorMessage(RecognitionException e, String[] tokenNames) { List stack = getRuleInvocationStack(e, this.getClass().getName()); String msg = null; if ( e instanceof NoViableAltException ) { NoViableAltException nvae = (NoViableAltException)e; msg = " no viable alt; token="+e.token+" (decision="+nvae.decisionNumber+" state "+nvae.stateNumber+")"+ " decision=<<"+nvae.grammarDecisionDescription+">>"; } else { msg = super.getErrorMessage(e, tokenNames); } return stack+" "+msg; } public String getTokenErrorDisplay(Token t) { return t.toString(); } } // MAIN BPEL SYNTAX program : declaration+ -> ^(ROOT declaration+); declaration : funct | process | namespace; // Process process : 'process' ns_id body -> ^(PROCESS ns_id body); proc_stmt : pick | flow | if_ex | while_ex | until_ex | foreach | forall | try_ex | scope_ex | with_ex | receive | ((invoke | reply | assign | throw_ex | wait_ex | exit | signal | join | variables | partner_link) SEMI!); block : '{' proc_stmt+ '}' -> ^(SEQUENCE proc_stmt+); param_block : '{' ('|' in+=ID (',' in+=ID)* '|')? proc_stmt+ '}' -> ^(SEQUENCE $in* proc_stmt+); body : block | proc_stmt; // Structured activities pick : 'pick' '{' receive* timeout* '}' -> ^(PICK receive* timeout*); timeout : 'timeout' '(' expr ')' block -> ^(TIMEOUT expr block); flow : 'parallel' b+=body ('and' b+=body)* -> ^(FLOW $b+); signal : 'signal' '('ID (',' expr)? ')' -> ^(SIGNAL ID expr?); join : 'join' '(' k+=ID (',' k+=ID)* (',' expr)? ')' -> ^(JOIN $k+ expr?); if_ex : 'if' '(' expr ')' ifb=body ('else' eb=body)? -> ^(IF expr $ifb (^(ELSE $eb))?); while_ex: 'while' '(' expr ')' body -> ^(WHILE expr body); until_ex: 'do' body 'until' '(' expr ')' -> ^(UNTIL expr body); foreach : 'for' '(' ID '=' init=expr ';' cond=expr ';' assign ')' body -> ^(FOREACH ID $init $cond assign body); forall : 'forall' '(' ID '=' from=expr 'to' to=expr ')' body -> ^(FORALL ID $from $to body); try_ex : 'try' body catch_ex* -> ^(TRY body catch_ex*); catch_ex: 'catch' '(' ns_id ')' param_block -> ^(CATCH ns_id param_block); scope_ex: 'scope' ('(' ID ')')? body scope_stmt* -> ^(SCOPE ID? body scope_stmt*); scope_stmt : event | alarm | compensation; event : 'event' '(' p=ID ',' o=ID ')' param_block -> ^(EVENT $p $o param_block); alarm : 'alarm' '(' expr ')' body -> ^(ALARM expr body); compensation : 'compensation' body -> ^(COMPENSATION body); with_ex : 'with' '(' wm+=with_map (',' wm+=with_map)* ')' body -> ^(WITH $wm+ body); with_map: ID ':' path_expr -> ^(MAP ID path_expr); // Simple activities invoke : 'invoke' '(' p=ID ',' o=ID (',' in=ID)? ')' -> ^(INVOKE $p $o $in?); receive options {backtrack=true;} : receive_base SEMI -> ^(RECEIVE receive_base) | receive_base param_block -> ^(RECEIVE receive_base) param_block; receive_base : 'receive' '(' p=ID ',' o=ID (',' correlation)? ')' -> ^($p $o correlation?); reply : 'reply' '(' ID (',' ID ',' ID)? ')' -> ^(REPLY ID (ID ID)?); assign : path_expr '=' rvalue -> ^(ASSIGN path_expr rvalue); rvalue : receive_base -> ^(RECEIVE receive_base) | invoke | expr | xml_literal; throw_ex: 'throw' '('? ns_id ')'? -> ^(THROW ns_id); wait_ex : 'wait' '('expr')' -> ^(WAIT expr); compensate : 'compensate' ('(' ID ')')? -> ^(COMPENSATE ID?); exit : 'exit' -> ^(EXIT); // Others namespace : 'namespace' ID '=' STRING SEMI -> ^(NAMESPACE ID STRING); variables : 'var'! v+=variable (','! v+=variable)*; variable: ID VAR_MODS* -> ^(VARIABLE ID VAR_MODS*); partner_link : 'partnerLink' pl+=ID (',' pl+=ID)* -> ^(PARTNERLINK $pl+); correlation : '{' corr_mapping (',' corr_mapping)* '}' -> ^(CORRELATION corr_mapping+); corr_mapping : f1=ID ':' expr -> ^(CORR_MAP $f1 expr); funct : 'function'^ f=ID '(' ID? (','! ID)* ')' js_block; // Expressions expr : s_expr | EXT_EXPR | funct_call; funct_call : p+=ID '(' p+=ID* ')' -> ^(CALL ID+); // TODO add && || ! s_expr : condExpr; condExpr: aexpr ( ('==' ^|'!=' ^|'<' ^|'>' ^|'<=' ^|'>=' ^) aexpr )?; aexpr : mexpr (('+'|'-') ^ mexpr)*; mexpr : atom (('*'|'/') ^ atom)* | STRING; atom : path_expr | INT | '(' s_expr ')' -> s_expr; path_expr : pelmt+=ns_id ('.' pelmt+=ns_id)* -> ^(PATH $pelmt+); ns_id : (pr=ID '::')? loc=ID -> ^(NS $pr? $loc); // In-line XML xml_literal @init { LinkedListTree xml = null; } : // We have to have the LT in the outer grammar for lookahead // in AS3Parser to be able to predict that the xmlLiteral rule // should be used. '<' { xml=parseXMLLiteral(); } -> { xml }; js_block @init { LinkedListTree js = null; } : '{' { js=parseJSLiteral(); } -> { js }; EXT_EXPR : '[' (options {greedy=false;} : .)* ']'; // Basic tokens VAR_MODS: 'unique' | 'external' | ('string' | 'int' | 'float'); SEMI : ';'; ID : (LETTER | '_' ) (LETTER | DIGIT | '_' | '-' )*; INT : (DIGIT )+ ; STRING : '"' ( ESCAPE_SEQ | ~('\\'|'"') )* '"'; ESCAPE_SEQ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\'); SL_COMMENTS : ('#'|'//') .* CR { $channel = HIDDEN; }; CR : ('\r' | '\n' )+ { $channel = HIDDEN; }; WS : ( ' ' | '\t' )+ { skip(); }; fragment DIGIT : '0'..'9'; fragment LETTER : 'a'..'z' | 'A'..'Z';
tree grammar SimPELWalker; options { tokenVocab=SimPEL; ASTLabelType=LinkedListTree; } tokens { XML_ELEMENT; XML_ATTRIBUTE; XML_NAME; XML_ATTRIBUTE_VALUE; XML_TEXT; XML_WS; XML_COMMENT; XML_CDATA; XML_PI; } scope BPELScope { OScope oscope; } scope Parent { OBuilder.StructuredActivity activity; } scope ReceiveBlock { OPickReceive receive; } scope ExprContext { SimPELExpr expr; } @header { package org.apache.ode.simpel.antlr; import uk.co.badgersinfoil.e4x.antlr.LinkedListTree; import uk.co.badgersinfoil.e4x.antlr.LinkedListToken; import org.apache.ode.simpel.ErrorListener; import org.apache.ode.simpel.omodel.OBuilder; import org.apache.ode.simpel.omodel.SimPELExpr; import org.apache.ode.bpel.o.*; } @members { // Grammar level members private ErrorListener el; public void setErrorListener(ErrorListener el) { this.el = el; } public void displayRecognitionError(String[] tokenNames, RecognitionException e) { el.reportRecognitionError(tokenNames, e.line, getErrorMessage(e, tokenNames), e); } public String getErrorMessage(RecognitionException e, String[] tokenNames) { List stack = getRuleInvocationStack(e, this.getClass().getName()); String msg = null; if ( e instanceof NoViableAltException ) { NoViableAltException nvae = (NoViableAltException)e; msg = " no viable alt; token="+e.token+" (decision="+nvae.decisionNumber+" state "+nvae.stateNumber+")"+ " decision=<<"+nvae.grammarDecisionDescription+">>"; } else { msg = super.getErrorMessage(e, tokenNames); } return stack+" "+msg; } public String getTokenErrorDisplay(Token t) { return t.toString(); } // Lamguage level members private OBuilder builder = new OBuilder(); public OBuilder getBuilder() { return builder; } private String text(org.antlr.runtime.tree.Tree t) { if (t == null) return null; else return t.getText(); } private String deepText(org.antlr.runtime.tree.Tree t) { LinkedListTree llt = ((LinkedListTree)t); StringBuffer b = new StringBuffer(); LinkedListToken tok = ((LinkedListTree)t).getStartToken(); b.append(tok.getText()); while(tok != llt.getStopToken() && (tok = tok.getNext()) != null) if (tok.getText() != null) b.append(tok.getText()); return b.toString(); } } program : ^(ROOT declaration+); declaration : process | namespace; namespace : ^(NAMESPACE ID STRING); // Process process scope BPELScope Parent; : ^(PROCESS ^(NS pr=ID? nm=ID) { OBuilder.StructuredActivity<OScope> scope = builder.buildProcess(text($pr), text($nm)); $BPELScope::oscope = scope.getOActivity(); $Parent::activity = scope; } body); proc_stmt : pick | flow | if_ex | while_ex | until_ex | foreach | forall | try_ex | scope_ex | with_ex | invoke | receive | reply | assign | throw_ex | wait_ex | exit | signal | join | variable | partner_link; block scope Parent; : ^(SEQUENCE { OBuilder.StructuredActivity seq = builder.build(OSequence.class, $BPELScope::oscope, $Parent[-1]::activity); $Parent::activity = seq; } proc_stmt+); param_block scope Parent; : ^(SEQUENCE ID* { OBuilder.StructuredActivity seq = builder.build(OSequence.class, $BPELScope::oscope, $Parent[-1]::activity); $Parent::activity = seq; builder.setBlockParam($BPELScope::oscope, (OActivity) $Parent[-1]::activity.getOActivity(), $ID.text); } proc_stmt+); body : block | proc_stmt; // Structured activities pick : ^(PICK receive* timeout*); timeout : ^(TIMEOUT expr block); // TODO links flow : ^(FLOW body+); signal : ^(SIGNAL ID expr?); join : ^(JOIN ID+ expr?); if_ex : ^(IF expr body (^(ELSE body))?); while_ex : ^(WHILE expr body); until_ex : ^(UNTIL expr body); foreach : ^(FOREACH ID init=expr cond=expr assign body); forall : ^(FORALL ID from=expr to=expr body); try_ex scope BPELScope; : ^(TRY body catch_ex*); catch_ex: ^(CATCH ^(NS ID ID?) param_block); scope_ex scope BPELScope; : ^(SCOPE ID? body scope_stmt*); scope_stmt : event | alarm | compensation; event : ^(EVENT ID ID param_block); alarm : ^(ALARM expr body); compensation : ^(COMPENSATION body); with_ex : ^(WITH with_map+ body); with_map: ^(MAP ID path_expr); // Simple activities invoke : ^(INVOKE p=ID o=ID in=ID?); reply : ^(REPLY msg=ID (pl=ID var=ID)?) { builder.build(OReply.class, $BPELScope::oscope, $Parent::activity, $ReceiveBlock::receive, text($msg), text($pl), text($var)); }; receive scope ReceiveBlock; : ^(RECEIVE ^(p=ID o=ID correlation?)) { OBuilder.StructuredActivity<OPickReceive> rec = builder.build(OPickReceive.class, $BPELScope::oscope, $Parent::activity, text($p), text($o)); $ReceiveBlock::receive = rec.getOActivity(); } (prb=(param_block))?; assign scope ExprContext; : ^(ASSIGN { $ExprContext::expr = new SimPELExpr(builder.getProcess()); } lv=(path_expr) rv=(rvalue)) { $ExprContext::expr.setExpr(deepText($rv)); OBuilder.StructuredActivity<OAssign> assign = builder.build(OAssign.class, $BPELScope::oscope, $Parent::activity, deepText($lv), $ExprContext::expr); // The long, winding road of abstraction $ExprContext::expr = (SimPELExpr) ((OAssign.Expression)((OAssign.Copy)assign.getOActivity().operations.get(0)).from).expression; }; rvalue : receive | invoke | expr | xmlElement; throw_ex: ^(THROW ns_id); wait_ex : ^(WAIT expr); exit : EXIT; // Other variable: ^(VARIABLE ID VAR_MODS*); partner_link : ^(PARTNERLINK ID+); correlation : ^(CORRELATION corr_mapping+); corr_mapping : ^(CORR_MAP ID expr); // XML xmlElement : ^(XML_EMPTY_ELEMENT XML_NAME xmlAttribute*) | ^(XML_ELEMENT XML_NAME xmlAttribute* xmlElementContent*) { System.out.println("ELMT " + $XML_NAME.text); }; xmlAttribute : ^(XML_ATTRIBUTE XML_NAME XML_ATTRIBUTE_VALUE) { System.out.println("ATTR " + $XML_NAME.text); }; xmlElementContent : xmlMarkup | xmlText | xmlElement; xmlText : XML_TEXT | XML_NAME | XML_WS; xmlMarkup : XML_COMMENT | XML_CDATA | XML_PI; // Expressions expr : s_expr | EXT_EXPR | funct_call; funct_call : ^(CALL ID*); path_expr : ^(PATH ids=(ns_id+)) { builder.addExprVariable($BPELScope::oscope, $ExprContext::expr, deepText($ids)); }; ns_id : ^(NS ID? ID); s_expr : ^('==' s_expr s_expr) | ^('!=' s_expr s_expr) | ^('<' s_expr s_expr) | ^('>' s_expr s_expr) | ^('>=' s_expr s_expr) | ^('<=' s_expr s_expr) | ^('+' s_expr s_expr) | ^('-' s_expr s_expr) | ^('*' s_expr s_expr) | ^('/' s_expr s_expr) | path_expr | INT | STRING;