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

Added unary expressions nodes

parent 0d5c683e
...@@ -723,8 +723,7 @@ def _primary_variable(prim): ...@@ -723,8 +723,7 @@ def _primary_variable(prim):
''' Single variable reference ''' ''' Single variable reference '''
sep = u'l_' if find_var(prim.value[0]) else u'' sep = u'l_' if find_var(prim.value[0]) else u''
string = u'{sep}{name}'.format(sep=sep, name=prim.value[0]) ada_string = u'{sep}{name}'.format(sep=sep, name=prim.value[0])
ada_string = unary(prim, string)
if prim.exprType.__name__ == 'for_range': if prim.exprType.__name__ == 'for_range':
# Ada iterator in FOR loops is an Integer - we must cast to 64 bits # Ada iterator in FOR loops is an Integer - we must cast to 64 bits
...@@ -896,7 +895,6 @@ def _prim_path(primary_id): ...@@ -896,7 +895,6 @@ def _prim_path(primary_id):
ada_string += ', '.join(list_of_params) ada_string += ', '.join(list_of_params)
ada_string += ')' ada_string += ')'
sep = '.' sep = '.'
ada_string = unary(primary_id, ada_string)
return stmts, ada_string, local_decl return stmts, ada_string, local_decl
...@@ -924,7 +922,6 @@ def _basic_operators(expr): ...@@ -924,7 +922,6 @@ def _basic_operators(expr):
code.extend(right_stmts) code.extend(right_stmts)
local_decl.extend(left_local) local_decl.extend(left_local)
local_decl.extend(right_local) local_decl.extend(right_local)
ada_string = unary(expr, ada_string)
return code, ada_string, local_decl return code, ada_string, local_decl
...@@ -964,7 +961,18 @@ def _bitwise_operators(expr): ...@@ -964,7 +961,18 @@ def _bitwise_operators(expr):
code.extend(right_stmts) code.extend(right_stmts)
local_decl.extend(left_local) local_decl.extend(left_local)
local_decl.extend(right_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 return code, ada_string, local_decl
...@@ -1090,8 +1098,11 @@ def _choice_determinant(primary): ...@@ -1090,8 +1098,11 @@ def _choice_determinant(primary):
@expression.register(ogAST.PrimReal) @expression.register(ogAST.PrimReal)
def _integer(primary): def _integer(primary):
''' Generate code for a raw numerical value ''' ''' Generate code for a raw numerical value '''
ada_string = primary.value[0] if float(primary.value[0]) < 0:
ada_string = unary(primary, ada_string) # 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, [] return [], ada_string, []
...@@ -1099,7 +1110,6 @@ def _integer(primary): ...@@ -1099,7 +1110,6 @@ def _integer(primary):
def _integer(primary): def _integer(primary):
''' Generate code for a raw boolean value ''' ''' Generate code for a raw boolean value '''
ada_string = primary.value[0] ada_string = primary.value[0]
ada_string = unary(primary, ada_string)
return [], ada_string, [] return [], ada_string, []
...@@ -1514,25 +1524,6 @@ def _inner_procedure(proc): ...@@ -1514,25 +1524,6 @@ def _inner_procedure(proc):
return code, local_decl 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): def find_basic_type(a_type):
''' Return the ASN.1 basic type of a_type ''' ''' Return the ASN.1 basic type of a_type '''
basic_type = a_type basic_type = a_type
......
...@@ -127,6 +127,14 @@ class ExprRem(Expression): ...@@ -127,6 +127,14 @@ class ExprRem(Expression):
operand = 'rem' operand = 'rem'
class ExprNot(Expression):
operand = 'not'
class ExprNeg(Expression):
operand = '-'
class ExprAssign(Expression): class ExprAssign(Expression):
operand = ':=' operand = ':='
...@@ -157,16 +165,12 @@ class Primary(Expression): ...@@ -157,16 +165,12 @@ class Primary(Expression):
self.inputString = primary.inputString self.inputString = primary.inputString
self.line = primary.line self.line = primary.line
self.charPositionInLine = primary.charPositionInLine self.charPositionInLine = primary.charPositionInLine
self.op_not = primary.op_not
self.op_minus = primary.op_minus
self.value = primary.value self.value = primary.value
self.exprType = primary.exprType self.exprType = primary.exprType
else: else:
self.inputString = inputString self.inputString = inputString
self.line = line self.line = line
self.charPositionInLine = charPositionInLine self.charPositionInLine = charPositionInLine
self.op_not = False
self.op_minus = False
self.value = None self.value = None
self.exprType = None self.exprType = None
......
...@@ -61,6 +61,8 @@ OPKIND = {lexer.PLUS: ogAST.ExprPlus, ...@@ -61,6 +61,8 @@ OPKIND = {lexer.PLUS: ogAST.ExprPlus,
lexer.APPEND: ogAST.ExprAppend, lexer.APPEND: ogAST.ExprAppend,
lexer.IN: ogAST.ExprIn, lexer.IN: ogAST.ExprIn,
lexer.REM: ogAST.ExprRem, lexer.REM: ogAST.ExprRem,
lexer.NOT: ogAST.ExprNot,
lexer.NEG: ogAST.ExprNeg,
lexer.PRIMARY: ogAST.Primary} lexer.PRIMARY: ogAST.Primary}
# Insert current path in the search list for importing modules # 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): ...@@ -454,7 +456,7 @@ def check_and_fix_op_params(op_name, expr_list, context):
def check_range(typeref, type_to_check): def check_range(typeref, type_to_check):
''' Verify the that the Min/Max bounds of two types are compatible ''' Verify the that the Min/Max bounds of two types are compatible
Called to test that assignments are withing allowed range Called to test that assignments are withing allowed range
both types assumed to be basic types both types assumed to be basic types
''' '''
try: try:
if float(type_to_check.Min) < float(typeref.Min) \ if float(type_to_check.Min) < float(typeref.Min) \
...@@ -861,8 +863,28 @@ def find_type(path, context): ...@@ -861,8 +863,28 @@ def find_type(path, context):
return result 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): 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): if isinstance(expr, ogAST.Primary):
return return
...@@ -1249,14 +1271,9 @@ def primary(root, context): ...@@ -1249,14 +1271,9 @@ def primary(root, context):
''' Process a primary (-/NOT value) ''' ''' Process a primary (-/NOT value) '''
warnings = [] warnings = []
errors = [] errors = []
op_not, op_minus = False, False
prim = None prim = None
for child in root.getChildren(): for child in root.getChildren():
if child.type == lexer.NOT: if child.type == lexer.PRIMARY_ID:
op_not = True
elif child.type == lexer.MINUS:
op_minus = True
elif child.type == lexer.PRIMARY_ID:
# Variable reference, indexed values, or ASN.1 value notation # Variable reference, indexed values, or ASN.1 value notation
prim, err, warn = primary_value(child, context=context) prim, err, warn = primary_value(child, context=context)
errors.extend(err) errors.extend(err)
...@@ -1292,10 +1309,6 @@ def primary(root, context): ...@@ -1292,10 +1309,6 @@ def primary(root, context):
prim.inputString = get_input_string(root) prim.inputString = get_input_string(root)
prim.line = root.getLine() prim.line = root.getLine()
prim.charPositionInLine = root.getCharPositionInLine() prim.charPositionInLine = root.getCharPositionInLine()
if op_not:
prim.op_not = True
if op_minus:
prim.op_minus = True
return prim, errors, warnings return prim, errors, warnings
...@@ -1325,7 +1338,7 @@ def expression(root, context): ...@@ -1325,7 +1338,7 @@ def expression(root, context):
root.children.pop(idx) root.children.pop(idx)
break break
# Binary expressions
if root.type in (lexer.PLUS, if root.type in (lexer.PLUS,
lexer.ASTERISK, lexer.ASTERISK,
lexer.DASH, lexer.DASH,
...@@ -1374,6 +1387,15 @@ def expression(root, context): ...@@ -1374,6 +1387,15 @@ def expression(root, context):
format(expr.inputString, str(report))) format(expr.inputString, str(report)))
expr = new_expr 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, if root.type in (lexer.EQ,
lexer.NEQ, lexer.NEQ,
lexer.GT, lexer.GT,
...@@ -1414,7 +1436,6 @@ def expression(root, context): ...@@ -1414,7 +1436,6 @@ def expression(root, context):
errors.append('Check that all your numerical data types have ' errors.append('Check that all your numerical data types have '
'a range constraint') 'a range constraint')
elif root.type in (lexer.OR, lexer.AND, lexer.XOR): elif root.type in (lexer.OR, lexer.AND, lexer.XOR):
# in the case of bitwise operators, if both sides are arrays, # in the case of bitwise operators, if both sides are arrays,
# then the result is an array too # then the result is an array too
...@@ -1425,15 +1446,22 @@ def expression(root, context): ...@@ -1425,15 +1446,22 @@ def expression(root, context):
else: else:
expr.exprType = expr.left.exprType expr.exprType = expr.left.exprType
elif root.type in (lexer.PLUS, elif root.type == lexer.NOT:
lexer.ASTERISK, basic = find_basic_type(expr.expr.exprType)
lexer.DASH, if basic.kind == 'BooleanType':
lexer.DIV, expr.exprType = BOOLEAN
lexer.APPEND, else:
lexer.REM, expr.exprType = expr.expr.exprType
lexer.MOD):
elif root.type == lexer.APPEND:
expr.exprType = expr.left.exprType 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: if root.type == lexer.PRIMARY:
expr, err, warn = primary(root, context) expr, err, warn = primary(root, context)
if not expr: if not expr:
...@@ -1927,15 +1955,15 @@ def text_area_content(root, ta_ast, context): ...@@ -1927,15 +1955,15 @@ def text_area_content(root, ta_ast, context):
elif child.type == lexer.SYNONYM_LIST: elif child.type == lexer.SYNONYM_LIST:
err, warn = synonym(child, ta_ast, context) err, warn = synonym(child, ta_ast, context)
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
elif child.type == lexer.NEWTYPE: elif child.type == lexer.NEWTYPE:
err, warn = newtype(child, ta_ast, context) err, warn = newtype(child, ta_ast, context)
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
elif child.type == lexer.SYNTYPE: elif child.type == lexer.SYNTYPE:
err, warn = syntype(child, ta_ast, context) err, warn = syntype(child, ta_ast, context)
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
elif child.type == lexer.PROCEDURE: elif child.type == lexer.PROCEDURE:
proc, err, warn = procedure(child, context=context) proc, err, warn = procedure(child, context=context)
errors.extend(err) errors.extend(err)
......
/* /*
OpenGEODE OpenGEODE
ANTLR 3.1.3 grammar for the SDL92 langage ANTLR 3.1.3 grammar for the SDL92 langage
Includes the following features from SDL2000+: Includes the following features from SDL2000+:
...@@ -89,7 +89,7 @@ tokens { ...@@ -89,7 +89,7 @@ tokens {
VARIABLES; VARIABLES;
SORT; SORT;
DCL; DCL;
MINUS; NEG;
GROUND; GROUND;
TEXTAREA; TEXTAREA;
TEXTAREA_CONTENT; TEXTAREA_CONTENT;
...@@ -183,7 +183,7 @@ route ...@@ -183,7 +183,7 @@ route
block_definition block_definition
: BLOCK block_id end : BLOCK block_id end
entity_in_block* entity_in_block*
ENDBLOCK end ENDBLOCK end
-> ^(BLOCK block_id entity_in_block*); -> ^(BLOCK block_id entity_in_block*);
...@@ -456,7 +456,7 @@ enabling_condition ...@@ -456,7 +456,7 @@ enabling_condition
continuous_signal continuous_signal
: PROVIDED expression end : PROVIDED expression end
(PRIORITY integer_literal_name=INT end)? (PRIORITY integer_literal_name=INT end)?
transition transition
-> ^(PROVIDED expression $integer_literal_name? transition); -> ^(PROVIDED expression $integer_literal_name? transition);
...@@ -491,7 +491,7 @@ signal_item ...@@ -491,7 +491,7 @@ signal_item
signal_list_id | signal_list_id |
timer_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) (irrelevant in the scope of the generation of code for a single process)
priority_input priority_input
: PRIORITY INPUT priority_input_list end transition; : PRIORITY INPUT priority_input_list end transition;
...@@ -576,7 +576,7 @@ procedure_call ...@@ -576,7 +576,7 @@ procedure_call
procedure_call_body procedure_call_body
: procedure_id actual_parameters? : procedure_id actual_parameters?
-> ^(OUTPUT_BODY procedure_id actual_parameters?); -> ^(OUTPUT_BODY procedure_id actual_parameters?);
...@@ -685,7 +685,7 @@ constant ...@@ -685,7 +685,7 @@ constant
create_request create_request
: CREATE : CREATE
createbody createbody
actual_parameters? actual_parameters?
end end
...@@ -712,7 +712,7 @@ outputbody ...@@ -712,7 +712,7 @@ outputbody
outputstmt outputstmt
: signal_id : signal_id
actual_parameters?; actual_parameters?;
to_part to_part
...@@ -795,20 +795,30 @@ variable ...@@ -795,20 +795,30 @@ variable
field_selection field_selection
: (('!'|'.') field_name); : (('!'|'.') field_name);
expression : operand0 ( IMPLIES^ operand0)* ; expression
operand0 : operand1 (( (OR^ ELSE?) | XOR^ ) operand1)*; : operand0 ( IMPLIES^ operand0)* ;
operand1 : operand2 ( AND^ THEN? operand2)*;
operand2 : operand3 operand0
(( EQ^ | NEQ^ | GT^ | GE^ | LT^ | LE^ | IN^ ) : operand1 (( (OR^ ELSE?) | XOR^ ) operand1)*;
operand3)*;
operand3 : operand4 (( PLUS^ | DASH^ | APPEND^ ) operand4)*; operand1
operand4 : operand5 : operand2 ( AND^ THEN? operand2)*;
(( ASTERISK^ | DIV^ | MOD^ | REM^ ) operand5)*;
operand5 : primary_qualifier? primary operand2
-> ^(PRIMARY primary_qualifier? primary); : 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 primary
: a=asn1Value primary_params* : a=asn1Value primary_params*
-> ^(PRIMARY_ID asn1Value primary_params*) -> ^(PRIMARY_ID asn1Value primary_params*)
...@@ -833,7 +843,7 @@ asn1Value ...@@ -833,7 +843,7 @@ asn1Value
| L_BRACKET | L_BRACKET
MANTISSA mant=INT COMMA MANTISSA mant=INT COMMA
BASE bas=INT COMMA BASE bas=INT COMMA
EXPONENT exp=INT EXPONENT exp=INT
R_BRACKET -> ^(FLOAT2 $mant $bas $exp) R_BRACKET -> ^(FLOAT2 $mant $bas $exp)
| choiceValue | choiceValue
| L_BRACKET | L_BRACKET
...@@ -859,7 +869,7 @@ informal_text ...@@ -859,7 +869,7 @@ informal_text
// hello:5 (CHOICE field value) // hello:5 (CHOICE field value)
choiceValue choiceValue
: choice=ID ':' expression : choice=ID ':' expression
-> ^(CHOICE $choice expression); -> ^(CHOICE $choice expression);
...@@ -869,12 +879,6 @@ namedValue ...@@ -869,12 +879,6 @@ namedValue
: ID expression; : ID expression;
primary_qualifier
: DASH
-> ^(MINUS)
| NOT;
primary_params primary_params
: '(' expression_list ')' : '(' expression_list ')'
-> ^(PARAMS expression_list) -> ^(PARAMS expression_list)
...@@ -882,7 +886,7 @@ primary_params ...@@ -882,7 +886,7 @@ primary_params
-> ^(FIELD_NAME literal_id); -> ^(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) above (Except structure primary, but we favour ASN.1 notation)
extended_primary extended_primary
: synonym | : synonym |
...@@ -960,7 +964,7 @@ operator_application ...@@ -960,7 +964,7 @@ operator_application
: operator_id '('active_expression_list ')'; : operator_id '('active_expression_list ')';
active_expression_list active_expression_list
: active_expression (',' expression_list)?;/* | : active_expression (',' expression_list)?;/* |
ground_expression ',' active_expression_list;*/ // Will not work (recursion) ground_expression ',' active_expression_list;*/ // Will not work (recursion)
/* /*
...@@ -990,7 +994,7 @@ conditional_ground_expression ...@@ -990,7 +994,7 @@ conditional_ground_expression
-> ^(IFTHENELSE $ifexpr $thenexpr $elseexpr); -> ^(IFTHENELSE $ifexpr $thenexpr $elseexpr);
expression_list expression_list
: expression (',' expression)* : expression (',' expression)*
-> expression+; -> expression+;
...@@ -1048,7 +1052,7 @@ cif ...@@ -1048,7 +1052,7 @@ cif
: cif_decl symbolname : cif_decl symbolname
L_PAREN x=INT COMMA y=INT R_PAREN L_PAREN x=INT COMMA y=INT R_PAREN
COMMA COMMA
L_PAREN width=INT COMMA height=INT R_PAREN L_PAREN width=INT COMMA height=INT R_PAREN
cif_end cif_end
-> ^(CIF $x $y $width $height); -> ^(CIF $x $y $width $height);
...@@ -1060,7 +1064,7 @@ hyperlink ...@@ -1060,7 +1064,7 @@ hyperlink
/* OpenGEODE specific: SDL does not allow specifying the name /* OpenGEODE specific: SDL does not allow specifying the name
of signal parameters, but it is needed to generate function signatures 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 body must comply with the one of the source
Extension is using CIF comment so it is invisible to other SDL parsers Extension is using CIF comment so it is invisible to other SDL parsers
(This is valid SDL code - see ITU-T Z106) (This is valid SDL code - see ITU-T Z106)
...@@ -1273,13 +1277,13 @@ ENDBLOCK : E N D B L O C K; ...@@ -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; SIGNALROUTE : S I G N A L R O U T E;
CONNECT : C O N N E C T; CONNECT : C O N N E C T;
SYNTYPE : S Y N T Y P E; 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; NEWTYPE : N E W T Y P E;
ENDNEWTYPE : E N D N E W T Y P E; ENDNEWTYPE : E N D N E W T Y P E;
ARRAY : A R R A Y;