-----------------------
OpenComal Documentation
-----------------------			    

Version:	0.2.9
I am:		Jos Visser <josvisser66@gmail.com>
Date: 		Wed Sep 20 21:04:18 CEST 2006

ALSO SEE
--------
- whitepaper1.txt for information on STATIC and MODULES


TODO
----
- Document the array rvalue stuff that changed in 0.2.5-pre3
- Document CHDIR, MKDIR, RMDIR, KEY$ and INKEY$
- Document UPPER$ and LOWER$ functions
- Document GET$ function
- Document COPY statement


1. Intro Info

This documentation file describes OpenComal. OpenComal is an 
implementation of the Comal language. The OpenComal sources are covered 
by the GNU General Public License.

OpenComal is written in C and special care has been taken to
guarantee its portability to other hardware platforms. All
system dependent code has been externalized in a separate module
with clearly defined entry points. A port should involve a
re-design of this system dependent module and a recompilation of
the OpenComal sources. A system independent stub (pdcdsys.c) has been 
provided which maps system dependent functions onto standard C 
functions. The interpreter will function as normal but special 
features such as cursor positioning, line editing and advanced memory 
allocation are not or only rudimentarily available.

The system dependent module of OpenComal also contains entry
points to facilitate the extension of OpenComal with new
PROCedures and FUNCtions whose definition can be in C. It is the
intention of the author that interfaces to windowing and
database systems and the like are implemented through these
defined entry points.

The author can be contacted at:

Jos Visser
<josvisser66@gmail.com>
http://www.josvisser.nl/opencomal


2. What is Comal

In the early history of micro computing, resources (CPU, memory,
disk) were scarce, slow and expensive. Micro computers were
usually distributed with limited memory capacity and limited on
board software.  The famous-in-it's-own-time ZX80 (by Sinclair)
probably set an all time record low with 4K ROM and 1K RAM.

BASIC was the language of choice back then. Almost all micro
computers featured their own dialect of BASIC, usually present
in ROM. These BASICs were basic indeed. Most of the time they
lacked about everything necessary to develop well-structured
and maintainable programs.

This situation led to bad-programming habits spreading like
wildfire. Would-be programmers were not encouraged to produce
clear program code, and in order to make the programs smaller,
faster and more attractive many tricks were used like directly
modifying system variables (the notorious POKE instruction),
using multi statement lines, using GOTO's etc. etc.

The principles of structured programming were available of
course, but structured languages like PASCAL were not really
available for small micro's due to limitations in the micro's
resource capacity and the then available compiler technology.

Somewhere in Denmark a teacher named Borge Christensen
understood the potential dangers of the BASIC habits and he
leaded a team of people who were determined to modify an
available BASIC interpreter so as to create a new language which
should support structured programming concepts like PROCedures,
FUNCtions and GOTO-less loops. The first Comal (COMmon
Algorithmic Language) interpreter was born.


3. Commercially available Comal

Comal has been available on a number of popular micro computers
and/or operating systems. A short, and surely non-exhaustive,
list follows:

MsDos		:	Comal, by UniComal
CP/M		:	Comal-80, by the Danish Regnecentrale
Commodore 64	:	Comal cartridge, by UniComal
BBC Micro	:	Comal ROM, by AcornSoft


4. OpenComal

In 1992 I went on an unplanned sabbatical of four months or so. With all
this extra time on my hands, I decided to create a free Comal
interpreter with the following features:

	- Free software (although I did not know that phrase at that
	  time).
	- Containing numerous ethically justifiable extensions 
	  to the basic Comal specifications
	- Highly portable
	- Containing no built in limits to program and variable size
	  (which is somewhat of a challenge on MsDos).

I created OpenComal (then called Public Domain Comal (or PDComal)) on an
XT PC (8088 CPU) running MsDos using Turbo C. I did however fathom
porting to Unixes and other platforms, so everything was written in
pretty portable K&R C, with all operating system dependencies separated
out in a set of routines in one source file (e.g. pdclinux.c).

Over the last ten years, I have been tweaking with OpenComal a bit, but
not regularly. The Comal movement has all but disappeared, which is a
shame because I think it is a nice language to start programming with...

And right now, in 2002, I am on yet another (this time planned)
sabbatical, and I decided to rename PDComal to OpenComal, attach the GPL
to it, improve Linux keyboard/screen support (using ncurses) and release
it to the general public. Let's see what happens....
	  
Apart from the interpreter (opencomal), a run-time only unit is
provided (opencomalrun) which contains all the code necessary to load
and execute a SAVEd OpenComal program.


5. (Open)Comal concepts

5.1 Program

A Comal program consists of a number of Comal program lines.
Each program line contains a line number, an optional Comal
statement and an optional comment. Line numbers are used for
editing purposes only!  Comal commands are available to save,
load, run and manipulate programs. Only syntaxically correct
lines can be entered into the program.

Only one program can be in memory at the same time, however,
OpenComal supports EXTERNAL PROCedures and FUNCtions which are
loaded from disk on demand.

Comal program listings (on screen or to file) are automatically 
indented and capitalized in order to create an esthetically appealing 
view of the structure of the program.

Before execution (RUN) of a program, it is SCANned for errors
such as incorrect program structure use (e.g. LOOP not closed
with ENDLOOP, IMPORT not from within a PROC or FUNC, RETURN
<exp> within a PROC).  Only correct programs can be RUN.


5.2 Variables

Comal supports three types of variables:

	- Integer
	- Floating point
	- String
	
A variable's type is reflected in its name. String variables
are suffixed with a $, integer variables with a #. E.g:

	Integer:		a#, sum#, aap#
	Floating point:		angle, mortgage, banaan
	String:			name$, title$, fruit$
	
In early Comal's, all string variables had to be explicitly
DIMensioned to a certain length, like:

	DIM aap$ OF 20
	
In OpenComal this restriction has been relaxed. If a string
variable is DIMensioned, the interpreter will maintain the
string with the given maximum length in mind. Assignments to the
string will be truncated if necessary. However, in OpenComal a
string variable need not be dimensioned. Such an undimensioned
string variable has no set maximum length.

The value ranges of each type depends on the C compiler OpenComal
has been compiled with. See the system specific documentation file for 
more information on this.


5.3 Assisted entry

Comal allows a lot of flexibility in entering Comal
statements. = may be input for :=, # for FILE and cosmetic
keywords like DO, THEN, OF etc. need not be input at all.


5.4 Escape

The execution of OpenComal programs, INPUT and the LIST command
can be interrupted with an escape. What the escape key is
depends on the OpenComal implementation as most of the escape key
processing is handled in the system dependent module (for Linux it is
Ctrl-C).

Processing of the escape key while running a program can be
modified with the TRAP ESC statement.


6. OpenComal keywords and tokens

6.1 Operators

Comal operators are used to combine two values to form a new
one according to the operator's definition.

General syntax:		<exp> <operator> <exp>

Used on numeric, returns numeric:

	x-y		: x minus y
	x*y		: x times y
	x/y		: x divided by y
	x^y		: x to the power y
	x DIV y		: integer division of x and y
	x MOD y		: remainder after integer division x and y
	x EOR y		: x exclusive or y
	x OR y		: x or y
	x AND y		: x and y
	x AND THEN y	: x and y, y is not evaluated if x is false
	x OR THEN y	: x or y, y is not evaluated if x is true

Used on strings and numerics, returns strings and numeric:

	x+y		: x plus y

Used on strings, returns numerics:

	x in y		: returns position of string x in string y.
	
Used on strings and numerics, returns numeric (False=0, True= not 0)

	x=y		: x equals y
	x<y		: x smaller then y
	x>y		: x greater then y
	x<=y		: x less then or equal to y
	x>=y		: x greater then or equal to y
	x<>y		: x not equal to y


6.2 Assignment operators

The three Comal assignment operators assign a value to a
variable (possibly a member of an array).

