Commit bee2e120 authored by dbarbera's avatar dbarbera
Browse files

Merge remote-tracking branch 'upstream/master' into llvm

parents 556f732c d614520e
...@@ -11,15 +11,50 @@ Developer documentation is provided in docstrings in the Python modules. ...@@ -11,15 +11,50 @@ Developer documentation is provided in docstrings in the Python modules.
License is LGPL (see file LICENSE) License is LGPL (see file LICENSE)
You need Pyside and ANTLR 3.1.3 runtimes to be able to use this Python module You need to install the following dependencies before you can run Opengeode:
On Debian, Ubuntu:
$ apt-get install python-pyside pip - Python 2.7
$ pip install antlr_python_runtime installed on all Linux distributions ; on Windows you need to install it manually
- PySide
on debian-based Linux run:
$ sudo apt-get install python-pyside
on windows and mac, download and run the automatic installer from Qt
- pip for Python2
on debian-based Linux run:
$ sudo apt-get install python-pip
on windows and mac, download and use the automatic installer
- enum34, singledispatch, graphviz, antlr runtime
graphviz core needs to be installed from the Linux repos first:
$ sudo apt-get install graphviz
Then using pip, install the python libraries:
$ sudo pip install --upgrade graphviz enum34 singledispatch
$ sudo pip install antlr_python_runtime --allow-external antlr_python_runtime --allow-unverified antlr_python_runtime
* Note: graphviz for python cannot be installed on Windows
- ASN1SCC - the ASN.1 compiler
Download here: http://www.semantix.gr/asn1scc/asn1Comp.tar.gz
It is a .NET application, it can be installed on Windows and Linux (you need mono)
Make sure asn1.exe is in the path
On linux :
$ cd /opt
$ sudo wget http://www.semantix.gr/asn1scc/asn1Comp.tar.gz
$ sudo tar zxvf asn1Comp.tar.gz
$ sudo apt-get install mono-runtime libmono-system-runtime4.0-cil libmono-i18n-west2.0-cil libmono-posix2.0-cil libmono-security2.0-cil
libmono-system-runtime-serialization4.0-cil
Check that it works:
$ asn1Comp/bin/asn1.exe
Then add to your PATH the bin directory in e.g. your .bashrc file
$ echo 'export PATH=$PATH:/opt/asn1Comp/bin' >> ~/.bashrc
- gnat - if you want to build the code you generate in Ada
$ sudo apt-get install gnat
Also tested on Windows and FreeBSD - use pip to install antlr-python-runtime.
Install Pyside from the Windows binary or from FreeBSD ports.
On Windows, you also need to install Python 2.7 manually.
To make a static binary on Linux with pyinstaller 2.0: To make a static binary on Linux with pyinstaller 2.0:
python pyinstaller.py ../../opengeode.py --onefile python pyinstaller.py ../../opengeode.py --onefile
...@@ -23,8 +23,8 @@ Features ...@@ -23,8 +23,8 @@ Features
- Graphical editor of SDL processes and procedures. - Graphical editor of SDL processes and procedures.
- SDL2010 features: FOR loops in task symbols, hierarchical states - SDL2010 features: FOR loops in task symbols, hierarchical states
- Works on pure PR+CIF files (textual SDL notation) - no fancy proprietary save format - Works on pure PR+CIF files (textual SDL notation) - no fancy proprietary save format
- Supports ASN.1 data types, including the Value notation - check this page to know more about our ASN.1 compiler and tools - Full supports ASN.1 data types - using ESA Space Certified compiler (www.github.com/ttsiodras/asn1scc)
- Generates Ada code with ASN.1 types using TASTE ASN.1 "space-certified" (SPARK) compiler - Generates Ada code
- Extensive syntax and semantic checks - Extensive syntax and semantic checks
- Automatic conversion to Statechart diagrams - Automatic conversion to Statechart diagrams
- Save the complete or parts of the model to PNG/SVG/PDF files - Save the complete or parts of the model to PNG/SVG/PDF files
...@@ -34,6 +34,7 @@ Features ...@@ -34,6 +34,7 @@ Features
- Syntax highlighting - Syntax highlighting
- Undo/Redo, Copy-Paste - Undo/Redo, Copy-Paste
- (Limited) VIM mode - You can use :wq or :%s,search,replace,g, and /search pattern - (Limited) VIM mode - You can use :wq or :%s,search,replace,g, and /search pattern
- (In progress) SDL to LLVM code generation
Installation Installation
============ ============
...@@ -41,46 +42,46 @@ Installation ...@@ -41,46 +42,46 @@ Installation
Pre-requisites Pre-requisites
-------------- --------------
There are three major dependencies for OpenGEODE: There are several dependencies for OpenGEODE:
Apart from pygraphviz, all of them exist for Linux, Windows, FreeBSD, and most likely Mac OSX
- Python 2.7 with pip
- Pyside (the Qt bindings for Python) - Pyside (the Qt bindings for Python)
- Python ANTLR Runtime - Python ANTLR Runtime
- PyGraphviz (Linux only - not available on Windows) - PyGraphviz (Linux only - not available on Windows)
- enum34, singledispatch
- ASN1SCC
- (optional) GNAT to build the generated Ada code
- mono
If you use pip to install OpenGEODE, these dependencies should be installed On Debian, Ubuntu, and probably other distributions:
automatically. However, note that installing PySide from pip requires some
work and is not straightforward.
If you are using a Linux Debian-based distribution (including Ubuntu),
I would recommended to install PySide using your package manager:
You should also install pygraphviz using the same method, for convenience.
```bash ```bash
$ sudo apt-get install python-pyside pyside-tools python-pygraphviz pip $ sudo apt-get install python-pyside pyside-tools graphviz pip gnat mono-runtime libmono-system-runtime4.0-cil libmono-i18n-west2.0-cil libmono-posix2.0-cil libmono-security2.0-cil
libmono-system-runtime-serialization4.0-cil
$ sudo pip install --upgrade graphviz enum34 singledispatch
$ sudo pip install antlr_python_runtime --allow-external antlr_python_runtime --allow-unverified antlr_python_runtime
``` ```
The Python 2.7 ANTLR 3.1.3 runtime is not part of Debian packages. Install To install the ASN.1 compiler:
it with pip (or download and install manually the package):
```bash ```bash
$ pip install antlr_python_runtime singledispatch $ cd /opt
$ sudo wget http://www.semantix.gr/asn1scc/asn1Comp.tar.gz
$ sudo tar zxvf asn1Comp.tar.gz
$ echo 'export PATH=$PATH:/opt/asn1Comp/bin' >> ~/.bashrc
``` ```
On Windows: Check that it works:
You need to download and install Python, Pyside, and pip (binaries are
available on respective websites)
On FreeBSD: ```bash
$ asn1.exe
PySide is available through the ports. ```
You can also use easy_install to install it.
Use pip to install the ANTLR runtime (see above)
Automatic installation (recommended) OpenGEODE installation
------------------------------------ ----------------------
To install the application on your machine: To install the application on your machine, once all dependencies are met:
```bash ```bash
$ pip install --upgrade opengeode $ pip install --upgrade opengeode
...@@ -88,30 +89,13 @@ $ pip install --upgrade opengeode ...@@ -88,30 +89,13 @@ $ pip install --upgrade opengeode
This is sufficient to get opengeode running This is sufficient to get opengeode running
In addition OpenGEODE is capable of generating code for embedded, real-
time systems in the Ada programming language, with compact and efficient
data manipulation and binary encoding using the ASN.1 notation.
To get the full benefits of SDL and OpenGEODE, consider installing
TASTE, that is a complete development environment dedicated to
real-time, embedded systems from the European Space Agency.
TASTE also allows the transparent integration and communication between
models developed by commercial tools such as Matlab-Simulink and
Real-Time Developer Studio.
Installation from source Installation from source
------------------------ ------------------------
You can get the source from the TASTE repositories or from GitHub You can get the source from the TASTE repositories or from GitHub
```bash ```bash
$ svn co https://tecsw.estec.esa.int/svn/taste/trunk/misc/opengeode opengeode $ git clone https://github.com/maxime-esa/opengeode.git
```
Or
```bash
$ git clone https://github.com/maxime-esa/opengeode.git opengeode
``` ```
Then enter the opengeode directory and as root, type: Then enter the opengeode directory and as root, type:
...@@ -120,6 +104,8 @@ Then enter the opengeode directory and as root, type: ...@@ -120,6 +104,8 @@ Then enter the opengeode directory and as root, type:
$ make install $ make install
``` ```
Installation is optional. You can simply run opengeode.py to get it work.
Information and contact Information and contact
======================= =======================
...@@ -127,9 +113,16 @@ OpenGEODE is part of the TASTE project. ...@@ -127,9 +113,16 @@ OpenGEODE is part of the TASTE project.
Find more information and download at http://taste.tuxfamily.org Find more information and download at http://taste.tuxfamily.org
OpenGEODE is developed and maintained by Maxime Perrotin TASTE allows to create embedded software systems that combine SDL models with C, Ada,
Matlab-Simulink and a few other languages or tools.
OpenGEODE is mainly designed, developed and maintained by Maxime Perrotin
maxime (dot) perrotin (at) esa (dot) int maxime (dot) perrotin (at) esa (dot) int
The LLVM backend was designed and implemented by Diego Barbera during the ESA Summer of Code 2014
Some parts have been implemented by Laurent Meyer (native SDL type support in the parser)
The background pattern was downloaded from www.subtlepatterns.com The background pattern was downloaded from www.subtlepatterns.com
The ASN.1 compiler (ASN1Scc) that OpenGEODE is based on was The ASN.1 compiler (ASN1Scc) that OpenGEODE is based on was
......
...@@ -1452,12 +1452,15 @@ def primary_index(root, context): ...@@ -1452,12 +1452,15 @@ def primary_index(root, context):
if not is_integer(idx_bty): if not is_integer(idx_bty):
errors.append(error(root, 'Index is not an integer')) errors.append(error(root, 'Index is not an integer'))
else: else:
if float(idx_bty.Min) < float(r_min) or\ if float(idx_bty.Max) >= float(r_max):
float(idx_bty.Max) >= float(r_max):
errors.append(error(root, errors.append(error(root,
'Index outside of range [{} .. <{}]' 'Index range [{id1} .. {id2}] '
.format(r_min, 'outside of range [0 .. <{r2}]'
r_max))) .format(id1=idx_bty.Min, id2=idx_bty.Max,
r2=r_max)))
elif float(idx_bty.Min) > float(r_min):
warnings.append(warning(root,
'Index higher than range min value'))
else: else:
msg = 'Index can only be applied to type SequenceOf' msg = 'Index can only be applied to type SequenceOf'
errors.append(error(root, msg)) errors.append(error(root, msg))
...@@ -1527,12 +1530,18 @@ def selector_expression(root, context): ...@@ -1527,12 +1530,18 @@ def selector_expression(root, context):
field_name = root.children[1].text.replace('_', '-').lower() field_name = root.children[1].text.replace('_', '-').lower()
try: try:
if receiver_bty.kind == 'ChoiceType':
warnings.append(error(root, 'Wrong syntax for a CHOICE selector. '
'Use "var := {field}: value" instead of '
'"var!{field} := value"'
.format(field=field_name)))
for n, f in receiver_bty.Children.viewitems(): for n, f in receiver_bty.Children.viewitems():
if n.lower() == field_name: if n.lower() == field_name:
node.exprType = f.type node.exprType = f.type
break break
else: else:
msg = 'Field "{}" not found in expression {}'.format(field_name) msg = 'Field "{}" not found in expression {}'.format(field_name,
receiver.inputString)
errors.append(error(root, msg)) errors.append(error(root, msg))
except AttributeError: except AttributeError:
# When parsing for syntax or copy-paste, receiver_bty may # When parsing for syntax or copy-paste, receiver_bty may
...@@ -1782,6 +1791,7 @@ def composite_state(root, parent=None, context=None): ...@@ -1782,6 +1791,7 @@ def composite_state(root, parent=None, context=None):
comp.operators = dict(context.operators) comp.operators = dict(context.operators)
except AttributeError: except AttributeError:
LOG.debug('Procedure context is undefined') LOG.debug('Procedure context is undefined')
inner_proc = []
# Gather the list of states defined in the composite state # Gather the list of states defined in the composite state
# and map a list of transitionsi to each state # and map a list of transitionsi to each state
comp.mapping = {name: [] for name in get_state_list(root)} comp.mapping = {name: [] for name in get_state_list(root)}
...@@ -1807,7 +1817,8 @@ def composite_state(root, parent=None, context=None): ...@@ -1807,7 +1817,8 @@ def composite_state(root, parent=None, context=None):
warnings.extend(warn) warnings.extend(warn)
comp.content.textAreas.append(textarea) comp.content.textAreas.append(textarea)
elif child.type == lexer.PROCEDURE: elif child.type == lexer.PROCEDURE:
new_proc, err, warn = procedure(child, context=comp) new_proc, content, err, warn = procedure_pre(child, context=comp)
inner_proc.append((new_proc, content))
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
if new_proc.inputString.strip().lower() == 'entry': if new_proc.inputString.strip().lower() == 'entry':
...@@ -1855,6 +1866,11 @@ def composite_state(root, parent=None, context=None): ...@@ -1855,6 +1866,11 @@ def composite_state(root, parent=None, context=None):
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
comp.content.floating_labels.append(lab) comp.content.floating_labels.append(lab)
for proc, content in inner_proc:
# parse content of procedures - all scopes are set
err, warn = procedure_post(proc, content, context=comp)
errors.extend(err)
warnings.extend(warn)
for each in states: for each in states:
# And parse the states after inner states to make sure all CONNECTS # And parse the states after inner states to make sure all CONNECTS
# are properly defined. # are properly defined.
...@@ -1875,27 +1891,14 @@ def composite_state(root, parent=None, context=None): ...@@ -1875,27 +1891,14 @@ def composite_state(root, parent=None, context=None):
return comp, errors, warnings return comp, errors, warnings
def procedure(root, parent=None, context=None): def procedure_pre(root, parent=None, context=None):
''' Parse a procedure definition ''' ''' Parse a procedure interface - the content has to be parsed after
proc = ogAST.Procedure() all procedure interfaces are known, to prevent missing references '''
errors = [] errors = []
warnings = [] warnings = []
# Create a list of all inherited data proc = ogAST.Procedure()
try: content = []
proc.global_variables = dict(context.variables)
proc.global_variables.update(context.global_variables)
proc.global_timers = list(context.timers)
proc.global_timers.extend(list(context.global_timers))
proc.input_signals = context.input_signals
proc.output_signals = context.output_signals
proc.procedures = context.procedures
proc.operators = dict(context.operators)
except AttributeError:
LOG.debug('Procedure context is undefined')
# Gather the list of states defined in the procedure
# and create a mapping of transitions to each state
# (Note, procedures in OG currently do NOT support states)
proc.mapping = {name: [] for name in get_state_list(root)}
for child in root.getChildren(): for child in root.getChildren():
if child.type == lexer.CIF: if child.type == lexer.CIF:
# Get symbol coordinates # Get symbol coordinates
...@@ -1911,13 +1914,6 @@ def procedure(root, parent=None, context=None): ...@@ -1911,13 +1914,6 @@ def procedure(root, parent=None, context=None):
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
proc.content.textAreas.append(textarea) proc.content.textAreas.append(textarea)
elif child.type == lexer.PROCEDURE:
new_proc, err, warn = procedure(child, context=proc)
errors.extend(err)
warnings.extend(warn)
proc.content.inner_procedures.append(new_proc)
# Add procedure to the context, to make it visible at scope level
context.procedures.append(new_proc)
elif child.type == lexer.EXTERNAL: elif child.type == lexer.EXTERNAL:
proc.external = True proc.external = True
elif child.type == lexer.FPAR: elif child.type == lexer.FPAR:
...@@ -1925,27 +1921,68 @@ def procedure(root, parent=None, context=None): ...@@ -1925,27 +1921,68 @@ def procedure(root, parent=None, context=None):
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
proc.fpar = params proc.fpar = params
elif child.type in (lexer.PROCEDURE, lexer.START,
lexer.STATE, lexer.FLOATING_LABEL):
content.append(child)
else:
warnings.append(
'Unsupported construct in procedure, type: ' +
str(child.type) + ' - line ' + str(child.getLine()) +
' - string: ' + str(proc.inputString))
return proc, content, errors, warnings
def procedure_post(proc, content, parent=None, context=None):
''' Parse the content of a procedure '''
errors = []
warnings = []
# Create a list of all inherited data
try:
proc.global_variables = dict(context.variables)
proc.global_variables.update(context.global_variables)
proc.global_timers = list(context.timers)
proc.global_timers.extend(list(context.global_timers))
proc.input_signals = context.input_signals
proc.output_signals = context.output_signals
proc.procedures = context.procedures
proc.operators = dict(context.operators)
except AttributeError:
LOG.debug('Procedure context is undefined')
# Gather the list of states defined in the procedure
# and create a mapping of transitions to each state
# (Note, procedures in OG currently do NOT support states)
# proc.mapping = {name: [] for name in get_state_list(root)}
inner_proc = []
for child in content:
if child.type == lexer.PROCEDURE:
new_proc, content, err, warn = procedure_pre(child, context=proc)
inner_proc.append((new_proc, content))
errors.extend(err)
warnings.extend(warn)
proc.content.inner_procedures.append(new_proc)
# Add procedure to the context, to make it visible at scope level
context.procedures.append(new_proc)
elif child.type == lexer.START: elif child.type == lexer.START:
# START transition (fills the mapping structure) # START transition (fills the mapping structure)
proc.content.start, err, warn = start(child, context=proc) proc.content.start, err, warn = start(child, context=proc)
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
elif child.type == lexer.STATE: # elif child.type == lexer.STATE:
# STATE - fills up the 'mapping' structure. # # STATE - fills up the 'mapping' structure.
newstate, err, warn = state(child, parent=None, context=proc) # newstate, err, warn = state(child, parent=None, context=proc)
errors.extend(err) # errors.extend(err)
warnings.extend(warn) # warnings.extend(warn)
proc.content.states.append(newstate) # proc.content.states.append(newstate)
elif child.type == lexer.FLOATING_LABEL: elif child.type == lexer.FLOATING_LABEL:
lab, err, warn = floating_label(child, parent=None, context=proc) lab, err, warn = floating_label(child, parent=None, context=proc)
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
proc.content.floating_labels.append(lab) proc.content.floating_labels.append(lab)
else: for new_proc, content in inner_proc:
warnings.append( # parse content of procedures
'Unsupported construct in procedure, type: ' + err, warn = procedure_post(new_proc, content, context=proc)
str(child.type) + ' - line ' + str(child.getLine()) + errors.extend(err)
' - string: ' + str(proc.inputString)) warnings.extend(warn)
for each in proc.terminators: for each in proc.terminators:
# check that RETURN statements type is correct # check that RETURN statements type is correct
if not proc.return_type and each.return_expr: if not proc.return_type and each.return_expr:
...@@ -1969,6 +2006,17 @@ def procedure(root, parent=None, context=None): ...@@ -1969,6 +2006,17 @@ def procedure(root, parent=None, context=None):
continue continue
for each in chain(errors, warnings): for each in chain(errors, warnings):
each[2].insert(0, 'PROCEDURE {}'.format(proc.inputString)) each[2].insert(0, 'PROCEDURE {}'.format(proc.inputString))
return errors, warnings
def procedure(root, parent=None, context=None):
''' Parse a procedure - call sequentially the pre- and post- functions
This function is called by the syntax checker only '''
proc, content, errors, warnings = procedure_pre(root, parent, context)
err, warn = procedure_post(proc, content, parent, context)
errors.extend(err)
warnings.extend(warn)
return proc, errors, warnings return proc, errors, warnings
...@@ -2360,6 +2408,7 @@ def process_definition(root, parent=None, context=None): ...@@ -2360,6 +2408,7 @@ def process_definition(root, parent=None, context=None):
process.filename = node_filename(root) process.filename = node_filename(root)
process.parent = parent process.parent = parent
proc_x, proc_y = 0, 0 proc_x, proc_y = 0, 0
inner_proc = []
# Prepare the transition/state mapping # Prepare the transition/state mapping
process.mapping = {name: [] for name in get_state_list(root)} process.mapping = {name: [] for name in get_state_list(root)}
for child in root.getChildren(): for child in root.getChildren():
...@@ -2408,8 +2457,9 @@ def process_definition(root, parent=None, context=None): ...@@ -2408,8 +2457,9 @@ def process_definition(root, parent=None, context=None):
# Number of instances - discarded (working on a single process) # Number of instances - discarded (working on a single process)
pass pass
elif child.type == lexer.PROCEDURE: elif child.type == lexer.PROCEDURE:
proc, err, warn = procedure( proc, content, err, warn = procedure_pre(
child, parent=None, context=process) child, parent=None, context=process)
inner_proc.append((proc, content))
errors.extend(err) errors.extend(err)
warnings.extend(warn) warnings.extend(warn)
process.content.inner_procedures.append(proc) process.content.inner_procedures.append(proc)
...@@ -2433,11 +2483,20 @@ def process_definition(root, parent=None, context=None): ...@@ -2433,11 +2483,20 @@ def process_definition(root, parent=None, context=None):
elif child.type == lexer.COMMENT: elif child.type == lexer.COMMENT:
process.comment, _, _ = end(child) process.comment, _, _ = end(child)
else: else:
warnings.append('Unsupported process definition child: ' + warnings.append(['Unsupported process definition child: ' +
sdl92Parser.tokenNames[child.type] + sdl92Parser.tokenNames[child.type] +
' - line ' + str(child.getLine())) ' - line ' + str(child.getLine()),
[proc_x, proc_y], []])
for proc, content in inner_proc:
err, warn = procedure_post(proc, content, context=process)
errors.extend(err)
warnings.extend(warn)
for each in chain(errors, warnings): for each in chain(errors, warnings):
each[2].insert(0, 'PROCESS {}'.format(process.processName)) try:
each[2].insert(0, 'PROCESS {}'.format(process.processName))
except AttributeError as err:
LOG.debug(str(err))
LOG.error('Internal error - please report "{}"'.format(str(each)))
errors.extend(perr) errors.extend(perr)
return process, errors, warnings return process, errors, warnings
...@@ -3423,6 +3482,9 @@ def assign(root, context): ...@@ -3423,6 +3482,9 @@ def assign(root, context):
) )
expr.kind = 'assign' expr.kind = 'assign'
if len(root.children) != 2:
errors.append('Syntax error: {}'.format(expr.inputString))
if root.children[0].type == lexer.CALL: if root.children[0].type == lexer.CALL:
expr.left, err, warn = call_expression(root.children[0], context) expr.left, err, warn = call_expression(root.children[0], context)
elif root.children[0].type == lexer.SELECTOR: elif root.children[0].type == lexer.SELECTOR:
...@@ -3535,7 +3597,8 @@ def for_loop(root, context): ...@@ -3535,7 +3597,8 @@ def for_loop(root, context):
basic = find_basic_type(start_expr.exprType) basic = find_basic_type(start_expr.exprType)
r_min = basic.Min if basic != UNKNOWN_TYPE else '0' r_min = basic.Min if basic != UNKNOWN_TYPE else '0'
basic = find_basic_type(stop_expr.exprType) basic = find_basic_type(stop_expr.exprType)
r_max = basic.Max if basic != UNKNOWN_TYPE else '4294967295' r_max = str(int(float(basic.Max) - 1)) \
if basic != UNKNOWN_TYPE else '4294967295'
# basic may be UNKNOWN_TYPE if the expression is a # basic may be UNKNOWN_TYPE if the expression is a
# reference to an ASN.1 constant - their values are not # reference to an ASN.1 constant - their values are not
# currently visible to the SDL parser # currently visible to the SDL parser
...@@ -3709,6 +3772,9 @@ def pr_file(root): ...@@ -3709,6 +3772,9 @@ def pr_file(root):
# Can happen if DataView.py is not there # Can happen if DataView.py is not there
LOG.info('USE Clause did not contain ASN.1 filename') LOG.info('USE Clause did not contain ASN.1 filename')
LOG.debug(str(err)) LOG.debug(str(err))
except TypeError as err:
errors.append('ASN.1 compiler execution failed')
LOG.debug(str(err))
for child in systems: for child in systems:
LOG.debug('found SYSTEM') LOG.debug('found SYSTEM')
......
...@@ -22,7 +22,7 @@ dcl VAR5 mychoice; ...@@ -22,7 +22,7 @@ dcl VAR5 mychoice;
DECISION var1 DECISION var1
/* CIF COMMENT (615, 128), (191, 35) */