/* * OCL validator framework for models and MOF compliant metamodels. * Copyright (C) 2004 Fadi Chabarek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Package de.tuberlin.cs.cis.ocl.parser; Helpers unicode_character = [0..0xffff]; ascii_letter = ['A' .. 'Z'] | ['a' .. 'z']; digit = ['0'..'9']; ht = 0x0009; // tab lf = 0x000a; // linefeed ff = 0x000c; // formfeed cr = 0x000d; // carriage return sp = ' '; // space line_terminator = lf | cr | cr lf; /* [MOF1.4] S. 3-16: name: String - "To minimize portability problems * use names that start with ASCII letter, and consist of ASCII letters * and digits, space and underscore". * Seems rational, done! But spaces won't be allowed for parsing reasons. */ /* Actually this is not needed because of our definition of char_for_name(_top), * but for completness as helper function... */ inhibited_chars = ' ' | '"' | '#' | ''' |'(' | ')' | '*' | '+' | ',' | '-' | '.' | '/' | ':' | ';' | '<' | '=' | '>' | '@' | '[' | '\' | ']' | '{' | '|' | '}'; char_for_name_top = ascii_letter | '_'; char_for_name = char_for_name_top | digit; input_character = [unicode_character - [cr + lf]]; Tokens /* For a given input, the longest matching token will be returned by * the lexer. In the case of two matches of the same length, * the token listed first in the specification file will be returned. * Thus identifier should be the last token to avoid failures. */ white_space = (sp | ht | ff | line_terminator)*; end_of_line_comment = '--' input_character* line_terminator?; set = 'Set'; bag = 'Bag'; sequence = 'Sequence'; collection = 'Collection'; dot = '.'; arrow = '->'; not = 'not'; mult = '*'; div = '/'; plus = '+'; minus = '-'; context = 'context'; pre = 'pre'; post = 'post'; inv = 'inv'; def = 'def'; equal = '='; n_equal = '<>'; lt = '<'; gt = '>'; lteq = '<='; gteq = '>='; and = 'and'; or = 'or'; xor = 'xor'; implies = 'implies'; l_par = '('; r_par = ')'; l_bracket = '['; r_bracket = ']'; l_brace = '{'; r_brace = '}'; semicolon = ';'; dcolon = '::'; colon = ':'; comma = ','; at = '@'; bar = '|'; ddot = '..'; if = 'if'; then = 'then'; else = 'else'; endif = 'endif'; boolean_literal = 'true' | 'false'; let = 'let'; in = 'in'; package = 'package'; endpackage = 'endpackage'; number_literal = digit (digit)* // integer part ( '.' digit (digit)*)? // decimal places ( ('e' | 'E') ('+' | '-')? digit (digit)* )? // exponent part ; string_literal = ''' ([[[unicode_character - [cr + lf]] - '''] - '\'] | '\' ( // escape sequences 'n' | 't' | 'b' | 'r' | 'f' | '\' | ''' | '\"' // octal escape | (['0'..'7'] (['0'..'7'] (['0'..'7'])?)?) ) ) * ''' ; identifier = char_for_name_top char_for_name*; Ignored Tokens white_space, end_of_line_comment; Productions /************************************************************* file structure and declarations etc. *************************************************************/ ocl_file = ocl_package+; ocl_package = package package_name constraint* endpackage; package_name = path_name; // changed: replaces 'oclExpressions', kleenex operator // relocated to 'oclFile'. constraint = context_declaration context_bodypart+; context_bodypart = {definition} def name? colon let_expression* | {constraint} stereotype name? colon ocl_expression; context_declaration = context context_kind; context_kind = {operation} name dcolon context_operation_name l_par formal_parameter_list r_par return_type? | {classifier} name classifier_type?; return_type = colon type_specifier; classifier_type = colon name; stereotype = {pre_condition} pre | {post_condition} post | {invariant} inv; // changed: reuse of the predefined operator-productions (3) context_operation_name = name | {logical} logical_operator | {relational} relational_operator | {add} add_operator | {multiply} multiply_operator; formal_parameter_list = param_list?; param_list = formal_parameter next_param*; formal_parameter = name type_postfix; next_param = comma formal_parameter; property_call = path_name time_expression? qualifiers? property_call_parameters?; property_call_parameters = l_par declarator? actual_parameter_list? r_par ; actual_parameter_list = expression next_expr*; next_expr = comma expression; literal_collection = collection_kind l_brace collection_item_list r_brace; collection_item_list = collection_item next_collection_item*; next_collection_item = comma collection_item; collection_item = expression range?; range = ddot expression; // changed: production not LALR(1)-parsable (5) // workaround: names wrapped by expressions (actual_parameter_list) declarator = {concrete} actual_parameter_list simple_type_postfix? accumulator? bar | (name_list simple_type_postfix? accumulator? bar); accumulator = semicolon name colon type_specifier equal expression; name_list = name next_name*; next_name = comma name; simple_type_postfix = colon simple_type_specifier; qualifiers = l_bracket actual_parameter_list r_bracket; /************************************************************* expressions *************************************************************/ ocl_expression = let_declaration? expression; let_declaration = let_expression* in; let_expression = let name let_parameter_list? type_postfix? equal expression; let_parameter_list = l_par formal_parameter_list r_par; type_postfix = colon type_specifier; if_expression = if [condition] : expression then [then_branch] : expression else [else_branch] : expression endif ; expression = logical_expression; // changed 8) logical_expression = boolean_expression implication*; implication = implies_operator boolean_expression; // added 8) boolean_expression = relational_expression boolean_operation*; boolean_operation = boolean_operator relational_expression; // changed 9) relational_expression = compareable_expression equation?; equation = equation_operator compareable_expression; // added 9) compareable_expression = additive_expression comparison?; comparison = compare_operator additive_expression; additive_expression = multiplicative_expression addition*; addition = add_operator multiplicative_expression; multiplicative_expression = unary_expression multiplication*; multiplication = multiply_operator unary_expression; unary_expression = {prefixed} unary_operator postfix_expression | postfix_expression; postfix_expression = primary_expression property_invocation*; property_invocation = {object} dot property_call | {collection} arrow property_call; primary_expression = {collection} literal_collection | {literal} literal | {property_call} property_call | {parenthesed} l_par expression r_par | {if} if_expression; time_expression = at pre; /************************************************************* operators *************************************************************/ // changed 8) logical_operator = boolean_operator | {implicative} implies_operator; // added 8) boolean_operator = {and} and | {or} or | {xor} xor; // added 8) implies_operator = implies; relational_operator = {equality} equation_operator | {compare} compare_operator; equation_operator = equal | {in} n_equal; compare_operator = {gt} gt | {lt} lt | {gteq} gteq | {lteq} lteq; add_operator = {plus} plus | {minus} minus; multiply_operator = {mult} mult | {div} div; unary_operator = {minus} minus | {not} not; /************************************************************* types **************************************************************/ type_specifier = {ocl_any} simple_type_specifier | {collection} collection_type; collection_type = collection_kind l_par simple_type_specifier r_par; collection_kind = {set} set | {bag} bag | {sequence} sequence | collection ; simple_type_specifier = path_name; // changed: enum_literal is left out (6) boolean literal added (7) literal = {string} string_literal | {number} number_literal | {boolean} boolean_literal; /************************************************************* names *************************************************************/ name = identifier; // changed: takes place of enum_literal (2) // qualified_name = name contained_element+; // contained_element = dcolon name; path_name = name_qualifier* name; name_qualifier = name dcolon; /* removed: united with name (1) type_name = identifier */