General syntax:		<lvalue> <assignop> <exp>

OpenComal knows three assignment operators:

	:=		: simple assignment (may be entered as =)
	:+		: adds the <exp> to the current value of <lvalue>
	:-		: subtracts <exp> from the <lvalue>

When assigning to a string lvalue the <exp> string is truncated
as is necessary for the DIMensioned string length. When
assigning to a substring the <exp> string is truncated or padded
with spaces as is required for the substring.

Multiple assignments can be specified on 1 program line,
separated by a semicolon.

If the target of the assignment is an array then all elements of
the array are assigned the same value:

Example:		a:=7
			b:+1; c:=9; a$:="Jos Visser"
			k:-1
			counter(8):+2
			b$(8,6):="aap" 
			a$(1:4):="xxxx" // Substring assignment
			b$(8)(1:2):="yy"
			c$(:n#:)=a$(:2:)
			
			DIM a(8)
			a=99
			
			
			
6.3 OpenComal built-in Functions

General syntax:		<func>(<exp>)

Takes numeric argument, return numeric:

	ABS	: absolute value
	ACS	: arc cosine
	ASN	: arc sine
	ATN	: arc tangent
	COS	: cosine
	DEG	: how many degrees (0-360) is the radian argument
	EOF	: end of file reached on specified file?
	EXP	: argument to the power of e
	FRAC	: Fractional part of argument
	INT	: integer part of argument
	LN	: natural logarithm (e log) 
	LOG	: 10 log
	NOT	: not x (not true=false, not false=true)
	RAD	: how many radians (0-2pi) is the degree argument
	ROUND	: Rounds argument with respect to fractional part 0.5
	RND	: Random value generator.
	            RND       yields a floating point number between 0 and 1
		    RND(x)    yields a whole number between 0 and x
		    RND(x,y)  yields a whole number between x and y
		    "between" here also means "including"
	SGN	: returns -1,0,1 depending on sign of argument
	SIN	: sine
	SQR	: square root
	TAN	: tangent

Takes string argument, returns numeric:

	VAL	: numeric value of string argument
	ORD	: numeric systems collating sequence code of first 
  		  character in string argument (usually ASCII code)
	LEN	: length of argument string


Takes numeric argument, returns string:

	CHR$	: returns string containing of 1 character, the character
		  whose position in the systems collating sequence is
		  specified by the numeric argument.
	STR$	: Returns string representation of numeric argument


Takes no argument, returns numeric:

	EOD	: end of data reached (all DATA statements processed)
	ERR	: last error
	ERRLINE	: line number of line where last error occurred
	FALSE	: 0=1
	TRUE	: 0=0
	PI	: ACS(-1)


Takes no argument, returns string:

	ERRTEXT$: text of last error


An overview of all OpenComal keywords:
	
6.4 APPEND

Modifier of OPEN to indicate that the sequential file is open
for WRITE and data should be appended to the file.

See OPEN.


6.5 AUTO

Command facilitate the input of program lines:

General syntax:		AUTO [<start>[,<increment>]]

The AUTO command generates line numbers as is specified by
<start> and <increment>. The program lines can immediately be
input.


6.6 CASE

This OpenComal program structure indicates an n-way selection:

General syntax:		CASE <exp> OF
			  WHEN <exp1>,<exp2>,....,<expn>
			    <comal line>
			    <comal line>
			  WHEN <relop><exp3>,<exp4>,...
			    <comal line>
			    <comal line>
			  ...
			  OTHERWISE
			    <comal line>
			    <comal line>
			ENDCASE

The expression <exp> is evaluated (once!) and compared with the
different WHEN expressions. If no relational operator is
provided the expressions are tested for equality. If no WHEN
expressions matches the next WHEN statement is processed. If no
WHEN statements match, program flow is passed to the statements
following the OTHERWISE clause. If a matching WHEN exists the
statements after that WHEN are executed, after which control is
passed to the statement after the ENDCASE. An OTHERWHISE need
not be present.

Example:
       10 FOR f:=1 TO 10 DO
       20   PRINT "Kees is ";f
       30   CASE f OF
       40     // test kees
       50   WHEN 1
       60     PRINT "een"
       70   WHEN <=2
       80     PRINT "kleiner gelijk 2:"
       90   WHEN 6, 7
      100     PRINT "zes of zeven"
      110   WHEN >9
      120     PRINT "groter negen"
      130   OTHERWISE
      140     PRINT "none of the above"
      150   ENDCASE
      160   //
      170 ENDFOR


6.7 CLOSE

CLOSE is used to close open files.

General Syntax:		CLOSE [FILE <exp1>[,<exp2>,<exp3>,...]]

CLOSE with no parameters closes all open FILEs.

Example:		CLOSE
			CLOSE FILE 1,5,infile#
			
			
6.8 CLOSED

CLOSED is a modifying keyword to specify that PROCedures and
FUNCtions have their own variable pool.

See PROC.


6.9 CON

With the CON command an interrupted program (STOP, escape or
error) can continue it's processing at the interrupted line. In
case of a STOP interruption the program is continued at the line
after the STOP.

Certain program modifications during interruption (such as
modifying the current line or adding a program structure line)
inhibit continuation.

General syntax:		CON


6.10 CURSOR

With the CURSOR statement the video output cursor can be
positioned somewhere on the output medium.

General syntax:		CURSOR <exp1>,<exp2>

The CURSOR statement is executed by the system dependent part of
OpenComal. Its behaviour is not defined by OpenComal.


6.11 DATA

With the DATA statement a fixed list of constant or variable
expressions can be specified for subsequent READ actions.

General Syntax: 		DATA <exp>,<exp>,<exp>,...

Every program has a current DATA pointer. At the start of the
program this pointer is initialized to the first DATA line of
the program. Each READ statement reads the current DATA value
and advances the DATA pointer to the next DATA value, skipping
lines if necessary. The EOD functions becomes true if the DATA
pointer does not point to any valid DATA value (e.g. no DATA
lines in program or last DATA value has been READ).

With RESTORE and RESTORE <id> the DATA pointer can be moved. See
RESTORE for more information.

OpenComal allows variable and constant expressions as DATA values.

Example: 		10 b:=7 
			20 WHILE NOT(EOD) DO 
			30   READ a 
			40   PRINT a
			50 ENDWHILE 
			60 // 
			70 DATA 1,2,b+8,"Jos Visser"
		

6.12 DELETE

Synonym for DEL.


6.13 DEL

The DEL keyword is used to delete program lines (DEL command)
and to delete external files (DEL statement).

General Syntax:		DEL <stringexp>
			DEL <line range>
			
A DEL line range can be specified like this:

		100		only line 100
		-100		from 1st line up to and including line 100
		100-		from line 100 onwards
		100-200		from line 100 up to and including line 200

Specifying no line range defaults to the whole program (line
1-MAXINT).  However, this is not allowed with DEL.
		
		
6.14 DIM

The DIM statement is used to define arrays and string lengths.

General syntax:		DIM <stringvar> OF <exp>, ...
			DIM <var>(<dimlist>) [OF <exp>], ...
			
When dimensioning a string variable or a string array to a
maximum length the interpreter will take care to maintain the
string to it's given maximum length.

When dimensioning an array an upper bound to it's dimension must
be specified. If no lower bound is specified it defaults to 1.

Example:		DIM a$ OF 4, b$ OF 6
			DIM matrix(8,9), reeks(-100:100)
			DIM naam$(2:6,-1:1) OF 56
			
6.14a DIR and DIR$

The DIR statement can be used to obtain a directory listing. The DIR$
string function yields the present working directory.

General syntax:		DIR [<stringexp>]
			DIR$

The exact output of DIR depends on the platform specific implementation.
For instance under Linux, the DIR statement calls the external "ls"
command so the output resembles an "ls -l" display.

Example:		DIR "*.cml"
			DIR
			PRINT DIR$


6.15 DO

DO is an auxilliary keyword used with WHILE. See WHILE.


6.16 DOWNTO

DOWNTO is used to specify a FOR loop with a decreasing counter
value.  See FOR.


6.17 DYNAMIC

The DYNAMIC keyword is used to specify that an EXTERNAL PROC or
FUNC should be reloaded at every call. See PROC.


6.18 EDIT

The EDIT command is used to edit a range of existing program
lines.

General syntax:			EDIT <line range>

The EDIT line range specification adheres to the previously
explained DEL line range semantics. EDIT without a line range
specification offers every line in the program for editing.


6.19 ELIF

ELIF is used in constructing a multi-way IF. See IF.


6.20 ELSE

The ELSE keywords specifies the start of the alternative
statement section in a multi line IF. See IF.


6.21 END

The END statements halts all program execution and returns
control to the interpreter's command loop. The program can not
be CONtinued after an END.

When executing in command mode, the END command clears the program run
environment.

6.22 ENDCASE

Specifies the end of an n-way selection CASE statement. See
CASE.


6.23 ENDFOR

Specifies the end of a multi-line FOR loop. See FOR.


6.24 NEXT

Synonym for ENDFOR.


6.25 ENDFUNC

Specifies the end of a FUNCtion definition. See FUNC.


6.26 ENDIF

Specifies the END of a multi-line IF construct. See IF.


6.27 ENDLOOP

Specifies the end of a LOOP-ENDLOOP construct. See LOOP.


6.28 ENDPROC

Specifies the end of a PROCedure definition. See PROC.


6.29 ENDTRAP

Specifies the end of an error trapping TRAP/HANDLER/ENDTRAP
construct.  See TRAP.


6.30 ENTER

The ENTER command is used to input program lines from a file.

General syntax:			ENTER "filename"

With ENTER program lines are input from the file and inserted in
the program as if the program lines has been entered from the
keyboard. The file can only contain program lines and no direct
statements or commands.


6.31 ENDWHILE

Specifies the end of a multi-line WHILE loop. See WHILE.


6.31a ENV

General syntax:			ENV 
				ENV <id>

The ENV command is used to switch between different programs that are 
in memory simultanuously. Each environment can contain an entire 
program with its own procedures, functions and variables.  At each 
moment in time, one environment is the current environment.  Commands 
like NEW, LOAD, SAVE et cetera act on the current environment. 

The ENV command can be used to switch from environment to environment.
Each environment has a name. An environment is automatically
created upon first activation of it. Using ENV without a name
argument provides a list of the environments in existence.

6.32 EXEC

The EXEC statement is included for compatibility with older
Comal versions. It can prelude procedure call statements. See
Procedure Call.


6.33 EXIT

The EXIT statement is used to exit from the nearest enclosing
LOOP/ENDLOOP. See LOOP.


6.34 EXTERNAL

The EXTERNAL keyword is used to specify that a PROCedure or
FUNCtion definition is not included in the program but that it
should be loaded from an external file that was previously
SAVEd. 

See PROC.


6.35 FILE

The FILE keyword is used with OPEN, READ, WRITE, PRINT, INPUT
and CLOSE to specify the file number and optionally the random
file record number a certain statement is to act on.


6.36 FOR

The FOR statement specifies a loop that is iterated a fixed
number of times under the control of a FOR (or index) variable.

General syntax:	FOR <lval>:=<exp> TO|DOWNTO <exp> [STEP <exp>] DO
		  ...
		  ...
		ENDFOR
		
		FOR <lval>:=<exp> TO|DOWNTO <exp> [STEP <exp>] DO <stat>
		
The FOR loop variable is assigned and gets incremented or
decremented at every iteration. If a STEP clause is not present
it defaults to 1.  DOWNTO signifies a negative step. The FOR
loop behaves like a WHILE loop, i.e.: the test whether the loop
should be left or iterated is evaluated beforehand. For example,
in the following cases the loop statements are not executed:

		FOR f:=10 TO 0 DO
		FOR f:=0 TO 10 STEP -1 DO
		FOR f:=10 DOWNTO 0 STEP -1 DO

Short and long forms exist of the FOR loop. In the short form
the DO is immediately followed by a simple statement (e.g., no
program structure statement): FOR f:=-1 to 1 DO PRINT f
		
No ENDFOR need be present in the short form.

Examples:	FOR a(9):=10 DOWNTO 0 STEP 2 PRINT a(9)

		FOR angle:=0 TO 2*PI STEP 0.1 DO
		  ...
		ENDFOR
		
		FOR i:=i^2 TO i^3 STEP i DO PRINT i
		
		
6.37 FUNC

Specifies the start of a FUNCtion definition. 

See PROC.


6.38 IMPORT

The IMPORT statement imports variables into a CLOSED
environment.

General syntax:		IMPORT [<id>:],<id>[()],...

In a CLOSED PROCedure or FUNCtion no variables from any of the
calling environments are visible. Furthermore all new variables
are local to the current environment and do not influence any
calling environment.  With the IMPORT statement the definitions
of variables from a calling environment can be imported into the
current environment. Modification of an IMPORTED variable also
affects the variable in its own environment.

OpenComal allows the IMPORT statement to specify from which
calling environment the variable should be imported. The calling
stack is reversly traversed and the variables are imported from
the first environment with the specified name (PROC/FUNC name,
_program for the main program).

If no identifier is specified variables are imported from the
current environments parent environment. The parent environment
is the nearest enclosing CLOSED environment. For a non-nested
PROC/FUNC this means the enviroment of the main program. For a
nested PROC/FUNC the parent environment is the environment of
the most nested enclosing CLOSED PROC or FUNC.

() must be used to import an array.

Examples:		IMPORT aap:a, b(), c$
			IMPORT _program: tabel()
			IMPORT any_var$, bny_var$
			

6.39 GLOBAL

Synonym for IMPORT.


6.40 HANDLER

Specifies the start of the error handling statements of a
TRAP/HANDLER/ENDTRAP structure. See TRAP.


6.41 IF

The IF statement is used to selectively execute OpenComal
statements according to the truth value of an expression.

General syntax:		IF <exp> THEN <simplestat>

			IF <exp> THEN
			  ...
			ELIF <exp>
			  ...
			ELSE
			  ...
			ENDIF
			
The short form IF evaluates the expression and then either
executes the simple statement or not. Control is then passed to
the statement following the IF.

The long form IF evaluates the expression and then either
executes the statements between the IF and the corresponding
ELIF, ELSE or ENDIF. If the IF expression does not evaluate to
TRUE OpenComal hops to the next ELIF and evaluates that
expression. If this evaluates to TRUE the statements between the
ELIF and the corresponding ELIF, ELSE or ENDIF are executed.
Multiple ELIFs can be present. If all ELIF's have been dealt
with and no ELIF expression has evaluated to TRUE the ELSE
statements are executed.

No ELIF or ELSE need be present in the long form IF. If an ELSE
clause is present it may not be followed by an ELIF.

Example:		IF a=b THEN PRINT "eql"

			IF a=b THEN
			  PRINT "eql"
			ENDIF
			
			IF a=b THEN
			  PRINT "eql"
			ELSE
			  PRINT "neq"
			ENDIF
			
			IF a=b THEN
			  PRINT "eql"
			ELIF a=c 
			  PRINT "a eql c"
			ELSE 
			  PRINT "neq"
			ENDIF
			

6.42 INPUT

With the INPUT statement data is read from a file or from the
keyboard and assigned to program variables.

General syntax:		INPUT FILE <exp>[,<exp>]: <lvallist>
			INPUT [<string>:]<lvallist>
			
INPUT FILE reads data from the specified file. If the file has
been opened for RANDOM a record number must be specified. The
other form of INPUT reads data from the keyboard or the current
input file (see also: SELECT INPUT). Optionally a string is
printed before the data is input.

If a variable is an array, INPUT reads one value and assigns
that value to every member of the array!!! (as opposed to READ
which reads and assigns n values)

INPUT FILE processes data from files written by OpenComal programs
with WRITE FILE or PRINT FILE.

INPUT reads data from the keyboard. Multiple values must be
separated by a comma. If a comma must be input as a part of a
string variable, enclose the keyboard input with ".

Example:		INPUT "Enter your choice :":c
			INPUT FILE 5,recno#:a,b,c
			INPUT name,number

Note: As a special case: when inputting a string variable the rest
of the line, including any leading spaces, are assigned to the last
string variable in the input statement. So, in order to read a line,
including leading spaces, just use INPUT line$.

6.43 LIST

The LIST command is used to list program lines.

General syntax:			LIST <linerange>[,<filename>]
				LIST <id>[,<filename>]

The LIST line range can be specified as with the DEL command. If
no line range is mentioned the whole program is listed. If the
LIST command specifies an identifier the PROC or FUNC in the
program with that name is listed. By specifying a filename
LIST's output is redirected to a file. The file thus created can
be ENTERed.

Depending on the system, LIST can provide paged output, where listing is
temporarily halted after a screenful of data. On Linux, <space> and
<return> continue the listing (for another page or just one line),
whereas Ctrl-C and 'q' terminate the listing.

Example:			LIST
				LIST -200
				LIST "aap"
				LIST 100-200,"aap"
				LIST print_proc,"file"
				

6.44 LOCAL

The LOCAL statement introduces variables and arrays that are
local to the current environment even though that environment is
not CLOSED.

General syntax:		LOCAL <var>,<var$> OF <exp>, <var>(<dimlist>)

Any variables that a non-CLOSED PROC or FUNC introduces are
added to the parent environment of the PROC or FUNC (for a
description of the parent environment, see IMPORT). With LOCAL
you can make new variables that are not added to the parent
environment but to the current environment. Any variables with
the same name in any of the calling enviroments are not
affected.

LOCAL can contain DIM-like definitions of strings and arrays.

Example:		LOCAL keuze#, a$ OF 20, matrix(20,20)
			LOCAL name$(10) OF 40


6.45 LOAD

The LOAD command is used to replace the program in memory with a
previously SAVEd program.

General syntax:			LOAD "filename"
				LOAD
				
If no filename is given the filename last LOADed or SAVEd is
used.


6.46 LOOP

The LOOP keyword signifies the beginning of a LOOP/ENDLOOP
iteration of OpenComal statements.

Syntax:				LOOP
				  ..
				  ..
				ENDLOOP
				
The statements between LOOP and ENDLOOP are repeatedly executed.
A LOOP/ENDLOOP loop can be left with an EXIT statement:

			EXIT
			EXIT WHEN <exp>
			IF <exp> THEN EXIT
				
EXIT transfers control to the statement after the ENDLOOP of the
nearest enclosing LOOP. EXIT itself may be nested inside other
IF's, REPEAT's, WHILE's etc.


6.47 NAME

The NAME keyword is used to specify pass-by-name parameter
passing. See PROC.


6.48 NEW

The NEW command removes the current program from memory.


6.49 NULL

Does nothing.


6.50 OF

OF is used as a cosmetic keyword with CASE.


6.51 OPEN

With the OPEN statement external files can be opened for
subsequent processing.

General syntax:		OPEN FILE <exp>,<stringexp>,<type>
			with type =	READ
					WRITE
					RANDOM <exp> [READ ONLY]
					APPEND
					
The external file is designated by it's name (the string
expression of OPEN). The specified file type determines which
access is possible to the file:

