Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
OpenGEODE
Commits
9615353d
Commit
9615353d
authored
Jul 10, 2015
by
Marco Lattuada
Browse files
Added first version of c backend
parent
04ffe32c
Changes
2
Hide whitespace changes
Inline
Side-by-side
opengeode/CGenerator.py
0 → 100644
View file @
9615353d
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
OpenGEODE - A tiny SDL Editor for TASTE
This module generates C code from SDL process models.
Copyright (c) 2015 Politecnico di Milano
Designed and implemented by Marco Lattuada
Contact: marco.lattuada@polimi.it
"""
import
logging
from
singledispatch
import
singledispatch
import
Helper
import
ogAST
LOG
=
logging
.
getLogger
(
__name__
)
__all__
=
[
'generate'
]
VARIABLES
=
{}
LOCAL_OUT_PARS
=
{}
LOCAL_VAR
=
{}
LOCAL_VARIABLE_TYPES
=
{}
OUT_SIGNALS
=
[]
PROCEDURES
=
[]
UNICODE_SEP
=
u
'___'
LPREFIX
=
u
'context'
LEFT_TYPE
=
''
VAR_COUNTER
=
0
# Specify that the target is a shared library
SHARED_LIB
=
False
@
singledispatch
def
generate
(
*
args
,
**
kwargs
):
''' Generate the code for an item of the AST '''
for
arg
in
args
:
LOG
.
info
(
arg
)
raise
TypeError
(
'[CGenerator] Unsupported AST construct'
)
return
[],
[]
# Processing of the AST
@
generate
.
register
(
ogAST
.
Decision
)
def
_decision
(
dec
,
**
kwargs
):
''' generate the code for a decision '''
global
VAR_COUNTER
stmts
,
decls
=
[],
[]
if
dec
.
kind
==
'any'
:
LOG
.
warning
(
'C backend does not support the "ANY" statement'
)
stmts
.
append
(
'// "DECISION ANY" statement was ignored'
)
return
stmts
,
decls
elif
dec
.
kind
==
'informal_text'
:
LOG
.
warning
(
'Informal decision ignored'
)
stmts
.
append
(
'// Informal decision was ignored: {}'
.
format
(
dec
.
inputString
))
return
stmts
,
decls
question_type
=
dec
.
question
.
exprType
actual_type
=
type_name
(
question_type
)
basic
=
find_basic_type
(
question_type
).
kind
in
(
'IntegerType'
,
'Integer32Type'
,
'BooleanType'
,
'RealType'
,
'EnumeratedType'
,
'ChoiceEnumeratedType'
)
# for ASN.1 types, declare a local variable
# to hold the evaluation of the question
if
not
basic
:
decls
.
append
(
'{actType} tmp{idx};'
.
format
(
idx
=
dec
.
tmpVar
,
actType
=
actual_type
))
question_stmts
,
question_string
,
question_decls
=
expression
(
dec
.
question
)
# Add code-to-model traceability
stmts
.
extend
(
traceability
(
dec
))
decls
.
extend
(
question_decls
)
stmts
.
extend
(
question_stmts
)
if
not
basic
:
stmts
.
append
(
'tmp{idx} = {q};'
.
format
(
idx
=
dec
.
tmpVar
,
q
=
question_string
))
sep
=
'if('
for
a
in
dec
.
answers
:
stmts
.
extend
(
traceability
(
a
))
if
a
.
kind
in
(
'open_range'
,
'constant'
):
# Note: removed and a.transition here because empty transitions
# have a different meaning, and a "null;" statement has to be
# generated, to go into the branch
ans_stmts
,
ans_str
,
ans_decl
=
expression
(
a
.
constant
)
stmts
.
extend
(
ans_stmts
)
decls
.
extend
(
ans_decl
)
if
not
basic
:
if
a
.
openRangeOp
in
(
ogAST
.
ExprEq
,
ogAST
.
ExprNeq
):
if
isinstance
(
a
.
constant
,
(
ogAST
.
PrimSequenceOf
,
ogAST
.
PrimStringLiteral
)):
ans_str
=
array_content
(
a
.
constant
,
ans_str
,
find_basic_type
(
question_type
))
VAR_COUNTER
=
VAR_COUNTER
+
1
decls
.
append
(
u
'{ty} temp_equal_{var_counter} = {init};'
.
format
(
ty
=
actual_type
,
var_counter
=
VAR_COUNTER
,
init
=
ans_str
))
ans_str
=
u
'temp_equal_{var_counter}'
.
format
(
var_counter
=
VAR_COUNTER
)
elif
isinstance
(
a
.
constant
,
ogAST
.
PrimChoiceItem
):
VAR_COUNTER
=
VAR_COUNTER
+
1
decls
.
append
(
u
'{ty} temp_equal_{var_counter};'
.
format
(
ty
=
actual_type
,
var_counter
=
VAR_COUNTER
))
stmts
.
append
(
u
'temp_equal_{var_counter} = {init};'
.
format
(
var_counter
=
VAR_COUNTER
,
init
=
ans_str
))
ans_str
=
u
'temp_equal_{var_counter}'
.
format
(
var_counter
=
VAR_COUNTER
)
exp
=
u
'{actType}_Equal(&tmp{idx}, &{ans})'
.
format
(
actType
=
actual_type
,
idx
=
dec
.
tmpVar
,
ans
=
ans_str
)
if
a
.
openRangeOp
==
ogAST
.
ExprNeq
:
exp
=
u
'! {}'
.
format
(
exp
)
else
:
exp
=
u
'tmp{idx} {op} {ans}'
.
format
(
idx
=
dec
.
tmpVar
,
op
=
'=='
if
a
.
openRangeOp
.
operand
==
'='
else
a
.
openRangeOp
.
operand
,
ans
=
ans_str
)
else
:
exp
=
u
'({q}) {op} {ans}'
.
format
(
q
=
question_string
,
op
=
'=='
if
a
.
openRangeOp
.
operand
==
'='
else
a
.
openRangeOp
.
operand
,
ans
=
ans_str
)
stmts
.
append
(
sep
+
exp
+
')'
)
stmts
.
append
(
'{'
)
if
a
.
transition
:
transition_stmts
,
transition_decls
=
generate
(
a
.
transition
)
else
:
transition_stmts
,
transition_decls
=
[
';'
],
[]
stmts
.
extend
(
transition_stmts
)
decls
.
extend
(
transition_decls
)
stmts
.
append
(
'}'
)
sep
=
'else if('
elif
a
.
kind
==
'closed_range'
:
cl0_stmts
,
cl0_str
,
cl0_decl
=
expression
(
a
.
closedRange
[
0
])
cl1_stmts
,
cl1_str
,
cl1_decl
=
expression
(
a
.
closedRange
[
1
])
stmts
.
extend
(
cl0_stmts
)
decls
.
extend
(
cl0_decl
)
stmts
.
extend
(
cl1_stmts
)
decls
.
extend
(
cl1_decl
)
stmts
.
append
(
'{sep} {dec} >= {cl0} && {dec} <= {cl1})'
.
format
(
sep
=
sep
,
dec
=
question_string
,
cl0
=
cl0_str
,
cl1
=
cl1_str
))
stmts
.
append
(
'{'
)
if
a
.
transition
:
transition_stmts
,
transition_decls
=
generate
(
a
.
transition
)
else
:
transition_stmts
,
transition_decls
=
[
';'
],
[]
stmts
.
extend
(
transition_stmts
)
decls
.
extend
(
transition_decls
)
stmts
.
append
(
'}'
)
sep
=
'else if('
elif
a
.
kind
==
'informal_text'
:
continue
elif
a
.
kind
==
'else'
:
# Keep the ELSE statement for the end
if
a
.
transition
:
else_stmts
,
else_decl
=
generate
(
a
.
transition
)
else_stmts
.
insert
(
0
,
'{'
)
else_stmts
.
append
(
'}'
)
else
:
else_stmts
,
else_decl
=
[
'{'
,
';'
,
'}'
],
[]
decls
.
extend
(
else_decl
)
try
:
if
sep
!=
'if('
:
# If there is at least one 'if' branch
else_stmts
.
insert
(
0
,
'else'
)
stmts
.
extend
(
else_stmts
)
else
:
stmts
.
extend
(
else_stmts
)
except
:
pass
return
stmts
,
decls
@
generate
.
register
(
ogAST
.
Floating_label
)
def
_floating_label
(
label
,
**
kwargs
):
''' Generate the code for a floating label (C label + transition) '''
code
=
[]
local_decl
=
[]
# Add the traceability information
code
.
extend
(
traceability
(
label
))
code
.
append
(
u
'{label}:'
.
format
(
label
=
label
.
inputString
))
if
label
.
transition
:
code_trans
,
local_trans
=
generate
(
label
.
transition
)
code
.
extend
(
code_trans
)
local_decl
.
extend
(
local_trans
)
else
:
code
.
append
(
'return;'
)
return
code
,
local_decl
@
generate
.
register
(
ogAST
.
Label
)
def
_label
(
lab
,
**
kwargs
):
''' Transition following labels are generated in a separate section
for visibility reasons
'''
return
[
'goto {label};'
.
format
(
label
=
lab
.
inputString
)],
[]
@
generate
.
register
(
ogAST
.
Output
)
@
generate
.
register
(
ogAST
.
ProcedureCall
)
def
_call_external_function
(
output
,
**
kwargs
):
''' Generate the code of a set of output or procedure call statement '''
stmts
=
[]
decls
=
[]
# Add the traceability information
stmts
.
extend
(
traceability
(
output
))
for
out
in
output
.
output
:
signal_name
=
out
[
'outputName'
]
if
signal_name
.
lower
()
in
(
'write'
,
'writeln'
):
# special built-in SDL procedure for printing strings
# supports printing of native types (int, real, bool)
# but not yet complex ASN.1 structures (sequence/seqof/choice)
for
param
in
out
[
'params'
][:
-
1
]:
write_stmts
,
_
,
local
=
write_statement
(
param
,
newline
=
False
)
stmts
.
extend
(
write_stmts
)
decls
.
extend
(
local
)
for
param
in
out
[
'params'
][
-
1
:]:
# Last parameter - add newline if necessary
write_stmts
,
_
,
local
=
write_statement
(
param
,
newline
=
True
if
signal_name
.
lower
()
==
'writeln'
else
False
)
stmts
.
extend
(
write_stmts
)
decls
.
extend
(
local
)
continue
elif
signal_name
.
lower
()
==
'reset_timer'
:
# built-in operator for resetting timers. param = timer name
param
,
=
out
[
'params'
]
param_stmts
,
p_id
,
p_local
=
expression
(
param
)
stmts
.
extend
(
param_stmts
)
decls
.
extend
(
p_local
)
if
not
SHARED_LIB
:
stmts
.
append
(
'RESET_{};'
.
format
(
p_id
))
else
:
stmts
.
append
(
'RESET_{t}("{t}");'
.
format
(
t
=
p_id
))
continue
elif
signal_name
.
lower
()
==
'set_timer'
:
# built-in operator for setting a timer: SET(1000, timer_name)
timer_value
,
timer_id
=
out
[
'params'
]
timer_stmts
,
t_val
,
t_local
=
expression
(
timer_value
)
param_stmts
,
p_id
,
p_local
=
expression
(
timer_id
)
stmts
.
extend
(
timer_stmts
)
stmts
.
extend
(
param_stmts
)
decls
.
extend
(
t_local
)
decls
.
extend
(
p_local
)
if
not
SHARED_LIB
:
# Use a temporary variable to store the timer value
tmp_id
=
'tmp'
+
str
(
out
[
'tmpVars'
][
0
])
decls
.
append
(
'asn1SccUint32 {};'
.
format
(
tmp_id
))
stmts
.
append
(
'{tmp} = {val};'
.
format
(
tmp
=
tmp_id
,
val
=
t_val
))
stmts
.
append
(
"SET_{timer}(&{value});"
.
format
(
timer
=
p_id
,
value
=
tmp_id
))
else
:
stmts
.
append
(
'SET_{t}("{t}", {val});'
.
format
(
t
=
p_id
,
val
=
t_val
))
continue
proc
,
out_sig
=
None
,
None
is_out_sig
=
False
try
:
out_sig
,
=
[
sig
for
sig
in
OUT_SIGNALS
if
sig
[
'name'
].
lower
()
==
signal_name
.
lower
()]
is_out_sig
=
True
if
SHARED_LIB
else
False
except
ValueError
:
# Not an output, try if it is an external or inner procedure
try
:
proc
,
=
[
sig
for
sig
in
PROCEDURES
if
sig
.
inputString
.
lower
()
==
signal_name
.
lower
()]
if
proc
.
external
:
out_sig
=
proc
except
ValueError
:
# Not there? Impossible, the parser would have barked
raise
ValueError
(
u
'Probably a bug - please report'
)
if
out_sig
:
list_of_params
=
[]
for
idx
,
param
in
enumerate
(
out
.
get
(
'params'
)
or
[]):
param_direction
=
'in'
try
:
# If it is an output, there is a single parameter
param_type
=
out_sig
[
'type'
]
except
TypeError
:
# Else if it is a procedure, get the type
param_type
=
out_sig
.
fpar
[
idx
][
'type'
]
param_direction
=
out_sig
.
fpar
[
idx
][
'direction'
]
typename
=
type_name
(
param_type
)
param_stmts
,
p_id
,
p_local
=
expression
(
param
)
stmts
.
extend
(
param_stmts
)
decls
.
extend
(
p_local
)
# Create a temporary variable for input parameters only
# (If needed, i.e. if argument is not a local variable)
if
param_direction
==
'in'
and
(
not
(
isinstance
(
param
,
ogAST
.
PrimVariable
)
and
p_id
.
startswith
(
LPREFIX
))
or
isinstance
(
param
,
ogAST
.
PrimFPAR
)):
tmp_id
=
'tmp{}'
.
format
(
out
[
'tmpVars'
][
idx
])
if
isinstance
(
param
,
ogAST
.
PrimStringLiteral
):
decls
.
append
(
'{sort} {tmp} = {init};'
.
format
(
tmp
=
tmp_id
,
sort
=
typename
,
init
=
array_content
(
param
,
p_id
,
find_basic_type
(
param_type
))))
else
:
decls
.
append
(
'{sort} {tmp};'
.
format
(
tmp
=
tmp_id
,
sort
=
typename
))
if
isinstance
(
param
,
ogAST
.
PrimSequenceOf
):
p_id
=
array_content
(
param
,
p_id
,
find_basic_type
(
param_type
))
stmts
.
append
(
'{} = {};'
.
format
(
tmp_id
,
p_id
))
list_of_params
.
append
(
"&{}{}"
.
format
(
tmp_id
,
", sizeof({})"
.
format
(
tmp_id
)
if
is_out_sig
else
""
))
else
:
# Output parameters/local variables
list_of_params
.
append
(
u
"&{var}{shared}"
.
format
(
var
=
p_id
,
shared
=
", sizeof({})"
.
format
(
p_id
)
if
is_out_sig
else
""
))
if
list_of_params
:
stmts
.
append
(
u
'{RI}({params});'
.
format
(
RI
=
out
[
'outputName'
],
params
=
', '
.
join
(
list_of_params
)))
else
:
if
not
SHARED_LIB
:
stmts
.
append
(
u
'{RI};'
.
format
(
RI
=
out
[
'outputName'
]))
else
:
stmts
.
append
(
u
'{RI}(("{RI}"));'
.
format
(
RI
=
out
[
'outputName'
]))
else
:
# inner procedure call
list_of_params
=
[]
param_counter
=
0
for
param
in
out
.
get
(
'params'
,
[]):
param_stmts
,
p_id
,
p_local
=
expression
(
param
)
stmts
.
extend
(
param_stmts
)
decls
.
extend
(
p_local
)
# no need to use temporary variables, we are in pure Ada
if
proc
.
fpar
[
param_counter
].
get
(
'direction'
)
==
'out'
:
p_id
=
u
'&'
+
p_id
list_of_params
.
append
(
p_id
)
param_counter
=
param_counter
+
1
if
list_of_params
:
stmts
.
append
(
u
'{sep}{proc}({params});'
.
format
(
sep
=
UNICODE_SEP
,
proc
=
proc
.
inputString
,
params
=
', '
.
join
(
list_of_params
)))
else
:
stmts
.
append
(
u
'{}{}();'
.
format
(
UNICODE_SEP
,
proc
.
inputString
))
return
stmts
,
decls
@
generate
.
register
(
ogAST
.
Procedure
)
def
_inner_procedure
(
proc
,
**
kwargs
):
''' Generate the code for a procedure - does not support states '''
LOG
.
debug
(
'Expanding procedure '
+
proc
.
inputString
)
code
=
[]
local_decl
=
[]
# TODO: Update the global list of procedures
# with procedure defined inside the current procedure
# Not critical: the editor forbids procedures inside procedures
# Save variable scopes (as local variables may shadow process variables)
outer_scope
=
dict
(
VARIABLES
)
local_scope
=
dict
(
LOCAL_VAR
)
outer_params
=
dict
(
LOCAL_OUT_PARS
)
VARIABLES
.
update
(
proc
.
variables
)
# Store local variables in global context
LOCAL_VAR
.
update
(
proc
.
variables
)
LOCAL_OUT_PARS
.
clear
()
# Also add procedure parameters in scope
for
var
in
proc
.
fpar
:
elem
=
{
var
[
'name'
]:
(
var
[
'type'
],
None
)}
VARIABLES
.
update
(
elem
)
LOCAL_VAR
.
update
(
elem
)
if
var
.
get
(
'direction'
)
==
'out'
:
LOCAL_OUT_PARS
.
update
(
elem
)
# Build the procedure signature (function if it can return a value)
ret_type
=
type_name
(
proc
.
return_type
)
if
proc
.
return_type
else
None
pi_header
=
u
'{ext}{ret_type} {sep}{proc_name}'
.
format
(
ext
=
'extern '
if
proc
.
external
else
''
,
ret_type
=
'void'
if
not
ret_type
else
ret_type
,
proc_name
=
proc
.
inputString
,
sep
=
UNICODE_SEP
if
not
proc
.
external
else
''
)
pi_header
+=
'('
if
proc
.
fpar
:
params
=
[]
first
=
True
for
fpar
in
proc
.
fpar
:
typename
=
type_name
(
fpar
[
'type'
])
params
.
append
(
u
'{ptype} {pt} {name}'
.
format
(
ptype
=
typename
,
pt
=
'*'
if
fpar
.
get
(
'direction'
)
==
'out'
or
proc
.
external
else
''
,
name
=
fpar
.
get
(
'name'
)))
first
=
False
pi_header
+=
','
.
join
(
params
)
pi_header
+=
')'
local_decl
.
append
(
pi_header
+
';'
)
# Remote procedures need to be exported with a C calling convention
if
not
proc
.
external
:
# Generate the code for the procedure itself
# local variables and code of the START transition
# Recursively generate the code for inner-defined procedures
for
inner_proc
in
proc
.
content
.
inner_procedures
:
inner_code
,
inner_local
=
generate
(
inner_proc
)
local_decl
.
extend
(
inner_local
)
code
.
extend
(
inner_code
)
code
.
append
(
pi_header
)
code
.
append
(
u
'{'
)
for
var_name
,
(
var_type
,
def_value
)
in
proc
.
variables
.
viewitems
():
typename
=
type_name
(
var_type
)
if
def_value
:
# Expression must be a ground expression, i.e. must not
# require temporary variable to store computed result
dst
,
dstr
,
dlocal
=
expression
(
def_value
)
varbty
=
find_basic_type
(
var_type
)
if
varbty
.
kind
in
(
'SequenceOfType'
,
'OctetStringType'
):
dstr
=
array_content
(
def_value
,
dstr
,
varbty
)
assert
not
dst
and
not
dlocal
,
'Ground expression error'
code
.
append
(
u
'{ty} {name} {default};'
.
format
(
ty
=
typename
,
name
=
var_name
,
default
=
' = '
+
dstr
if
def_value
else
''
))
# Look for labels in the diagram and transform them in floating labels
Helper
.
inner_labels_to_floating
(
proc
)
if
proc
.
content
.
start
:
tr_code
,
tr_decl
=
generate
(
proc
.
content
.
start
.
transition
)
else
:
tr_code
,
tr_decl
=
[
'; // Empty procedure'
],
[]
# Generate code for the floating labels
code_labels
=
[]
for
label
in
proc
.
content
.
floating_labels
:
code_label
,
label_decl
=
generate
(
label
)
code_labels
.
extend
(
code_label
)
tr_decl
.
extend
(
label_decl
)
code
.
extend
(
set
(
tr_decl
))
code
.
extend
(
tr_code
)
code
.
extend
(
code_labels
)
code
.
append
(
u
'}'
)
code
.
append
(
'
\n
'
)
# Reset the scope to how it was prior to the procedure definition
VARIABLES
.
clear
()
VARIABLES
.
update
(
outer_scope
)
LOCAL_VAR
.
clear
()
LOCAL_VAR
.
update
(
local_scope
)
LOCAL_OUT_PARS
.
clear
()
LOCAL_OUT_PARS
.
update
(
outer_params
)
return
code
,
local_decl
@
generate
.
register
(
ogAST
.
Process
)
def
_process
(
process
,
simu
=
False
,
**
kwargs
):
''' Generate the code for a complete process (AST Top level) '''
#Types
global
TYPES
TYPES
=
process
.
dataview
del
OUT_SIGNALS
[:]
OUT_SIGNALS
.
extend
(
process
.
output_signals
)
del
PROCEDURES
[:]
PROCEDURES
.
extend
(
process
.
procedures
)
#The name of the process
process_name
=
process
.
processName
#The generated source code
c_source_code
=
[]
h_source_code
=
[]
#The global declarations
global_decls
=
[]
#The number of temporary variable
global
tmp_var_id
tmp_var_id
=
0
#True if math.h has to be included
global
math_include
math_include
=
False
#True if stdio.h has to be included
global
STDIO_INCLUDE
STDIO_INCLUDE
=
False
#True if string.h has to be included
global
string_include
string_include
=
False
global
LPREFIX
global
SHARED_LIB
if
simu
:
SHARED_LIB
=
True
LPREFIX
=
process_name
+
u
'_ctxt'
# When building a shared library (with simu=True), generate a "mini-cv"
# for aadl2glueC to create the code interfacing with asn1scc
minicv
=
[
'// Automatically generated by OpenGEODE - do NOT modify!'
]
def
aadl_template
(
sp_name
,
io_param
,
pi_or_ri
):
''' AADL mini-cv code in case of shared library
sp_name : name of the PI or RI
io_param : list of (param_name, type_name, direction)
pi_or_ri : string "PI" or "RI" depending on the direction
return a string
'''
res
=
[]
if
not
io_param
:
LOG
.
info
(
'Parameterless interface "{}" will not appear in the'
' AADL file but will be handled directly by the GUI'
.
format
(
sp_name
))
return
''
# In case of shared library, generate the AADL "mini-cv" code
res
.
append
(
'SUBPROGRAM {}'
.
format
(
sp_name
))
if
io_param
:
res
.
append
(
'FEATURES'
)
for
param_name
,
sort
,
direction
in
io_param
:
res
.
append
(
' {pname}: {io} PARAMETER DataView::{sort} '
'{{encoding=>Native;}};'
.
format
(
pname
=
param_name
,
sort
=
sort
,
io
=
direction
))
res
.
append
(
'END {};
\n
'
.
format
(
sp_name
))
res
.
append
(
'SUBPROGRAM IMPLEMENTATION {}.GUI_{}'
.
format
(
sp_name
,
pi_or_ri
))
res
.
append
(
'PROPERTIES'
)
res
.
append
(
' FV_Name => "{}";'
.
format
(
process_name
))
res
.
append
(
' Source_Language => GUI_{};'
.
format
(
pi_or_ri
))
res
.
append
(
'END {}.GUI_{};
\n
'
.
format
(
sp_name
,
pi_or_ri
))
return
'
\n
'
.
join
(
res
)
# bash script to simulate the system (TEMPORARY)
simu_script
=
'''#!/bin/bash -e
opengeode {pr}.pr --shared --toC
asn1.exe -c dataview-uniq.asn -typePrefix asn1Scc -equal
gcc -c *.c -fPIC
gcc -shared -fPIC -o lib{pr}.so {pr}.o dataview-uniq.o adaasn1rtl.o -lgnat
rm -rf simu
mkdir -p simu
asn2aadlPlus dataview-uniq.asn simu/DataView.aadl
cp lib{pr}.so dataview-uniq.asn *.pr simu
mv *.aadl simu
cd simu
aadl2glueC DataView.aadl {pr}_interface.aadl
asn2dataModel -toPython dataview-uniq.asn
make -f Makefile.python
echo "errCodes=$(taste-asn1-errCodes ./dataview-uniq.h)" >>datamodel.py
LD_LIBRARY_PATH=. taste-gui -l
'''
.
format
(
pr
=
process_name
)
LOG
.
info
(
'Generating C code for process '
+
str
(
process_name
))
# In case model has nested states, flatten everything
Helper
.
flatten
(
process
,
sep
=
UNICODE_SEP
)
# Make an maping {input: {state: transition...}} in order to easily
# generate the lookup tables for the state machine runtime
mapping
=
Helper
.
map_input_state
(
process
)
VARIABLES
.
update
(
process
.
variables
)
#Computing state lists
state_list
=
', '
.
join
(
name
for
name
in
process
.
mapping
.
iterkeys
()
if
not
name
.
endswith
(
u
'START'
))
or
'No_State'
#Declaring global type modeling the state
if
state_list
:
state_decl
=
u
'typedef enum {{{}}} states_t;'
.
format
(
state_list
)
global_decls
.
append
(
state_decl
)
#Declaring global type modeling the context
context_type
=
[]
context_init_code
=
[]
context_type
.
append
(
u
'typedef struct'
)
context_type
.
append
(
u
'{'
)
context_init_code
.
append
(
u
'void CInit()'
)
context_init_code
.
append
(
u
'{'
)
if
state_list
:
context_type
.
append
(
u
'states_t state;'
)
for
var_name
,
(
var_type
,
init
)
in
process
.
variables
.
viewitems
():
init_stmt
=
[]
init_string
=
''
init_decl
=
[]
if
init
:
init_stmt
,
temp_init_string
,
init_decls
=
expression
(
init
)
if
find_basic_type
(
var_type
).
kind
in
(
'SequenceOfType'
,
'OctetStringType'
):
init_string
=
array_content
(
init
,
temp_init_string
,
find_basic_type
(
var_type
))
if
find_basic_type
(
var_type
).
Min
==
find_basic_type
(
var_type
).
Max
:
init_string
=
u
'{{{init}}}'
.
format
(
init
=
init_string
)
else
:
init_stmt
,
init_string
,
init_decl
=
expression
(
init
)
if
find_basic_type
(
var_type
).
kind
in
(
'SequenceOfType'
,
'OctetStringType'
,
'SequenceType'
):
init_string
=
u
'('
+
type_name
(
var_type
)
+
u
') '
+
init_string
LOG
.
debug
(
var_name
)
context_init_code
.
append
(
u
'{ct}.{field} = {init};'
.
format
(
ct
=
LPREFIX
,
field
=
var_name
,
init
=
init_string
))
assert
not
init_stmt
,
'Initialization of '
+
init_name
+
' requires to add statement'
assert
not
init_decl
,
'Initialization of '
+
init_name
+
' requires to add declartions'
context_type
.
append
(
u
'{tn} {vn};'
.
format
(
tn
=
type_name
(
var_type
),
vn
=
var_name
))
context_type
.
extend
([
'} context_t;'
])
context_init_code
.
append
(
u
'}'
)
global_decls
.
extend
(
context_type
)
# Adding the declaration of the state variable
global_decls
.
append
(
u
'context_t {ct};'
.
format
(
ct
=
LPREFIX
))
global_decls
.
extend
(
context_init_code
)
for
name
,
val
in
process
.
mapping
.
viewitems
():
if
name
.
endswith
(
u
'START'
)
and
name
!=
u
'START'
:
global_decls
.
append
(
u
'#define {name} {val}'
.
format
(
name
=
name
,
val
=
str
(
val
)))
# Add the declaration of the runTransition procedure, if needed
if
process
.
transitions
:
global_decls
.
append
(
'void runTransition(int Id);'
)
# Generate the code of the start transition (if process not empty)
start_transition
=
[
'runTransition(0);'
]
if
process
.
transitions
else
[]
dll_code
=
[]
if
simu
:
h_source_code
.
append
(
'// DLL Interface'
)
dll_code
.
append
(
'// DLL Interface to remotely change internal data'
)
# Add function allowing to trace current state as a string
global_decls
.
append
(
u
'char * {pn}_state()'
.
format
(
pn
=
process_name
))
global_decls
.
append
(
u
'{'
)
for
state_name
in
process
.
mapping
.
iterkeys
():
if
not
state_name
.
endswith
(
u
'START'
)
and
state_name
!=
'No_State'
:
global_decls
.
append
(
u
'if({ctxt}.state == {sn}) return
\"
{sn}
\\
0
\"
;'
.
format
(
ctxt
=
LPREFIX
,
sn
=
state_name
))
global_decls
.
append
(
u
'return
\"\\
0
\"
;'
)
global_decls
.
append
(
u
'}'
)
set_state_decl
=
u
'void _set_state(char * new_state)'
h_source_code
.
append
(
u
'{};'
.
format
(
set_state_decl
))
dll_code
.
append
(
u
'{}'
.
format
(
set_state_decl
))
dll_code
.
append
(
u
'{'
)
for
state_name
in
process
.
mapping
.
iterkeys
():
if
not
state_name
.
endswith
(
u
'START'
)
and
state_name
!=
'No_State'
:
dll_code
.
append
(
u
'if(strcmp(new_state,
\"
{st}
\"
) == 0) {ctxt}.state = {st};'
.
format
(
st
=
state_name
,
ctxt
=
LPREFIX
))
dll_code
.
append
(
u
'}'
)
dll_code
.
append
(
u
''
)
# Functions to get gobal variables (length and value)