Commit 0ebeef6e authored by dbarbera's avatar dbarbera
Browse files

Added unary expressions nodes

parent 0d5c683e
......@@ -723,8 +723,7 @@ def _primary_variable(prim):
''' Single variable reference '''
sep = u'l_' if find_var(prim.value[0]) else u''
string = u'{sep}{name}'.format(sep=sep, name=prim.value[0])
ada_string = unary(prim, string)
ada_string = u'{sep}{name}'.format(sep=sep, name=prim.value[0])
if prim.exprType.__name__ == 'for_range':
# Ada iterator in FOR loops is an Integer - we must cast to 64 bits
......@@ -896,7 +895,6 @@ def _prim_path(primary_id):
ada_string += ', '.join(list_of_params)
ada_string += ')'
sep = '.'
ada_string = unary(primary_id, ada_string)
return stmts, ada_string, local_decl
......@@ -924,7 +922,6 @@ def _basic_operators(expr):
code.extend(right_stmts)
local_decl.extend(left_local)
local_decl.extend(right_local)
ada_string = unary(expr, ada_string)
return code, ada_string, local_decl
......@@ -964,7 +961,18 @@ def _bitwise_operators(expr):
code.extend(right_stmts)
local_decl.extend(left_local)
local_decl.extend(right_local)
ada_string = unary(expr, ada_string)
return code, ada_string, local_decl
@expression.register(ogAST.ExprNot)
@expression.register(ogAST.ExprNeg)
def _unary_operator(expr):
''' Generate the code for an unary expression '''
code, local_decl = [], []
expr_stmts, expr_str, expr_local = expression(expr.expr)
ada_string = u'({op} {expr})'.format(op=expr.operand, expr=expr_str)
code.extend(expr_stmts)
local_decl.extend(expr_local)
return code, ada_string, local_decl
......@@ -1090,8 +1098,11 @@ def _choice_determinant(primary):
@expression.register(ogAST.PrimReal)
def _integer(primary):
''' Generate code for a raw numerical value '''
ada_string = primary.value[0]
ada_string = unary(primary, ada_string)
if float(primary.value[0]) < 0:
# Parentesize negative integers for maintaining the precedence in the generated code
ada_string = '({})'.format(primary.value[0])
else:
ada_string = primary.value[0]
return [], ada_string, []
......@@ -1099,7 +1110,6 @@ def _integer(primary):
def _integer(primary):
''' Generate code for a raw boolean value '''
ada_string = primary.value[0]
ada_string = unary(primary, ada_string)
return [], ada_string, []
......@@ -1514,25 +1524,6 @@ def _inner_procedure(proc):
return code, local_decl
# A few helper functions needed by the Ada backend
def unary(expr, string):
''' Check for NOT or MINUS unary operators and add them to the string '''
op_minus = getattr(expr, 'op_minus', False)
op_not = getattr(expr, 'op_not', False)
try:
float_val = float(string)
except ValueError:
float_val = 1
if op_minus and float_val > 0:
string = u'(-{})'.format(string)
elif float_val <= 0:
string = u'({})'.format(string)
if op_not:
string = u'not {}'.format(string)
return string
def find_basic_type(a_type):
''' Return the ASN.1 basic type of a_type '''
basic_type = a_type
......
......@@ -127,6 +127,14 @@ class ExprRem(Expression):
operand = 'rem'
class ExprNot(Expression):
operand = 'not'
class ExprNeg(Expression):
operand = '-'
class ExprAssign(Expression):
operand = ':='
......@@ -157,16 +165,12 @@ class Primary(Expression):
self.inputString = primary.inputString
self.line = primary.line
self.charPositionInLine = primary.charPositionInLine
self.op_not = primary.op_not
self.op_minus = primary.op_minus
self.value = primary.value
self.exprType = primary.exprType
else:
self.inputString = inputString
self.line = line
self.charPositionInLine = charPositionInLine
self.op_not = False
self.op_minus = False
self.value = None
self.exprType = None
......
......@@ -61,6 +61,8 @@ OPKIND = {lexer.PLUS: ogAST.ExprPlus,
lexer.APPEND: ogAST.ExprAppend,
lexer.IN: ogAST.ExprIn,
lexer.REM: ogAST.ExprRem,
lexer.NOT: ogAST.ExprNot,
lexer.NEG: ogAST.ExprNeg,
lexer.PRIMARY: ogAST.Primary}
# Insert current path in the search list for importing modules
......@@ -454,7 +456,7 @@ def check_and_fix_op_params(op_name, expr_list, context):
def check_range(typeref, type_to_check):
''' Verify the that the Min/Max bounds of two types are compatible
Called to test that assignments are withing allowed range
both types assumed to be basic types
both types assumed to be basic types
'''
try:
if float(type_to_check.Min) < float(typeref.Min) \
......@@ -861,8 +863,28 @@ def find_type(path, context):
return result
def fix_expression_type(expr, context):
''' Check/ensure type consistency in unary expressions '''
if expr.expr.exprType == UNKNOWN_TYPE \
and isinstance(expr.expr, ogAST.PrimPath) \
and len(expr.expr.value) == 1:
try:
exprType = find_variable(expr.expr.value[0], context)
# Differentiate DCL and FPAR variables
use_type = ogAST.PrimVariable
if isinstance(context, ogAST.Procedure):
for each in context.fpar:
if each['name'].lower() == expr.expr.value[0].lower():
use_type = ogAST.PrimFPAR
break
expr.expr = use_type(primary=expr.expr)
expr.expr.exprType = exprType
except AttributeError:
pass
def fix_expression_types(expr, context):
''' Check/ensure type consistency in expressions having two sides '''
''' Check/ensure type consistency in binary expressions '''
if isinstance(expr, ogAST.Primary):
return
......@@ -1249,14 +1271,9 @@ def primary(root, context):
''' Process a primary (-/NOT value) '''
warnings = []
errors = []
op_not, op_minus = False, False
prim = None
for child in root.getChildren():
if child.type == lexer.NOT:
op_not = True
elif child.type == lexer.MINUS:
op_minus = True
elif child.type == lexer.PRIMARY_ID:
if child.type == lexer.PRIMARY_ID:
# Variable reference, indexed values, or ASN.1 value notation
prim, err, warn = primary_value(child, context=context)
errors.extend(err)
......@@ -1292,10 +1309,6 @@ def primary(root, context):
prim.inputString = get_input_string(root)
prim.line = root.getLine()
prim.charPositionInLine = root.getCharPositionInLine()
if op_not:
prim.op_not = True
if op_minus:
prim.op_minus = True
return prim, errors, warnings
......@@ -1325,7 +1338,7 @@ def expression(root, context):
root.children.pop(idx)
break
# Binary expressions
if root.type in (lexer.PLUS,
lexer.ASTERISK,
lexer.DASH,
......@@ -1374,6 +1387,15 @@ def expression(root, context):
format(expr.inputString, str(report)))
expr = new_expr
# Unary expressions
elif root.type in (lexer.NOT, lexer.NEG):
child = root.getChildren()[0]
expr.expr, err_expr, warn_expr = expression(child, context)
errors.extend(err_expr)
warnings.extend(warn_expr)
fix_expression_type(expr, context)
if root.type in (lexer.EQ,
lexer.NEQ,
lexer.GT,
......@@ -1414,7 +1436,6 @@ def expression(root, context):
errors.append('Check that all your numerical data types have '
'a range constraint')
elif root.type in (lexer.OR, lexer.AND, lexer.XOR):
# in the case of bitwise operators, if both sides are arrays,
# then the result is an array too
......@@ -1425,15 +1446,22 @@ def expression(root, context):
else:
expr.exprType = expr.left.exprType
elif root.type in (lexer.PLUS,
lexer.ASTERISK,
lexer.DASH,
lexer.DIV,
lexer.APPEND,
lexer.REM,
lexer.MOD):
elif root.type == lexer.NOT:
basic = find_basic_type(expr.expr.exprType)
if basic.kind == 'BooleanType':
expr.exprType = BOOLEAN
else:
expr.exprType = expr.expr.exprType
elif root.type == lexer.APPEND:
expr.exprType = expr.left.exprType
elif root.type == lexer.NEG:
basic = find_basic_type(expr.expr.exprType)
attrs = {'Min': str(-float(basic.Max)),
'Max': str(-float(basic.Min))}
expr.exprType = type('Neg', (basic,), attrs)
if root.type == lexer.PRIMARY:
expr, err, warn = primary(root, context)
if not expr:
......@@ -1927,15 +1955,15 @@ def text_area_content(root, ta_ast, context):
elif child.type == lexer.SYNONYM_LIST:
err, warn = synonym(child, ta_ast, context)
errors.extend(err)
warnings.extend(warn)
warnings.extend(warn)
elif child.type == lexer.NEWTYPE:
err, warn = newtype(child, ta_ast, context)
errors.extend(err)
warnings.extend(warn)
warnings.extend(warn)
elif child.type == lexer.SYNTYPE:
err, warn = syntype(child, ta_ast, context)
errors.extend(err)
warnings.extend(warn)
warnings.extend(warn)
elif child.type == lexer.PROCEDURE:
proc, err, warn = procedure(child, context=context)
errors.extend(err)
......
/*
/*
OpenGEODE
ANTLR 3.1.3 grammar for the SDL92 langage
Includes the following features from SDL2000+:
......@@ -89,7 +89,7 @@ tokens {
VARIABLES;
SORT;
DCL;
MINUS;
NEG;
GROUND;
TEXTAREA;
TEXTAREA_CONTENT;
......@@ -183,7 +183,7 @@ route
block_definition
: BLOCK block_id end
entity_in_block*
entity_in_block*
ENDBLOCK end
-> ^(BLOCK block_id entity_in_block*);
......@@ -456,7 +456,7 @@ enabling_condition
continuous_signal
: PROVIDED expression end
: PROVIDED expression end
(PRIORITY integer_literal_name=INT end)?
transition
-> ^(PROVIDED expression $integer_literal_name? transition);
......@@ -491,7 +491,7 @@ signal_item
signal_list_id |
timer_id;*/
/* Not considered for the moment
/* Not considered for the moment
(irrelevant in the scope of the generation of code for a single process)
priority_input
: PRIORITY INPUT priority_input_list end transition;
......@@ -576,7 +576,7 @@ procedure_call
procedure_call_body
: procedure_id actual_parameters?
: procedure_id actual_parameters?
-> ^(OUTPUT_BODY procedure_id actual_parameters?);
......@@ -685,7 +685,7 @@ constant
create_request
: CREATE
: CREATE
createbody
actual_parameters?
end
......@@ -712,7 +712,7 @@ outputbody
outputstmt
: signal_id
: signal_id
actual_parameters?;
to_part
......@@ -795,20 +795,30 @@ variable
field_selection
: (('!'|'.') field_name);
expression : operand0 ( IMPLIES^ operand0)* ;
operand0 : operand1 (( (OR^ ELSE?) | XOR^ ) operand1)*;
operand1 : operand2 ( AND^ THEN? operand2)*;
operand2 : operand3
(( EQ^ | NEQ^ | GT^ | GE^ | LT^ | LE^ | IN^ )
operand3)*;
operand3 : operand4 (( PLUS^ | DASH^ | APPEND^ ) operand4)*;
operand4 : operand5
(( ASTERISK^ | DIV^ | MOD^ | REM^ ) operand5)*;
operand5 : primary_qualifier? primary
-> ^(PRIMARY primary_qualifier? primary);
expression
: operand0 ( IMPLIES^ operand0)* ;
operand0
: operand1 (( (OR^ ELSE?) | XOR^ ) operand1)*;
operand1
: operand2 ( AND^ THEN? operand2)*;
operand2
: operand3 (( EQ^ | NEQ^ | GT^ | GE^ | LT^ | LE^ | IN^ ) operand3)*;
operand3
: operand4 (( PLUS^ | DASH^ | APPEND^ ) operand4)*;
// primary below covers all cases including ASN.1 Value Notation
operand4
: operand5 (( ASTERISK^ | DIV^ | MOD^ | REM^ ) operand5)*;
operand5
: primary -> ^(PRIMARY primary)
| NOT^ operand5
| DASH operand5 -> ^(NEG operand5);
// primary below covers all cases including ASN.1 Value Notation
primary
: a=asn1Value primary_params*
-> ^(PRIMARY_ID asn1Value primary_params*)
......@@ -833,7 +843,7 @@ asn1Value
| L_BRACKET
MANTISSA mant=INT COMMA
BASE bas=INT COMMA
EXPONENT exp=INT
EXPONENT exp=INT
R_BRACKET -> ^(FLOAT2 $mant $bas $exp)
| choiceValue
| L_BRACKET
......@@ -859,7 +869,7 @@ informal_text
// hello:5 (CHOICE field value)
choiceValue
choiceValue
: choice=ID ':' expression
-> ^(CHOICE $choice expression);
......@@ -869,12 +879,6 @@ namedValue
: ID expression;
primary_qualifier
: DASH
-> ^(MINUS)
| NOT;
primary_params
: '(' expression_list ')'
-> ^(PARAMS expression_list)
......@@ -882,7 +886,7 @@ primary_params
-> ^(FIELD_NAME literal_id);
/* All cases are covered by the ground primary
/* All cases are covered by the ground primary
above (Except structure primary, but we favour ASN.1 notation)
extended_primary
: synonym |
......@@ -960,7 +964,7 @@ operator_application
: operator_id '('active_expression_list ')';
active_expression_list
active_expression_list
: active_expression (',' expression_list)?;/* |
ground_expression ',' active_expression_list;*/ // Will not work (recursion)
/*
......@@ -990,7 +994,7 @@ conditional_ground_expression
-> ^(IFTHENELSE $ifexpr $thenexpr $elseexpr);
expression_list
expression_list
: expression (',' expression)*
-> expression+;
......@@ -1048,7 +1052,7 @@ cif
: cif_decl symbolname
L_PAREN x=INT COMMA y=INT R_PAREN
COMMA
L_PAREN width=INT COMMA height=INT R_PAREN
L_PAREN width=INT COMMA height=INT R_PAREN
cif_end
-> ^(CIF $x $y $width $height);
......@@ -1060,7 +1064,7 @@ hyperlink
/* OpenGEODE specific: SDL does not allow specifying the name
of signal parameters, but it is needed to generate function signatures
when generating code (in particular in Ada, where the name in the
when generating code (in particular in Ada, where the name in the
body must comply with the one of the source
Extension is using CIF comment so it is invisible to other SDL parsers
(This is valid SDL code - see ITU-T Z106)
......@@ -1273,13 +1277,13 @@ ENDBLOCK : E N D B L O C K;
SIGNALROUTE : S I G N A L R O U T E;
CONNECT : C O N N E C T;
SYNTYPE : S Y N T Y P E;
ENDSYNTYPE : E N D S Y N T Y P E;
ENDSYNTYPE : E N D S Y N T Y P E;
NEWTYPE : N E W T Y P E;
ENDNEWTYPE : E N D N E W T Y P E;
ARRAY : A R R A Y;
ARRAY : A R R A Y;
CONSTANTS : C O N S T A N T S;
STRUCT : S T R U C T;
SYNONYM : S Y N O N Y M;
SYNONYM : S Y N O N Y M;
IMPORT : I M P O R T;
VIEW : V I E W;
ACTIVE : A C T I V E;
......
This diff is collapsed.
This diff is collapsed.
/* CIF PROCESS (148, 150), (150, 75) */
PROCESS myfunction;
/* CIF TEXT (0, 17), (296, 428) */
/* CIF TEXT (0, 17), (296, 456) */
-- Timers defined in the interface view
-- Use SET_TIMER (value, timer name)
-- and RESET_TIMER (timer name) in a
......@@ -22,7 +22,7 @@ dcl someInt t_uInt8 := 2;
dcl otherint T_uint8 := 1;
-- To test 'op_not'
dcl opnot T_boolean := not true;
dcl opnot T_boolean := false;
-- To test writeln with octet strings
dcl str MyOctStr := 'abc';
dcl variable_str String := 'Hello!';
......@@ -33,7 +33,7 @@ dcl bar SeqInt := { 1,1 };
/* CIF PROCEDURE (1172, 490), (91, 35) */
PROCEDURE factorial;
/* CIF TEXT (29, 42), (215, 53) */
fpar in N MyInteger,
fpar in N MyInteger,
in/out result MyInteger;
/* CIF ENDTEXT */
/* CIF START (298, 33), (70, 35) */
......@@ -49,14 +49,14 @@ endfor;
ENDPROCEDURE;
/* CIF START (591, 0), (100, 50) */
START;
/* CIF PROCEDURECALL (553, 65), (175, 35) */
/* CIF PROCEDURECALL (552, 65), (176, 35) */
CALL writeln(-(someint + 1))
/* CIF COMMENT (748, 65), (226, 38) */
/* CIF COMMENT (748, 65), (227, 40) */
COMMENT 'Test unary on expression result
should display -3';
/* CIF PROCEDURECALL (542, 115), (197, 35) */
CALL writeln(not(true or false))
/* CIF COMMENT (759, 115), (187, 38) */
/* CIF COMMENT (759, 115), (187, 40) */
COMMENT 'test unary on expression
should display FALSE';
/* CIF PROCEDURECALL (586, 165), (110, 35) */
......@@ -69,15 +69,15 @@ should display FALSE';
COMMENT 'Write again to check local variables';
/* CIF PROCEDURECALL (558, 265), (165, 35) */
CALL writeln(variable_str)
/* CIF COMMENT (743, 265), (275, 35) */
/* CIF COMMENT (743, 265), (278, 35) */
COMMENT 'Write a non-fixed length OCTET STRING';
/* CIF PROCEDURECALL (541, 315), (199, 38) */
CALL writeln(variable_str // '!!!')
/* CIF COMMENT (760, 316), (117, 35) */
/* CIF COMMENT (760, 316), (119, 35) */
COMMENT 'with APPEND';
/* CIF PROCEDURECALL (465, 368), (352, 35) */
CALL writeln(if someint>0 then variable_str else other fi)
/* CIF COMMENT (837, 368), (275, 35) */
/* CIF COMMENT (837, 368), (278, 35) */
COMMENT 'Write a non-fixed lenght OCTET STRING';
/* CIF PROCEDURECALL (552, 418), (177, 35) */
CALL writeln(1 + (-otherint))
......@@ -85,17 +85,17 @@ should display FALSE';
COMMENT 'Test the op_minus in a sub-expression';
/* CIF PROCEDURECALL (430, 468), (421, 35) */
CALL writeln(-someint, if someint>0 then ' is ' else 'Foo' fi, not true)
/* CIF COMMENT (871, 468), (291, 35) */
/* CIF COMMENT (871, 468), (292, 35) */
COMMENT 'Various tests with strings, ternary, op_not';
/* CIF PROCEDURECALL (514, 518), (254, 35) */
CALL write(if someint>0 then 2 else 1 fi)
/* CIF COMMENT (788, 518), (220, 35) */
/* CIF COMMENT (788, 518), (221, 35) */
COMMENT 'test ternary with raw numbers';
/* CIF PROCEDURECALL (496, 568), (289, 35) */
CALL write(if someint>0 then someint else 1 fi)
/* CIF COMMENT (805, 568), (308, 35) */
/* CIF COMMENT (805, 568), (310, 35) */
COMMENT 'test ternary with mixed variable/raw number';
/* CIF PROCEDURECALL (577, 618), (128, 35) */
/* CIF PROCEDURECALL (576, 618), (129, 35) */
CALL writeln(bar(1))
/* CIF COMMENT (725, 618), (100, 35) */
COMMENT 'test index';
......@@ -103,63 +103,63 @@ should display FALSE';
CALL writeln(opnot, ' ', not opnot)
/* CIF COMMENT (769, 668), (191, 35) */
COMMENT 'test op_not with variable';
/* CIF TASK (480, 718), (321, 35) */
/* CIF TASK (478, 718), (324, 35) */
TASK someInt := if someint = 0 then someint else 0 fi;
/* CIF DECISION (504, 768), (273, 87) */
/* CIF DECISION (501, 768), (278, 87) */
DECISION someint /=0 and then (10 / someInt > 0)
or else someint = 0
/* CIF COMMENT (793, 777), (179, 68) */
/* CIF COMMENT (795, 777), (179, 72) */
COMMENT 'Using "and else" is the
short-circuit form. The
second part should not
be evaluated.';
/* CIF ANSWER (561, 875), (70, 23) */
/* CIF ANSWER (561, 875), (70, 24) */
(true):
/* CIF TASK (541, 913), (110, 35) */
/* CIF TASK (540, 914), (111, 35) */
TASK someInt := 2;
/* CIF PROCEDURECALL (537, 963), (117, 38) */
/* CIF PROCEDURECALL (536, 964), (118, 38) */
CALL writeln('OK');
/* CIF ANSWER (664, 875), (70, 23) */
/* CIF ANSWER (662, 875), (70, 24) */
(false):
ENDDECISION;
/* CIF NEXTSTATE (608, 1016), (65, 33) */
/* CIF NEXTSTATE (605, 1017), (68, 33) */
NEXTSTATE Wait;
/* CIF STATE (608, 1016), (65, 33) */
/* CIF STATE (605, 1017), (68, 33) */
STATE Wait;
/* CIF INPUT (865, 1069), (89, 33) */
/* CIF INPUT (863, 1070), (90, 33) */
INPUT mytimer;
/* CIF PROCEDURECALL (818, 1117), (182, 33) */
/* CIF PROCEDURECALL (818, 1118), (182, 33) */
CALL writeln('timer expired');
/* CIF PROCEDURECALL (829, 1165), (160, 33) */
/* CIF PROCEDURECALL (828, 1166), (161, 33) */
CALL factorial(3, someint);
/* CIF NEXTSTATE (877, 1213), (65, 33) */
/* CIF NEXTSTATE (874, 1214), (68, 33) */
NEXTSTATE Wait;
/* CIF INPUT (421, 1069), (181, 33) */
/* CIF INPUT (421, 1070), (181, 33) */
INPUT start_something (toto);
/* CIF OUTPUT (376, 1117), (270, 33) */
/* CIF OUTPUT (373, 1118), (275, 33) */
OUTPUT result_data((toto+1) mod 2147483647);
/* CIF PROCEDURECALL (436, 1165), (150, 48) */
/* CIF PROCEDURECALL (436, 1166), (150, 48) */
CALL writeln
('Hello Toto', toto);
/* CIF PROCEDURECALL (413, 1228), (196, 33) */
/* CIF PROCEDURECALL (412, 1229), (198, 33) */
CALL set_timer(1000, myTimer);
/* CIF TASK (346, 1276), (330, 35) */
/* CIF TASK (346, 1277), (330, 35) */
TASK largeReal := power(someReal, 2);
/* CIF PROCEDURECALL (282, 1326), (458, 35) */
/* CIF PROCEDURECALL (282, 1327), (458, 35) */
CALL writeln(someReal, ' ** 2' , ' == ', largeReal, ' (should be 2.25 )');
/* CIF TASK (411, 1376), (201, 35) */
/* CIF TASK (410, 1377), (201, 35) */
TASK someReal := float(someInt);
/* CIF TASK (391, 1426), (241, 35) */
/* CIF TASK (389, 1427), (243, 35) */
TASK someInt := fix(someReal) mod 255;
/* CIF TASK (435, 1476), (152, 35) */
/* CIF TASK (434, 1477), (153, 35) */
TASK opnot := not opnot;
/* CIF TASK (430, 1526), (163, 35) */
/* CIF TASK (429, 1527), (164, 35) */
TASK 'someint := -someint'
/* CIF COMMENT (613, 1526), (196, 35) */
/* CIF COMMENT (613, 1527), (196, 35) */
COMMENT 'XXX should raise an error!';
/* CIF TASK (429, 1576), (164, 35) */
/* CIF TASK (428, 1577), (165, 35) */
TASK someint := (-8) mod 5;
/* CIF NEXTSTATE (480, 1626), (63, 33) */
/* CIF NEXTSTATE (478, 1627), (66, 33) */
NEXTSTATE wait;
ENDSTATE;
ENDPROCESS myfunction;
\ No newline at end of file