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;