READ		only READ FILE and INPUT file allowed
WRITE		READ FILE, INPUT FILE, PRINT FILE and WRITE FILE allowed
APPEND		like WRITE but opens an existing file and appends data
		at the file's tail
RANDOM		See below.

The user specified file number is the file's identification
within the program. Ideally all OPEN files should be CLOSEd as
well, however, OpenComal closes open files when necessary (e.g.,
at QUIT, NEW, RUN).

Random files are files which are logically segmented into
records with a fixed and pre-determined record length. This
record length must be specified at OPEN. OpenComal keeps no
administration of this record length. It is the user's
responsibility to specify the correct length at every OPEN.

Random files are opened for READ and WRITE by default, however
by specifying READ ONLY the file is opened for read only.

Actions on random files require a record number to be specified:

		FILE <exp>,<exp>
		
The first <exp> specifies the file number by which a file has
been opened. The second <exp> specifies the random record
number.

Random record sizes should be carefully calculated beforehand.
Unfortunately, the size of a data item can vary from one
implementation to another so no basic guidelines can be given.
OpenComal writes a data item to a file as follows:

Integer:	1 byte type, k bytes data
Float:		1 byte type, n bytes data
String:		1 byte type, k bytes length, p bytes data

with:		p=LEN(string$)
		k=sizeof an integer 
		n=sizeof a floating point value

