/*description: { This script parses an object modelling file that conform to \samp{CWML}, a modelling language proposed by \CodeWorker\ as an illustration. \samp{\textit{package_declaration} ::= \textbf{"package"} \textit{package_path} \textbf{'\{'} \textit{package_body} \textbf{'\}'}}\\ \samp{\textit{package_body} ::= \textit{package_declaration} | \textit{class_declaration} | \textit{service_declaration}}\\ \TODO\ } */ translation_unit ::= #ignore(C++) #continue [ package_declaration(this) | service_declaration(this) | component_declaration ]* #empty; package_declaration(myParentPackage : node) ::= #readIdentifier:"package" => local myPackage; #continue package_path:listOfPaths '{' => { ref myPackage = myParentPackage; foreach i in listOfPaths { insert myPackage.listOfPackages[i].name = i; if myPackage.sequence insert myPackage.listOfPackages[i].sequence = myPackage.sequence + "." + i; else insert myPackage.listOfPackages[i].sequence = i; ref myPackage = myPackage.listOfPackages[i]; } } [ package_declaration(myPackage) | class_declaration(myPackage) | service_declaration(myPackage) ]* '}'; package_path : list ::= #readIdentifier:package_path [['.' | "::"] #continue #readIdentifier:package_path]*; class_declaration(myPackage : node) : value ::= [class_modifier]?:myModifiers #readIdentifier:"class" #continue #readIdentifier:class_declaration => merge myPackage.listOfClasses[class_declaration] = myModifiers; => localref myClass = myPackage.listOfClasses[class_declaration]; => insert myClass.name = class_declaration; [parent_declaration(myClass)]? class_declaration_body(myClass) => { pushItem this.allClasses[class_declaration].packages; ref this.allClasses[class_declaration].packages#back = myPackage; insert myPackage.listOfClasses[class_declaration].sequence = myPackage.sequence; } [';']?; class_modifier : node ::= #readIdentifier:"abstract" => insert class_modifier.isAbstract = true; ; parent_declaration(myClass : node) ::= [ #readIdentifier:"extends" #continue #readIdentifier:myClass.extendedClass ]? [ #readIdentifier:"implements" #continue => pushItem myClass.listOfInterfaces; #readIdentifier:myClass.listOfInterfaces#back [ ',' #continue => pushItem myClass.listOfInterfaces; #readIdentifier:myClass.listOfInterfaces#back ]* ]? ; class_declaration_body(myClass : node) ::= '{' #continue [ attribute_declaration(myClass) | method_declaration(myClass) ]* '}'; service_declaration(myPackage : node) : value ::= #readIdentifier:"service" #continue #readIdentifier:service_declaration => insert myPackage.listOfServices[service_declaration].name = service_declaration; service_declaration_body(myPackage.listOfServices[service_declaration]) => { pushItem this.allServices[service_declaration].packages; ref this.allServices[service_declaration].packages#back = myPackage; insert myPackage.listOfServices[service_declaration].sequence = myPackage.sequence; } [';']? ; service_declaration_body(myService : node) ::= '{' #continue [method_declaration(myService)]* '}'; component_declaration ::= #readIdentifier:"component" #continue #readIdentifier:sName => if findElement(sName, this.listOfComponents) error("component '" + sName + "' has already been declared"); => insert this.listOfComponents[sName].name = sName; => localref theComponent = this.listOfComponents[sName]; '{' [ #readIdentifier:{"client", "server"}:sSide #continue ':' #readIdentifier:sService // ['.' #continue #readIdentifier]? => if !this.allServices.findElement(sService) error("unrecognized service '" + sService + "'"); => if sSide == "client" insert theComponent.client[sService] = sService; else insert theComponent.server[sService] = sService; [ ',' #continue #readIdentifier:sService // ['.' #continue #readIdentifier]? => if !this.allServices.findElement(sService) error("unrecognized service '" + sService + "'"); => if sSide == "client" insert theComponent.client[sService] = sService; else insert theComponent.server[sService] = sService; ]* ';' ]* '}' [';']? ; type_specifier(myType : node) ::= [ base_type_specifier(myType) | container_type_specifier(myType) | class_type(myType) ] [array_specifier(myType)]*; base_type_specifier(myType : node) ::= numeric_type(myType) | #readIdentifier:{"char", "string", "date", "bool", "boolean"}:myType.name => if myType.name == "bool" set myType.name = "boolean"; ; numeric_type(myType : node) ::= [numeric_type_modifier(myType)]? #readIdentifier:{"byte", "short", "long", "int", "float", "double"}:myType.name; numeric_type_modifier(myType : node) ::= #readIdentifier:{"positive", "negative"}:sModifier => { if sModifier == "positive" insert myType.isPositive = true; else insert myType.isNegative = true; } ; class_type(myType : node) ::= #readIdentifier:thePath[0] [ ['.' | "::"] #continue => pushItem thePath; #readIdentifier:thePath#back ]* => { if thePath.size() == 1 { insert myType.name = thePath#back; insert myType.isObject = true; } else { error("'class_type' with scope (" + thePath.size() + " elements) not implemented yet"); } if !findElement(myType.name, this.allClasses) error("invalid class type '" + myType.name + "'"); }; container_type_specifier(myType : node) ::= #readIdentifier:{"list", "map", "vector"}:myType.name '<' #continue [ #check(myType.name == "map") #continue base_type_specifier(myType.keyType) ',' ]? type_specifier(myType.elementType) '>'; array_specifier(myType : node) ::= '[' ']' => { slideNodeContent(myType, elementType); if myType.elementType.isObject insert myType.isObject = true; insert myType.isArray = true; }; method_declaration(myClass : node) ::= [method_pre_modifier(myModifiers)]* type_specifier(myType) #readIdentifier:sName '(' #continue [ #pushItem(listOfParameters) parameter_declaration:listOfParameters#back [ ',' #continue => pushItem listOfParameters; parameter_declaration:listOfParameters#back ]* ]? ')' [method_post_modifier(myModifiers)]? =>{ local sKey = sName; setall myClass.listOfMethods[sKey] = myModifiers; insert myClass.listOfMethods[sKey].name = sName; setall myClass.listOfMethods[sKey].listOfParameters = listOfParameters; setall myClass.listOfMethods[sKey].type = myType; } ';'; method_pre_modifier(myModifiers : node) ::= #readIdentifier:{"synchronized", "abstract", "final"}:sModifier => { if sModifier == "synchronized" insert myModifiers.isSynchronized = true; else if sModifier == "abstract" insert myModifiers.isAbstract = true; else if sModifier == "final" insert myModifiers.isFinal = true; }; method_post_modifier(myModifiers : node) ::= #readIdentifier:"const" => insert myModifiers.isConst = true; ; parameter_declaration : node ::= parameter_type_specifier(parameter_declaration.type) #continue #readIdentifier:parameter_declaration.name; parameter_type_specifier(myType : node) ::= [parameter_type_modifier(myType)]* type_specifier(myType); parameter_type_modifier(myType : node) : node ::= #readIdentifier:{"const", "synchronized"}:sModifier => { if sModifier == "const" insert myType.isConst = true; else if sModifier == "synchronized" insert myType.isSynchronized = true; }; attribute_declaration(myClass : node) ::= attribute_type_specifier(myType) #readIdentifier:sName #continue ['=' #continue literal:myClass.listOfAttributes[sName].default]? ';' => { insert myClass.listOfAttributes[sName].name = sName; setall myClass.listOfAttributes[sName].type = myType; }; attribute_type_specifier(myType : node) ::= [attribute_type_modifier(myModifiers)]* type_specifier(myType) => merge myType = myModifiers; ; attribute_type_modifier(myModifier : node) ::= #readIdentifier:{"aggregate", "const", "readonly", "transient", "pertinent", "synchronized", "pkey", "optional"}:sModifier => switch(sModifier) { case "aggregate": insert myModifier.isAggregate = true;break; case "const": insert myModifier.isConst = true;break; case "readonly": insert myModifier.isReadOnly = true;break; case "transient": insert myModifier.isTransient = true;break; case "pertinent": insert myModifier.isPertinent = true;break; case "synchronized": insert myModifier.isSynchronized = true;break; case "pkey": insert myModifier.isPrimaryKey = true;break; case "optional": insert myModifier.isOptional = true;break; }; literal ::= integer_literal | string_literal | character_literal | numeric_literal | boolean_literal; boolean_literal ::= #readIdentifier:{"true", "false"}; integer_literal ::= INT | OCTAL | HEX; string_literal ::= [STRING_LITERAL]+; character_literal ::= CHAR_LITERAL; numeric_literal ::= FLOAT; /* COMMON LEXICAL RULES */ OR ::= '|'; XOR ::= '^'; AND ::= '&'; NOT ::= '!'; LT ::= '<'; LSHIFT ::= "<<"; GT ::= '>'; RSHIFT ::= ">>"; DIV ::= '/'; PLUS ::= '+'; MINUS ::= '-'; TILDE ::= '~'; STAR ::= '*'; MOD ::= '%'; CHAR_LITERAL ::= #!ignore '\'' [ESC | ~'\''] '\''; ESC ::= #!ignore '\\' ['n' | 't' | 'v' | 'b' | 'r' | 'f' | 'a' | '\\' | '?' | '\'' | '"' | HEX | OCTAL]; DIGIT ::= '0'..'9'; OCTDIGIT ::= '0'..'7'; HEXDIGIT ::= '0'..'9' | 'a'..'f' | 'A'..'F'; OCTAL ::= #!ignore ['0'..'3'] [OCTDIGIT]*; HEX ::= #!ignore ["0x" | "0X"] [HEXDIGIT]+; INT ::= #!ignore [DIGIT]+; FLOAT ::= #!ignore [ '.' [DIGIT]+ | [DIGIT]+ '.' [DIGIT]* ] [['e' | 'E'] ['+' | '-']? [DIGIT]+]?;