/* * USE - UML based specification environment * Copyright (C) 1999-2004 Mark Richters, University of Bremen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $ProjectHeader: use 2-3-1-release.3 Wed, 02 Aug 2006 17:53:29 +0200 green $ */ // set package for all generated classes header { /* * USE - UML based specification environment * Copyright (C) 1999-2004 Mark Richters, University of Bremen * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.tzi.use.parser.use; } // ------------------------------------ // USE parser // ------------------------------------ { import java.util.List; import java.util.ArrayList; import java.util.HashMap; import java.io.PrintWriter; import org.tzi.use.parser.MyToken; import org.tzi.use.parser.ParseErrorHandler; import org.tzi.use.parser.ocl.*; } class GUSEParser extends GOCLParser; options { exportVocab = GUSE; defaultErrorHandler = true; buildAST = false; k = 5; //codeGenMakeSwitchThreshold = 2; //codeGenBitsetTestThreshold = 3; } // grammar start /* ------------------------------------ model ::= "model" id { enumTypeDefinition } { classDefinition | associationDefinition | "constraints" { invariant | prePost } } */ model returns [ASTModel n] { ASTEnumTypeDefinition e = null; ASTAssociation a = null; ASTConstraintDefinition cons = null; ASTPrePost ppc = null; n = null; } : "model" name:IDENT { n = new ASTModel((MyToken) name); } ( e=enumTypeDefinition { n.addEnumTypeDef(e); } )* ( ( generalClassDefinition[n] ) | ( a=associationDefinition { n.addAssociation(a); } ) | ( "constraints" ( cons=invariant { n.addConstraint(cons); } | ppc=prePost { n.addPrePost(ppc); } )* ) )* EOF ; /* ------------------------------------ enumTypeDefinition ::= "enum" id "{" idList "}" [ ";" ] */ enumTypeDefinition returns [ASTEnumTypeDefinition n] { List idList; n = null; } : "enum" name:IDENT LBRACE idList=idList RBRACE ( SEMI )? { n = new ASTEnumTypeDefinition((MyToken) name, idList); } ; /* ------------------------------------ generalClassDefinition ::= [ "abstract" ] { classDefinition | associationClassDefinition } */ generalClassDefinition[ASTModel n] { boolean isAbstract = false; ASTClass c = null; ASTAssociationClass ac = null;} : ( "abstract" { isAbstract = true; } )? ( ( c=classDefinition[isAbstract] { n.addClass(c); } ) | ( ac=associationClassDefinition[isAbstract] { n.addAssociationClass(ac); } ) ) ; /* ------------------------------------ classDefinition ::= [ "abstract" ] "class" id [ specialization ] [ attributes ] [ operations ] [ constraints ] "end" specialization ::= "<" idList attributes ::= "attributes" { attributeDefinition } operations ::= "operations" { operationDefinition } constraints ::= "constraints" { invariantClause } */ classDefinition[boolean isAbstract] returns [ASTClass n] { List idList; n = null; } : "class" name:IDENT { n = new ASTClass((MyToken) name, isAbstract); } ( LESS idList=idList { n.addSuperClasses(idList); } )? ( "attributes" { ASTAttribute a; } ( a=attributeDefinition { n.addAttribute(a); } )* )? ( "operations" { ASTOperation op; } ( op=operationDefinition { n.addOperation(op); } )* )? ( "constraints" ( { ASTInvariantClause inv; } inv=invariantClause { n.addInvariantClause(inv); } )* )? "end" ; /* ------------------------------------ associationClassDefinition ::= [ "abstract" ] "associationClass" id [ specialization ] [ attributes ] [ operations ] [ constraints ] [( "aggregation" | "composition" )] "between" associationEnd { associationEnd }+ "end" specialization ::= "<" idList attributes ::= "attributes" { attributeDefinition } operations ::= "operations" { operationDefinition } constraints ::= "constraints" { invariantClause } */ associationClassDefinition[boolean isAbstract] returns [ASTAssociationClass n] {List idList; n = null; ASTAssociationEnd ae; } : { MyToken t1 = (MyToken) LT(1); } ("associationClass"|"associationclass") { if (t1.getText().equals("associationClass")) { reportWarning("the 'associationClass' keyword is deprecated and will " + "not be supported in the future, use 'associationclass' instead"); } } name:IDENT { n = new ASTAssociationClass((MyToken) name, isAbstract); } ( LESS idList=idList { n.addSuperClasses(idList); } )? "between" ae=associationEnd { n.addEnd(ae); } ( ae=associationEnd { n.addEnd(ae); } )+ ( "attributes" { ASTAttribute a; } ( a=attributeDefinition { n.addAttribute(a); } )* )? ( "operations" { ASTOperation op; } ( op=operationDefinition { n.addOperation(op); } )* )? ( "constraints" ( { ASTInvariantClause inv; } inv=invariantClause { n.addInvariantClause(inv); } )* )? ( { MyToken t = (MyToken) LT(1); } ( "aggregation" | "composition" ) { n.setKind(t); } )? "end" ; /* ------------------------------------ attributeDefinition ::= id ":" type [ ";" ] */ attributeDefinition returns [ASTAttribute n] { ASTType t; n = null; } : name:IDENT COLON t=type ( SEMI )? { n = new ASTAttribute((MyToken) name, t); } ; /* ------------------------------------ operationDefinition ::= id paramList [ ":" type [ "=" expression ] ] { prePostClause } [ ";" ] */ operationDefinition returns [ASTOperation n] { List pl; ASTType t = null; ASTExpression e = null; ASTPrePostClause ppc = null; n = null; ASTALActionList al = null; } : name:IDENT pl=paramList ( COLON t=type )? (EQUAL e=expression )? ("begin" al=alActionList "end" )? { n = new ASTOperation((MyToken) name, pl, t, e,al); } ( ppc=prePostClause { n.addPrePostClause(ppc); } )* ( SEMI )? ; /* ------------------------------------ associationDefinition ::= ( "association" | "aggregation" | "composition" ) id "between" associationEnd associationEnd { associationEnd } "end" */ associationDefinition returns [ASTAssociation n] { ASTAssociationEnd ae; n = null; } : { MyToken t = (MyToken) LT(1); } ( "association" | "aggregation" | "composition" ) // ( classDefinition | (name:IDENT { n = new ASTAssociation(t, (MyToken) name); }) ) name:IDENT { n = new ASTAssociation(t, (MyToken) name); } "between" ae=associationEnd { n.addEnd(ae); } ( ae=associationEnd { n.addEnd(ae); } )+ "end" ; /* ------------------------------------ associationEnd ::= id "[" multiplicity "]" [ "role" id ] [ "ordered" ] [ ";" ] */ associationEnd returns [ASTAssociationEnd n] { ASTMultiplicity m; n = null; } : name:IDENT LBRACK m=multiplicity RBRACK { n = new ASTAssociationEnd((MyToken) name, m); } ( "role" rn:IDENT { n.setRolename((MyToken) rn); } )? ( "ordered" { n.setOrdered(); } )? ( SEMI )? ; /* ------------------------------------ multiplicity ::= multiplicityRange { "," multiplicityRange } multiplicityRange ::= multiplicitySpec [ ".." multiplicitySpec ] multiplicitySpec ::= "*" | INT */ multiplicity returns [ASTMultiplicity n] { ASTMultiplicityRange mr; n = null; } : { MyToken t = (MyToken) LT(1); // remember start position of expression n = new ASTMultiplicity(t); } mr=multiplicityRange { n.addRange(mr); } ( COMMA mr=multiplicityRange { n.addRange(mr); } )* ; multiplicityRange returns [ASTMultiplicityRange n] { int ms1, ms2; n = null; } : ms1=multiplicitySpec { n = new ASTMultiplicityRange(ms1); } ( DOTDOT ms2=multiplicitySpec { n.setHigh(ms2); } )? ; multiplicitySpec returns [int m] { m = -1; } : i:INT { m = Integer.parseInt(i.getText()); } | STAR { m = -1; } ; /* ------------------------------------ constraintDefinition ::= invariant | prePost */ // constraintDefinition returns [ASTConstraintDefinition n] // { n = null; } // : // n=invariant // | prePost // ; /* ------------------------------------ invariant ::= invariantContext invariantClause { invariantClause } invariantContext := "context" [ id ":" ] simpleType */ invariant returns [ASTConstraintDefinition n] { n = null; ASTType t = null; ASTInvariantClause inv = null; } : { n = new ASTConstraintDefinition(); } "context" ( v:IDENT COLON { n.setVarName((MyToken) v); } )? // requires k = 2 t=simpleType { n.setType(t); } ( inv=invariantClause { n.addInvariantClause(inv); } )* //+ ; /* ------------------------------------ invariantClause ::= "inv" [ id ] ":" expression */ invariantClause returns [ASTInvariantClause n] { ASTExpression e; n = null; } : "inv" ( name:IDENT )? COLON e=expression { n = new ASTInvariantClause((MyToken) name, e); } ; /* ------------------------------------ prePost ::= prePostContext prePostClause { prePostClause } prePostContext := "context" id "::" id paramList [ ":" type ] */ prePost returns [ASTPrePost n] { n = null; List pl = null; ASTType rt = null; ASTPrePostClause ppc = null; } : "context" classname:IDENT COLON_COLON opname:IDENT pl=paramList ( COLON rt=type )? { n = new ASTPrePost((MyToken) classname, (MyToken) opname, pl, rt); } ( ppc=prePostClause { n.addPrePostClause(ppc); } )+ ; /* ------------------------------------ prePostClause := ("pre" | "post") [ id ] ":" expression */ prePostClause returns [ASTPrePostClause n] { ASTExpression e; n = null; } : { MyToken t = (MyToken) LT(1); } ( "pre" | "post" ) ( name:IDENT )? COLON e=expression { n = new ASTPrePostClause(t, (MyToken) name, e); } ; alActionList returns [ASTALActionList al] { al = null; ASTALAction action = null; al = new ASTALActionList(); } : ( action=alAction {al.add(action);})* ; alAction returns [ASTALAction action] { action = null; } : action = alCreateVar | action = alDelete | action = alSet | action = alSetCreate | action = alInsert | action = alDestroy | action = alIf | action = alWhile | action = alFor | action = alExec ; alCreateVar returns [ASTALCreateVar var] { var = null; ASTType type = null; } : ("var"|"declare") name:IDENT COLON type=type { var = new ASTALCreateVar(name,type); } ; alSet returns [ASTALSet set] { set = null; ASTExpression lval = null; ASTExpression rval = null; } : "set" lval=expression COLON_EQUAL rval=expression { set = new ASTALSet(lval, rval); } ; alSetCreate returns [ASTALSetCreate setcreate] { setcreate = null; ASTExpression lval = null; ASTExpression nameExpr = null; } : "create" lval=expression COLON_EQUAL { LT(1).getText().equals("new") }? new_:IDENT cls:IDENT ( "namehint" nameExpr=expression )? { setcreate = new ASTALSetCreate(lval, (MyToken)cls, nameExpr);} ; alInsert returns [ASTALInsert insert] { ASTExpression e; List exprList = new ArrayList(); insert = null; } : "insert" LPAREN e=expression { exprList.add(e); } COMMA e=expression { exprList.add(e); } ( COMMA e=expression { exprList.add(e); } )* RPAREN "into" id:IDENT { insert = new ASTALInsert(exprList, (MyToken) id); } ; alDelete returns [ASTALDelete n] { ASTExpression e; List exprList = new ArrayList(); n = null; } : "delete" LPAREN e=expression { exprList.add(e); } COMMA e=expression { exprList.add(e); } ( COMMA e=expression { exprList.add(e); } )* RPAREN "from" id:IDENT { n = new ASTALDelete(exprList, (MyToken) id); } ; alDestroy returns [ASTALDestroy n] { ASTExpression e = null; n = null; } : "destroy" e=expression { n = new ASTALDestroy(e); } ; alIf returns [ASTALIf i] { i = null; ASTExpression ifexpr; ASTALActionList thenlist; ASTALActionList elselist=null; } : "if" ifexpr=expression "then" thenlist=alActionList ("else" elselist=alActionList)? "endif" { i = new ASTALIf(ifexpr,thenlist,elselist); } ; alWhile returns [ASTALWhile w] { w = null; ASTExpression expr; ASTALActionList body; } : "while" expr=expression "do" body=alActionList "wend" { w = new ASTALWhile(expr,body); } ; alFor returns [ASTALFor f] { f = null; ASTExpression expr; ASTALActionList body; ASTType type; } : "for" var:IDENT COLON type=type "in" expr=expression "do" body=alActionList { LT(1).getText().equals("next") }? next:IDENT { f = new ASTALFor(var,type,expr,body); } ; alExec returns [ASTALExecute c] { ASTExpression op; c=null; } : "execute" op=expression { c = new ASTALExecute(op); } ; // ------------------------------------ // USE lexer // ------------------------------------ { import java.io.PrintWriter; import org.tzi.use.util.Log; import org.tzi.use.util.StringUtil; import org.tzi.use.parser.ParseErrorHandler; import org.tzi.use.parser.MyToken; } class GUSELexer extends GOCLLexer; options { importVocab=GUSE; // MyLexer.reportError depends on defaultErrorHandler == true for // providing correct column number information defaultErrorHandler = true; // don't automatically test all tokens for literals testLiterals = false; k = 2; } { protected int fTokColumn = 1; private PrintWriter fErr; private ParseErrorHandler fParseErrorHandler; public void consume() throws CharStreamException { if (inputState.guessing == 0 ) { if (text.length() == 0 ) { // remember token start column fTokColumn = getColumn(); } } super.consume(); } public String getFilename() { return fParseErrorHandler.getFileName(); } protected Token makeToken(int t) { MyToken token = new MyToken(getFilename(), getLine(), fTokColumn); token.setType(t); if (t == EOF ) token.setText("end of file or input"); return token; } public void reportError(RecognitionException ex) { fParseErrorHandler.reportError( ex.getLine() + ":" + ex.getColumn() + ": " + ex.getMessage()); } /** * Returns true if word is a reserved keyword. */ public boolean isKeyword(String word) { ANTLRHashString s = new ANTLRHashString(word, this); boolean res = literals.get(s) != null; Log.trace(this, "keyword " + word + ": " + res); return res; } public void traceIn(String rname) throws CharStreamException { traceIndent(); traceDepth += 1; System.out.println("> lexer " + rname + ": c == '" + StringUtil.escapeChar(LA(1), '\'') + "'"); } public void traceOut(String rname) throws CharStreamException { traceDepth -= 1; traceIndent(); System.out.println("< lexer " + rname + ": c == '" + StringUtil.escapeChar(LA(1), '\'') + "'"); } public void init(ParseErrorHandler handler) { fParseErrorHandler = handler; } } // Whitespace -- ignored WS: ( ' ' | '\t' | '\f' | ( "\r\n" | '\r' | '\n' ) { newline(); } ) { $setType(Token.SKIP); } ; // Single-line comments SL_COMMENT: ("//" | "--") (~('\n'|'\r'))* ('\n'|'\r'('\n')?) { $setType(Token.SKIP); newline(); } ; // multiple-line comments ML_COMMENT: "/*" ( options { generateAmbigWarnings = false; } : { LA(2)!='/' }? '*' | '\r' '\n' { newline(); } | '\r' { newline(); } | '\n' { newline(); } | ~('*'|'\n'|'\r') )* "*/" { $setType(Token.SKIP); } ; // Use paraphrases for nice error messages //EOF options { paraphrase = "\"end of file\""; } : EOF; ARROW options { paraphrase = "'->'"; } : "->"; AT options { paraphrase = "'@'"; } : '@'; BAR options { paraphrase = "'|'"; } : '|'; COLON options { paraphrase = "':'"; } : ':'; COLON_COLON options { paraphrase = "'::'"; } : "::"; COLON_EQUAL options { paraphrase = "':='"; } : ":="; COMMA options { paraphrase = "','"; } : ','; DOT options { paraphrase = "'.'"; } : '.'; DOTDOT options { paraphrase = "'..'"; } : ".."; EQUAL options { paraphrase = "'='"; } : '='; GREATER options { paraphrase = "'>'"; } : '>'; GREATER_EQUAL options { paraphrase = "'>='"; } : ">="; HASH options { paraphrase = "'#'"; } : '#'; LBRACE options { paraphrase = "'{'"; } : '{'; LBRACK options { paraphrase = "'['"; } : '['; LESS options { paraphrase = "'<'"; } : '<'; LESS_EQUAL options { paraphrase = "'<='"; } : "<="; LPAREN options { paraphrase = "'('"; } : '('; MINUS options { paraphrase = "'-'"; } : '-'; NOT_EQUAL options { paraphrase = "'<>'"; } : "<>"; PLUS options { paraphrase = "'+'"; } : '+'; RBRACE options { paraphrase = "'}'"; } : '}'; RBRACK options { paraphrase = "']'"; } : ']'; RPAREN options { paraphrase = "')'"; } : ')'; SEMI options { paraphrase = "';'"; } : ';'; SLASH options { paraphrase = "'/'"; } : '/'; STAR options { paraphrase = "'*'"; } : '*'; protected INT: ('0'..'9')+ ; protected REAL: INT ( '.' INT )? ( ('e'|'E') ('+'|'-')? INT )? ; RANGE_OR_INT: ( INT ".." ) => INT { $setType(INT); } | ( INT '.' INT) => REAL { $setType(REAL); } | ( INT ('e'|'E')) => REAL { $setType(REAL); } | INT { $setType(INT); } ; // String literals STRING { char c1; StringBuffer s = new StringBuffer(); } : '\'' { s.append('\''); } ( c1=ESC { s.append(c1); } | c2:~('\''|'\\') { s.append(c2); } )* '\'' { s.append('\''); } { $setText(s.toString()); } ; // escape sequence -- note that this is protected; it can only be called // from another lexer rule -- it will not ever directly return a token to // the parser // There are various ambiguities hushed in this rule. The optional // '0'...'7' digit matches should be matched here rather than letting // them go back to STRING_LITERAL to be matched. ANTLR does the // right thing by matching immediately; hence, it's ok to shut off // the FOLLOW ambig warnings. protected ESC returns [char c] { c = 0; int h0,h1,h2,h3; } : '\\' ( 'n' { c = '\n'; } | 'r' { c = '\r'; } | 't' { c = '\t'; } | 'b' { c = '\b'; } | 'f' { c = '\f'; } | '"' { c = '"'; } | '\'' { c = '\''; } | '\\' { c = '\\'; } | ('u')+ h3=HEX_DIGIT h2=HEX_DIGIT h1=HEX_DIGIT h0=HEX_DIGIT { c = (char) (h0 + h1 * 16 + h2 * 16 * 16 + h3 * 16 * 16 * 16); } | o1:'0'..'3' { c = (char) Character.digit(o1, 8); } ( options { warnWhenFollowAmbig = false; } : o2:'0'..'7' { c = (char) (c * 8 + Character.digit(o2, 8)); } ( options { warnWhenFollowAmbig = false; } : o3:'0'..'7' { c = (char) (c * 8 + Character.digit(o3, 8)); } )? )? | d1:'4'..'7' { c = (char) Character.digit(d1, 8); } ( options { warnWhenFollowAmbig = false; } : d2:'0'..'7' { c = (char) (c * 8 + Character.digit(d2, 8)); } )? ) ; // hexadecimal digit (again, note it's protected!) protected HEX_DIGIT returns [int n] { n = 0; } : ( c1:'0'..'9' { n = Character.digit(c1, 16); } | c2:'A'..'F' { n = Character.digit(c2, 16); } | c3:'a'..'f' { n = Character.digit(c3, 16); } ) ; // An identifier. Note that testLiterals is set to true! This means // that after we match the rule, we look in the literals table to see // if it's a literal or really an identifer. IDENT options { testLiterals = true; paraphrase = "an identifier"; } : ('$' |'a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')* ; // A dummy rule to force vocabulary to be all characters (except // special ones that ANTLR uses internally (0 to 2) protected VOCAB: '\3'..'\377' ;