Example for an Msdos/Turbo C implementation of OpenComal:

Integer:	1 byte type, 4 bytes integer data
Float:		1 byte type, 8 bytes floating point data
String:		1 byte type, 4 bytes length of string, p bytes data

In my personal opinion this aspect of Comal has always been very
weak since it requires the programmer to be much to familiar
with the underlying machine implementation. I am working on a
different (structured) approach towards working with files in
OpenComal.

Example:	OPEN FILE 1,"aap",READ
		OPEN FILE 2,filename$,RANDOM 40 READ ONLY
		

6.52 OS, PASS

With the OS statement the programmer can send commands to the
host operating system. PASS is an alias for OS (from UniComal?)

General syntax:		OS <stringexp>

OpenComal does not process the command in any way but passes it on
to the operating system. On DOS/Windows systems providing an empty
string spawns an operating system subshell (if you can call COMMAND.COM
or CMD.EXE a "shell", that is :-)

Example:		OS "dir >dir.dir"
			OS "format "+disk$+":"
			OS "Z EOD"
			

6.53 OTHERWISE

The OTHERWISE clause is used to specify the start of the OpenComal
program lines that should be executed if no WHEN-clause of a
CASE statement can be activated. See CASE.


6.54 PAGE

The PAGE statement usually clears the screen. However, because
PAGE is entirely executed by the system dependent module no
exact definition can be given.


6.55 PRINT

With the PRINT statement data can be printed on the output
screen or to an external file.

General syntax:		PRINT FILE <exp>[,<exp>]:<exp list>
			PRINT <exp list>
			PRINT USING <stringexp>:<num exp list>

Basic PRINT evaluates the expressions in the expression list and
prints their values on the screen or onto the current SELECT
OUTPUT file.  Values in the list may be separated by , and ;.
There is no difference between , and ;. Data is printed as is.
If the last element of the expression list is followed by ; or ,
then the cursor will not skip to a new line, otherwise it will.

PRINT USING is used to display numeric expressions in a
predetermined format. The format string looks like ##.####
hereby signifying how many digits should be placed before and
after the decimal point.

PRINT FILE writes data to previously opened files. The file
should be opened for WRITE, APPEND or RANDOM. The difference
between PRINT FILE and WRITE FILE is that WRITE FILE write
variables (incl. arrays) and PRINT FILE writes expressions.

Example:		PRINT "Output value = ";oval;" Kbytes"
			PRINT USING "##.####": angle;
			PRINT FILE 4,recno: name$,number,78
			

6.56 PROC (and FUNC)

Comal fully supports named procedures and functions that can
take parameters.

General syntax:	PROC <id>[(<parlist>)] [CLOSED] [[DYNAMIC] EXTERNAL <stringexp>]]
		  ..
		  ..
		ENDPROC
		
		FUNC <id>[(<parlist>)] [CLOSED] [[DYNAMIC] EXTERNAL <stringexp>]]
		  ..
		  ..
		ENDFUNC
		
Procedures and functions can be defined anywhere in the program.
The call to the PROC or FUNC need not succede the routines
definition like in PASCAL.

