/*
* 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 */