Procedure calls are simple OpenComal statements. Specifying their
name and all parameters if necessary leads to a shift in flow
control to the first statement of the PROCedure. Functions can
be called from any expression.

A procedure name must be an ordinary identifier, a function name
can be any type identifier. The type of the function name must
equal the return type of the function, e.q.:

		first$		returns a string
		aap		returns a floating point value
		fiets#		returns an integer value
		
The procedure returns to the caller upon execution of a RETURN
statement. If the ENDPROC of a procedure is reached, an implicit
RETURN is executed.

Functions must explicitly return a value to the caller with the
RETURN statement. The execution of an ENDFUNC statement yields
an error.

Procedures and functions can be fully nested with OpenComal. A
nested PROC or FUNC can call all PROCs and FUNCs defined at the
same level in the parent PROC/FUNC, plus all PROCs and FUNCs
defined at a higher level.

Each procedure and function creates a local variable environment
upon call. All passed parameters become variables in this local
environment and do not interfere with any variables with the
same name in any other environment.

Optionally, a routine can be declared CLOSED. This means that
all variables used in the PROC/FUNC are a part of the local
environment.  New variables will belong to this local
environment and will not interfere with existing variables with
the same name in any other environment. Variables from the
parent environment are not visible within a CLOSED PROC or FUNC.
If they are to be used they must be imported with the IMPORT
statement. With the LOCAL statement new variables can be
introduced in the local environment in a non-CLOSED PROC/FUNC.

OpenComal differs signficantly from other Comal's in the concept
of OPEN/CLOSED procedures and functions. Other Comal's usually
don't allow CLOSED procedures to call OPEN ones. OpenComal does.

The variables that are introduced and used in a non-CLOSED
PROC/FUNC (apart from the PROC/FUNC's parameters and explicitly
LOCALly defined variables) belong to the parent environment
(also called the OPEN environment) of the procedure. This parent
environment is the environment of the most deeply nested CLOSED
parent procedure or function of the PROC/FUNC meant here. The
main program is treated as a CLOSED procedure at level -1.

Now onto the subject of parameters. Comal allows to type of
parameter passing: by value and by reference. OpenComal supports
these two types and adds call-by-name and the passing of PROC
and FUNC type parameters.  The parameter list definition
contains a list of identifiers with optionally a modifier
signifying the type of parameter pass. () must be used to
specify the passing of an entire array:

	aap		call by value of into local var aap
	bert#()		call by value into local integer array bert#
	REF name$	call by reference into name$
	REF table()	call by reference into array table
	NAME bus	call by name into locale name value bus
	PROC a		passing of a procedure name into a
	FUNC b$		passing of a string function into b$
	
The PROC/FUNC passing mechanism allows the programmer to specify
the name of a OpenComal defined procedure or function to a
procedure or function. The call of the parameter in the
PROC/FUNC will lead to a call to the passed PROC/FUNC. A short
example:

	 10 aap(a)
	 20 aap(b)
	 30 //
	 40 PROC aap(PROC c)
	 50   c
	 60 ENDPROC
	 70 //
	 80 PROC a
	 90   PRINT "Hello from a"
 	100 ENDPROC
	110 //
	120 PROC b
	130   PRINT "Hello from b"
	140 ENDPROC
	
When calling a procedure or a function a passed PROC/FUNC takes
priority over a PROC/FUNC explicitly defined with the same name.

The other exotic feature of OpenComal is call-by-name. This allows
the programmer to pass an entire expression to a PROC/FUNC. This
expression is not evaluated upon call but is evaluated every
time the name value is used in the PROC/FUNC! Example:

       10 aap(voornaam$+" visser")
       20 //
       30 PROC aap(NAME name$)
       40   PRINT name$
       50   PRINT name$
       60   PRINT name$(1:3)
       70 ENDPROC
       80 //
       90 FUNC voornaam$ CLOSED
      100   IF EOD THEN RETURN "End of DATA"
      110   READ a$
      120   RETURN a$
      130 ENDFUNC
      140 //
      150 DATA "jos", "patrick"

The expression voornaam$+" visser" is evaluated three times
within PROC aap, yielding a different result each time!!
The NAME expression is evaluated in the environment of the caller!!

Usually PROCedures and FUNCtions are incorporated into the
program (inline so as to speak). However, OpenComal also features
the possibility to store the program code of PROCedures and
FUNCtions on an external file. 

If this is the case, the program must contain a stub for the
PROC/FUNC containing it's name, the keyword EXTERNAL and an
string expression which must evaluate to the name of the file
containing a SAVEd program text:

		1066 PROC aap EXTERNAL "aap.sq"
		
Upon calling 'aap' the file aap.sq is LOADed and SCANned. This
file may contain only one routine (with nested PROC/FUNC's).
Its program text is then executed. The PROC/FUNC header stub
may contain a parameter list definition, however this is not
compulsary. If it contains one it must match the PROC/FUNC
parameter definition in the file. If the stub contains:

		1066 PROC aap(a, REF b) EXTERNAL "aap.sq"
		
and the PROC in the file aap.sq looks like this:

		10 PROC aap(a#, REF b)
		
an error is generated because the first parameters do not match.
The names of the parameters are not matched and may be different.

The name of the external file containing the routine's code need
not be a constant. The following is perfectly legal:

		2000 FUNC banaan$ EXTERNAL prog$+".sq"
		
The string expression is evaluated IN THE CALLING VARIABLE
ENVIRONMENT and should result in a filename.

If an external PROC/FUNC file is pointed to by a constant string
expression (like "aap.sq") it is called a STATIC external. If a
variable string expression is used to specify the PROC/FUNC code
filename it is called a DYNAMIC external.

The difference is that static external procedures and functions
are maintained in memory after the first call. Subsequent calls
need not load the file again, resulting in enormous speed gains.
However, changes in the procedure/function program file are not
processed until a rerun of the program. Dynamic external
routines are discarded from memory upon PROC/FUNC return.
Another call will lead to a re-evaluation of the string
expression and will the resulting program file. Multiple calls
of the same external procedure will result in considerable overhead.

OpenComal's educated guess about the nature of an external routine
can be modified by the STATIC and DYNAMIC keywords:

	1200 PROC aap DYNAMIC EXTERNAL "aap.sq"
	1300 //
	2020 FUNC fruit$ STATIC EXTERNAL prog$
	
A reason for this might be that an external routine is very
large and you do not want to tie up memory with it after a call,
or the program filename of an external routine is determined
once and not changed after that, so you want to load it only once.

External procedures and functions may not contain DATA lines.
All DATA is read from the main program. External routines may
call other external routines. If a dynamic external routine
calls a static external routine, the program code of the static
routine is removed from memory upon removal of the calling
dynamic external.


6.57 QUIT

The QUIT command ends the OpenComal interpreter. Control is
usually passed to the calling environment.


6.58 RANDOM

The RANDOM keyword is used to specify that the file to be OPENed
is to be treated as a random record file. File actions (WRITE,
READ etc.) must specify which record number in the file is to be
processed. See OPEN.

6.59 READ

lines or from external files.

General syntax:			READ [FILE <exp>[,<exp>]:] <lvallist>

The READ/DATA variant evaluates the expression pointed to by the
current data pointer, assigns it's value to the variable in the
lval list, advances the data pointer and processes the next
element in the list.

READ FILE reads data elements from the specified file and
optionally the specified record. If the variable in the variable
list is an array then READ FILE reads as many elements from the
file as there are elements in the array.

Example:			READ name$,wpl$,salary,age#
				READ FILE 4,6: noels#,table
				

The READ ONLY clause is used to specify that the random record
file to be opened is opened for READ only (sounds logical). See
OPEN.


6.61 REF

The REF keyword is used to specify pass-by-reference parameter
passing.  See PROC.


6.62 RENUMBER
Synonym for RENUM.


6.63 RENUM

The RENUM command is used to renumber program lines.

General syntax:		RENUM [<start>][,<inc>]

If no start or increment is used, they default to 10.

Example:		RENUM 100,20
			RENUM ,100
			RENUM
			

6.64 REPEAT

REPEAT signifies the beginning of a REPEAT/UNTIL loop: an
interation of OpenComal statements with a test at the end of the
iteration.

General syntax:			REPEAT
				  ...
				  ...
				UNTIL <exp>
				
The statements between the REPEAT and the UNTIL are executed as
long as the <exp> is FALSE. If the <exp> evaluates to TRUE at
the execution of the UNTIL, control is transferred to the
statement after the UNTIL.

Example:			REPEAT
				  INPUT "Enter number neq 0: ":a
				UNTIL a<>0
				

6.65 RESTORE

The RESTORE statement moves the current DATA pointer to a
different location.

General syntax:			RESTORE
				RESTORE <id>
				
Plain RESTORE moves the DATA pointer to the first DATA line in
the program. RESTORE <id> locates the line marked <id>: in the
program and moves the DATA pointer to the first DATA line after
the mentioned line.

Example:			RESTORE
				RESTORE aap
				
6.65a RETRY

The RETRY statement retries a TRAP part. See TRAP.


6.66 RETURN

With the RETURN statement the processing of a called PROCedure
or FUNCtion ends and control is returned to the caller. See
PROC.


6.67 RUN

load and execute a program from an external file (RUN
statement).

General syntax:			RUN
				RUN <stringexp>
				
Example:			RUN
				RUN prog$+".sq"
			

6.68 SAVE

SAVE is used to store the current OpenComal program in memory to
an external file.

General syntax:			SAVE "filename"
				SAVE

If no filename is specified the filename last SAVEd or LOADed is
used.  The format of the SAVEd file is highly implementation
dependent and can't be LOADed by a different OpenComal
implementation.


6.69 SELECT OUTPUT

The SELECT OUTPUT statement specifies that all output from the
running program (PRINT etc.) should be written to a file instead
of to the screen.

General syntax:			SELECT OUTPUT <stringexp>

A file with the specified name is opened and all program output
is redirected to it. If the file exists the program output is
appended at the end of the file. Output is directed to the
screen again by specifying an empty string as filename.

Example:			SELECT OUTPUT ""
				SELECT OUTPUT "filenout"
				

6.70 SELECT INPUT

The SELECT INPUT statement specifies that all input into the
running program (INPUT etc.) should be read from a file instead
of from the keyboard.

General syntax:			SELECT INPUT <stringexp>

The file with the specified name is opened and all subsequent
INPUT statements read data from the file. Input is directed from
the keyboard again by specifying an empty string as filename.

Example:			SELECT INPUT "data.in"
				SELECT INPUT ""
				

6.71 SCAN

The SCAN command invokes the OpenComal pre-RUN program checks
without running the program if it is correct. Any program
(structure) errors are reported.


6.71a STATIC

The STATIC keyword is used in the definition of EXTERNAL
routines. It signifies that the called procedure or function
should be kept in memory upon return. See PROC.


6.72 SYS

The SYS statement, SYS() and SYS$() functions have been made available
as methods to gain access to non-standard extensions of OpenComal in a
specific implementation.

General syntax:		statement:	SYS <exp list>
			functions:	SYS(<exp list>)
					
When the SYS statement or one of the SYS() functions is executed
control is passed to predetermined entry points in the system
dependent module. The expressions in the list are *not*
evaluated by the OpenComal interpreter. If evaluation is
necessary this should be invoked by the extensions program
code. This gives the extensions the possibility to use
unevaluated expressions as sub-keywords.

A number of SYS items have been incorporated in the default
extensions part of OpenComal:

	SYS <flag>,on|off	Set internal flag
	SYS(<flag>)		Return status of internal flag
	SYS$(<flag>)		Return status of internal flag
	SYS(version)		Returns OpenComal version no.
	SYS$(host)		Returns name of OpenComal implementation
	SYS$(interpreter)	Return interpreter name (opencomalrun, opencomal)
	SYS$(version)		Return interpreter version
	SYS SYSOUT,"file"	Send all screen output to file "file"
	SYS SYSIN,"file"	Read all input (incl. commands) from
				file "file"

	Internal flags are:

	debug			Switches internal debugging state
	yydebug			Switches YACC parser debugging
	show_exec		Whether EXEC keyword shown in listings
	prog_trace		Same as TRACE statement
	short_circuit		Short circuit boolean exp eval?

The Linux version of OpenComal supports SYS(sbrk) and SYS(now).  
SYS(sbrk) which gives the current end address of the data segment as a 
Comal integer. This is really handy when monitoring the OpenComal 
interpreter's memory usage from within a Comal program. SYS(now) gives 
the current time of the system in seconds since the epoch (midnight on 
1st january 1970).

6.74 STEP

The STEP clause is used to specify the value with which a FOR
loop variable should be incremented (TO) or decremented
(DOWNTO). See FOR.


6.74a SPC$

Generatl syntax:	SPC$(<numexp>)

The SPC$ function returns a string containing the specified number
of spaces.

Example:		a$:=SPC$(16)


6.75 STOP

General syntax:		STOP
			STOP <stringexp>
		
The STOP statement halts program execution and gives control to
the OpenComal interpreter command loop. The program can be
continued with the CON command. STOP is not trapped by a
TRAP/ENDTRAP construct. If the optional string expression is present, it
is evaluated and printed when the program stops. Come to think of it,
you can get the OpenComal interpreter to loop in infinite recursion when
using "STOP f" in a FUNCtion 'f'. You don't want to do this...


6.76 THEN

Specifies the statement(s) that should be executed if the
expression of an IF statement evaluates to TRUE. See IF.


6.77 TO

Cosmetic keyword in FOR statements


6.78 TRACE

The TRACE statement can be used to switch OpenComal program
tracing on and off. When tracing is ON each line is listed
before it is executed.

General syntax:			TRACE on|off


6.79 TRAP

The TRAP keyword plays a role in two kinds of statements: The
TRAP ESC statement to switch escape processing on and off, and
the TRAP/HANDLER/ENDTRAP statement to catch all kinds of program
errors.  The TRAP statement signifies the beginning of an error
trapping program structure:

General syntax:			TRAP ESC[-|+]

				TRAP
				  ...
				  ...
				HANDLER
				  ...
				  RETRY
				  ...
				ENDTRAP

As soon as TRAP ESC- is executed all escape conditions will be
ignored by the program. After a TRAP ESC+ depressing the escape
key will result in a program STOP as usual.

In a long form TRAP, the statements between TRAP and HANDLER are
executed. If an error occurs during the execution, control is
passed to the statements after HANDLER.  If no error occurs
control is passes to the statements after ENDTRAP as soon as
HANDLER is executed.  A HANDLER section need not be present.

If the HANDLER part contains a RETRY statement, the execution of the
HANDLER part is terminated and control is passed back to the statement
following the TRAP.

Example:			TRAP ESC-
				TRAP ESC+
				
				TRAP
				  DEL "ofile"
				ENDTRAP
			
				TRAP
				  PRINT 1/0
				HANDLER
				  PRINT "Error: ";ERr$
				ENDTRAP
				
6.79a UNIT and UNIT$

The UNIT statement sets the current disk drive of the Comal interpreter.
The UNIT$ returns the currently selected UNIT.

General syntax:			UNIT <stringexp>
				UNIT$

The exact implementation depends on the operating system. For instance
under Linux, the UNIT statement does nothing whereas the UNIT$ function
always returns "C:".

Example:			UNIT "l:"
				PRINT UNIT$

6.80 UNTIL

The UNTIL statement marks the end of a REPEAT/UNTIL loop. See REPEAT.


6.81 USING

The USING clause of PRINT allows the formatted printing of
numeric values. See PRINT.


6.82 WHEN

The WHEN statement is used to specify the selection criteria in
an n-way selection CASE. See CASE.


6.83 WHILE

WHILE signifies the beginning of a WHILE/ENDWHILE loop: an
interation of OpenComal statements with a test at the beginning of
the iteration.

General syntax:			WHILE <exp> DO
				  ...
				  ...
				ENDWHILE
				
				WHILE <exp> DO <simplestat>
				
The statements between the WHILE and the ENDWHILE (long form) or
the statement after the DO (short form) are executed as long as
the <exp> is TRUE. If the <exp> evaluates to FALSE at the
execution of the WHILE, control is transferred to the statement
after the ENDWHILE.

Example:			WHILE a<>0 DO INPUT "Enter number neq 0: ":a

				WHILE keuze<>0 DO
				  PAGE
				  prt_menu
				  keuze:=menu_keuze
				ENDWHILE
				

6.84 WRITE

WRITE writes variables to previously opened external files.

General syntax:			WRITE FILE <exp>[,<exp>]: <varlist>

WRITE FILE operates just like PRINT FILE with this difference
that WRITE FILE can be used to write complete arrays to a file.

Example:			WRITE FILE t: a, b$, c#
				WRITE FILE 1,1: root#
			

6.85 <id>:

The <id>: statement has no execution behaviour but simply marks
a program line for reference by RESTORE. In this way a self
documenting, non-line number dependent program line reference is
possible.
Example:			  10 RESTORE aap
				1200 aap:
				1202 DATA 1,4,9,16,25,36
				

6.86 Procedure call
The procedure call statement is used to call OpenComal defined PROCedures.


Procedures are called by their name. Older Comal implementations
demanded the keyword EXEC to signify a procedure call. OpenComal
allows the use of EXEC when entering program lines but will not
show it in program listings.

The procedures parameters should be enclosed in parenthesis. A
procedure with no parameters may not specify an empty parameter
list like ().

 
Example:			menu("Main menu",1)
				build_screen
				lees(a,b$,"xxx")


The following part is an adaptation of the OpenComal YACC input with
which valid OpenComal input lines are parsed.

All terminals (ending in SYM) are returned from the lexical analyzer of
functions are recognized into 5 different terminal tokens:

	rnSYM		Returns Num			like EOD, ERR
	rsSYM		Returns String			like ERRTEXT$
	tnrnSYM		Takes Num, Returns Num		like ABS, COS
	tnrsSYM		Takes Num,Returns String	like STR$
	
The grammar as here presented is not the most beautiful one
imaginable for OpenComal. However, beauty has been discarded in
favour of ease of processing and the limits an LALR(1) parser
generator like YACC imposes.
	

7.1 The Grammar

a_comal_line	:	comal_line eolnSYM
		|	error eolnSYM
		;
		
comal_line	:	command 
		|	intnumSYM program_line optrem
		|	simple_stat
		|	optrem
		;
		
optrem		:	remSYM
		|	/* epsilon */
		;
	
		
command		:	quitSYM
		|	list_cmd
		|	saveSYM optfilename
		|	loadSYM optfilename
		|	enterSYM stringSYM
		|	envSYM optid2
		|	runSYM
		|	newSYM
		|	scanSYM
		|	autoSYM autolines
		|	contSYM
		|	delSYM line_range
		|	editSYM line_range
		|	renumberSYM renumlines
		;

list_cmd	:	listSYM line_range
		|	listSYM stringSYM
		|	listSYM line_range commaSYM stringSYM
		|	listSYM id
		|	listSYM id commaSYM stringSYM
		;

line_range	:	/* epsilon */
		|	intnumSYM
		|	minusSYM intnumSYM
		|	intnumSYM minusSYM
		|	intnumSYM minusSYM intnumSYM
		;		
		
renumlines	:	intnumSYM
		|	intnumSYM commaSYM intnumSYM
		|	commaSYM intnumSYM
		|	/* epsilon */
		;

autolines	:	intnumSYM
		|	intnumSYM commaSYM intnumSYM
		|	commaSYM intnumSYM
		|	/* epsilon */
		;
		
program_line	:	complex_stat
		|	simple_stat
		|	/* epsilon */
		;
		
complex_stat	:	case_stat
		|	data_stat
		|	elif_stat
		|	exit_stat
		|	for_stat
		|	func_stat
		|	if_stat
		|	proc_stat
		|	until_stat
		|	when_stat
		|	while_stat
		|	label_stat
		|	complex_1word
		;
		
simple_stat	:	close_stat
		|	cursor_stat
		|	del_stat
		|	dim_stat
		|	dir_stat
		|	local_stat
		|	exec_stat
		|	import_stat
		|	input_stat
		|	open_stat
		|	os_stat
		|	print_stat
		|	read_stat
		|	restore_stat
		|	return_stat
		|	run_stat
		|	select_out_stat
		|	select_in_stat
		|	stop_stat
		|	sys_stat
		|	trace_stat
		|	trap_stat
		|	unit_stat
		|	write_stat
		|	xid
		|	assign_stat
		|	simple_1word
		;

complex_1word	:	elseSYM
		|	endcaseSYM
		|	endfuncSYM optid
		|	endifSYM
		|	loopSYM
		|	endloopSYM
		|	endprocSYM optid2
		|	endwhileSYM
		|	endforSYM optnumlvalue
		|	otherwiseSYM
		|	repeatSYM
		|	trapSYM
		|	handlerSYM
		|	endtrapSYM
		;

simple_1word	:	nullSYM
		|	endSYM
		|	exitSYM
		|	pageSYM
		;
		
case_stat	:	caseSYM exp optof
		;
		
close_stat	:	closeSYM
		|	closeSYM optfileS exp_list
		;

cursor_stat	:	cursorSYM numexp commaSYM numexp
		;
		
data_stat	:	dataSYM exp_list
		;

del_stat	:	delSYM stringexp
		;

dir_stat	:	dirSYM opt_stringexp
		;

unit_stat	:	unitSYM stringexp
		;


local_stat	:	localSYM local_list
		;
local_list	:	local_list commaSYM local_item
		|	local_item
		;
		
local_item	:	numid opt_dim_ensions
		|	stringidSYM
		|	stringidSYM ofSYM numexp
		|	stringidSYM dim_ensions of numexp
		|	stringidSYM dim_ensions
		;


dim_stat	:	dimSYM dim_list
		;
		
dim_list	:	dim_list commaSYM dim_item
		|	dim_item
		;
		
dim_item	:	numid dim_ensions
		|	stringidSYM ofSYM numexp
		|	stringidSYM dim_ensions of numexp
		|	stringidSYM dim_ensions
		;

of		:	ofSYM
		|	timesSYM
		;

opt_dim_ensions	:	dim_ensions
		|	/* epsilon */
		;
				
dim_ensions	:	lparenSYM dim_ension_list rparenSYM
		;
		
dim_ension_list	:	dim_ension_list commaSYM dim_ension
		|	dim_ension
		;
		
dim_ension	:	numexp
		|	numexp colonSYM numexp
		|	numexp becminusSYM numexp
		;

elif_stat	:	elifSYM numexp optthen
		;

exit_stat	:	exitSYM ifwhen numexp
		;
		
ifwhen		:	ifSYM
		|	whenSYM
		;
		
exec_stat	:	execSYM xid
		;

for_stat	:	forSYM numlvalue assign1 numexp todownto numexp optstep optdo optsimple_stat
		;

todownto	:	toSYM
		|	downtoSYM
		;
		
optstep		:	stepSYM numexp
		|	/* epsilon */
		;
		
func_stat	:	funcSYM id procfunc_head optclosed opt_external
		;

if_stat		:	ifSYM numexp optthen optsimple_stat
		;
		
import_stat	:	importSYM id colonSYM import_list
		|	importSYM import_list
		;
		
import_list	:	import_list commaSYM oneparm		
		|	oneparm
		;

input_stat	:	inputSYM input_modifier lval_list
		;
		
input_modifier	:	file_designator
		|	stringSYM colonSYM
		|	/* epsilon */
		;

open_stat	:	openSYM fileSYM numexp commaSYM stringexp commaSYM open_type
		;
		
open_type	:	readSYM
		|	writeSYM
		|	appendSYM
		|	randomSYM numexp optread_only
		;

os_stat		:	osSYM stringexp
		;

print_stat	:	printi
		|	printi print_list optpr_sep
		|	printi usingSYM stringexp colonSYM prnum_list optpr_sep
		|	printi file_designator print_list
		;
		
printi		:	printSYM
		|	semicolonSYM
		;
		
prnum_list	:	prnum_list pr_sep numexp
		|	numexp
		;
		
print_list	:	print_list pr_sep exp
		|	exp
		;

pr_sep		:	commaSYM
		|	semicolonSYM
		;
		
optpr_sep	:	pr_sep
		|	/* epsilon */
		;
		
proc_stat	:	procSYM idSYM procfunc_head optclosed opt_external
		;

read_stat	:	readSYM optfile lval_list
		;

restore_stat	:	restoreSYM optid2
		;

return_stat	:	returnSYM optexp
		;

run_stat	:	runSYM stringexp
		;		

select_out_stat	:	select_outputSYM stringexp
		;


select_in_stat	:	select_inputSYM stringexp
		;

stop_stat	:	stopSYM optexp
		;

sys_stat	:	sysSYM exp_list
		;

until_stat	:	untilSYM numexp
		;

trace_stat	:	traceSYM numexp
		;

trap_stat	:	trapSYM escSYM plusorminus
		;		

plusorminus	:	plusSYM
		|	minusSYM
		;
				
when_stat	:	whenSYM when_list
		;

when_list	:	when_numlist
		|	when_strlist
		;
				
when_numlist	:	when_numlist commaSYM when_numitem
		|	when_numitem
		;
		
when_numitem	:	relop numexp
		|	numexp
		;
				
when_strlist	:	when_strlist commaSYM when_stritem
		|	when_stritem
		;
		
when_stritem	:	relop stringexp
		|	stringexp
		|	inSYM stringexp
		;
		
relop		:	gtrSYM
		|	lssSYM
		|	eqlSYM
		|	neqSYM
		|	geqSYM
		|	leqSYM
		;

while_stat	:	whileSYM numexp optdo optsimple_stat
		;
		
write_stat	:	writeSYM file_designator lval_list
		;

assign_stat	:	assign_list
		;
		
assign_list	:	assign_list semicolonSYM assign_item
		|	assign_item
		;
		
assign_item	:	numlvalue nassign numexp
		|	strlvalue sassign stringexp
		;

nassign		:	assign1
		|	assign2
		;

sassign		:	assign1
		|	becplusSYM
		;
				
assign1		:	eqlSYM
		|	becomesSYM
		;
		
assign2		:	becplusSYM
		|	becminusSYM
		;
		
label_stat	:	idSYM colonSYM
		;
		
xid		:	idSYM
		|	idSYM lparenSYM exp_list rparenSYM
		;

exp		:	numexp
		|	stringexp
		;
				
numexp		:	numexp2
		;
		
numexp2		:	numexp2 eqlSYM numexp2
		|	numexp2 neqSYM numexp2		
		|	numexp2 lssSYM numexp2		
		|	numexp2 gtrSYM numexp2		
		|	numexp2 leqSYM numexp2		
		|	numexp2 geqSYM numexp2		
		|	numexp2 andSYM numexp2		
		|	numexp2 andthenSYM numexp2		
		|	numexp2 orSYM numexp2		
		|	numexp2 orthenSYM numexp2		
		|	numexp2 eorSYM numexp2		
		|	numexp2 plusSYM numexp2		
		|	numexp2 minusSYM numexp2		
		|	numexp2 timesSYM numexp2		
		|	numexp2 divideSYM numexp2		
		|	numexp2 powerSYM numexp2		
		|	numexp2 divSYM numexp2		
		|	numexp2 modSYM numexp2		
		|	stringexp2 eqlSYM stringexp2
		|	stringexp2 neqSYM stringexp2
		|	stringexp2 lssSYM stringexp2
		|	stringexp2 gtrSYM stringexp2
		|	stringexp2 leqSYM stringexp2
		|	stringexp2 geqSYM stringexp2
		|	stringexp2 inSYM stringexp2
		|	minusSYM numexp2 %prec USIGN
		|	plusSYM numexp2 %prec USIGN
		|	intnumSYM
		|	floatnumSYM
		|	numlvalue2
		|	tsrnSYM lparenSYM stringexp2 rparenSYM
		|	tnrnSYM lparenSYM numexp2 rparenSYM
		|	rnSYM
		|	sysSYM lparenSYM exp_list rparenSYM
		|	lparenSYM numexp2 rparenSYM
		;

stringexp	:	stringexp2
		;

stringexp2	:	stringexp2 plusSYM string_factor
		|	string_factor
		;

opt_stringexp	:	stringexp
		|	/* epsilon */
		;

string_factor	:	strlvalue2
		|	string_factor substr_spec
		|	tnrsSYM lparenSYM numexp2 rparenSYM
		|	rsSYM
		|	stringSYM
		|	syssSYM lparenSYM exp_list rparenSYM
		|	lparenSYM stringexp2 rparenSYM
		;

substr_spec	:	lparenSYM substr_spec2 rparenSYM
		;
		
substr_spec2	:	numexp colonSYM numexp
		|	colonSYM numexp
		|	numexp colonSYM
		;
	
optnumlvalue	:	numlvalue
		|	/* epsilon */
		;
			
optexp		:	exp
		|	/* epsilon */
		;

optid		:	id
		|	/* epsilon */
		;

optid2		:	idSYM
		|	/* epsilon */
		;
		
optfile		:	file_designator
		|	/* epsilon */
		;

optfileS	:	fileSYM
		|	/* epsilon */
		;
				
lval_list	:	lval_list commaSYM lvalue
		|	lvalue
		;
		
lvalue		:	numlvalue
		|	strlvalue
		;
	
numlvalue	:	numlvalue2
		;
			
numlvalue2	:	xid
		|	intidSYM
		|	intidSYM lparenSYM exp_list rparenSYM
		;
		
strlvalue	:	strlvalue2
		;
		
strlvalue2	:	stringidSYM
		|	stringidSYM lparenSYM exp_list rparenSYM
		|	stringidSYM substr_spec
		|	stringidSYM lparenSYM exp_list rparenSYM substr_spec
		;
		
file_designator	:	fileSYM numexp colonSYM
		|	fileSYM numexp commaSYM numexp colonSYM
		;

opt_external	:	externalSYM stringexp
		|	dynamicSYM externalSYM stringexp
		|	staticSYM externalSYM stringexp
		|	/* epsilon */
		;
		
procfunc_head	:	lparenSYM parmlist rparenSYM
		|	/* epsilon */
		;
		
parmlist	:	parmlist commaSYM parmitem
		|	parmitem
		;
		
parmitem	:	oneparm
		|	refSYM oneparm
		|	nameSYM id
		|	procSYM idSYM
		|	funcSYM id
		;
		
oneparm		:	id
		|	id lparenSYM rparenSYM
		;
		
id		:	numid
		|	stringidSYM
		;
				
numid		:	idSYM
		|	intidSYM
		;
		
exp_list	:	exp_list commaSYM exp
		|	exp
		;
		
optsimple_stat	:	simple_stat
		|	/* epsilon */
		;

optfilename	:	stringSYM
		|	/* epsilon */
		;
		
optof		:	ofSYM
		|	/* epsilon */
		;

optdo		:	doSYM
		|	/* epsilon */
		;

optthen		:	thenSYM
		|	/* epsilon */
		;
		
optread_only	:	read_onlySYM
		|	/* epsilon */
		;	

optclosed	:	closedSYM
		|	/* epsilon */
		;	
