* Copyright (c) 1994 David I. Bell
* Permission is granted to use, distribute, or modify this source,
* provided that this copyright notice remains intact.
* Module to generate opcodes from the input tokens.
static BOOL rdonce
; /* TRUE => do not reread this file */
static BOOL
getfilename(), getid();
static void getshowcommand(), getfunction(), getbody(), getdeclarations();
static void getstatement(), getobjdeclaration(), getobjvars();
static void getmatdeclaration(), getsimplebody(), getonedeclaration();
static void getcondition(), getmatargs(), getelement(), usesymbol();
static void definesymbol(), getcallargs();
static int getexprlist(), getassignment(), getaltcond(), getorcond();
static int getandcond(), getrelation(), getsum(), getproduct();
static int getorexpr(), getandexpr(), getshiftexpr(), getterm();
static long getinitlist();
* Read all the commands from an input file.
* These are either declarations, or else are commands to execute now.
* In general, commands are terminated by newlines or semicolons.
* Exceptions are function definitions and escaped newlines.
* Commands are read and executed until the end of file.
* The toplevel flag indicates whether we are at the top interactive level.
char name
[PATHSIZE
+1]; /* program name */
(void) tokenmode(TM_NEWLINES
);
if (!getfilename(name
, FALSE
, NULL
)) {
strcpy(name
, DEFAULTCALCHELP
);
if (!getfilename(name
, TRUE
, &rdonce
))
switch (opensearchfile(name
,calcpath
,CALCEXT
,rdonce
)) {
/* previously read and -once was given */
scanerror(T_NULL
, "Cannot open \"%s\"\n", name
);
if (!getfilename(name
, TRUE
, NULL
))
scanerror(T_NULL
, "Error writing \"%s\"\n", name
);
* Evaluate a line of statements.
* This is done by treating the current line as a function body,
* compiling it, and then executing it. Returns TRUE if the line
* successfully compiled and executed. The last expression result
* is saved in the f_savedvalue element of the current function.
* The nestflag variable should be FALSE for the outermost evaluation
* level, and TRUE for all other calls (such as the 'eval' function).
* The function name begins with an asterisk to indicate specialness.
BOOL nestflag
; /* TRUE if this is a nested evaluation */
funcname
= (nestflag
? "**" : "*");
beginfunc(funcname
, nestflag
);
scanerror(T_SEMICOLON
, "Declarations must be used before code");
getstatement(NULL_LABEL
, NULL_LABEL
,
* Get a function declaration.
* func = name '(' '' | name [ ',' name] ... ')' simplebody
* | name '(' '' | name [ ',' name] ... ')' body.
char *name
; /* parameter name */
int type
; /* type of token read */
(void) tokenmode(TM_DEFAULT
);
if (gettoken() != T_SYMBOL
) {
scanerror(T_NULL
, "Function name expected");
beginfunc(tokenstring(), FALSE
);
if (gettoken() != T_LEFTPAREN
) {
scanerror(T_SEMICOLON
, "Left parenthesis expected for function");
if (type
== T_RIGHTPAREN
)
scanerror(T_COMMA
, "Bad function definition");
switch (symboltype(name
)) {
scanerror(T_NULL
, "Parameter \"%s\" is already defined", name
);
if (type
== T_RIGHTPAREN
)
scanerror(T_COMMA
, "Bad function definition");
getbody(NULL_LABEL
, NULL_LABEL
, NULL_LABEL
,
"Left brace or equals sign expected for function");
* Get a simple assignment style body for a function declaration.
* simplebody = '=' assignment '\n'.
if (gettoken() != T_ASSIGN
) {
scanerror(T_SEMICOLON
, "Missing equals for simple function body");
(void) tokenmode(TM_NEWLINES
);
if (gettoken() != T_SEMICOLON
)
if (gettoken() != T_NEWLINE
)
scanerror(T_NULL
, "Illegal function definition");
* Get the body of a function, or a subbody of a function.
* body = '{' [ declarations ] ... [ statement ] ... '}'
* | [ declarations ] ... [statement ] ... '\n'
getbody(contlabel
, breaklabel
, nextcaselabel
, defaultlabel
, toplevel
)
LABEL
*contlabel
, *breaklabel
, *nextcaselabel
, *defaultlabel
;
BOOL gotstatement
; /* TRUE if seen a real statement yet */
if (gettoken() != T_LEFTBRACE
) {
scanerror(T_SEMICOLON
, "Missing left brace for function body");
oldmode
= tokenmode(TM_DEFAULT
);
(void) tokenmode(oldmode
);
scanerror(T_SEMICOLON
, "Declarations must be at the top of the function");
scanerror(T_SEMICOLON
, "Declarations must be used before code");
getstatement(contlabel
, breaklabel
, nextcaselabel
, defaultlabel
);
* Get a line of possible local, global, or static variable declarations.
* declarations = { LOCAL | GLOBAL | STATIC } onedeclaration
* [ ',' onedeclaration ] ... ';'.
if ((type
!= T_LOCAL
) && (type
!= T_GLOBAL
) && (type
!= T_STATIC
)) {
scanerror(T_SEMICOLON
, "Bad syntax in declaration statement");
* Get a single declaration of a symbol of the specified type.
* onedeclaration = name [ '=' getassignment ]
* | 'obj' type name [ '=' objvalues ]
* | 'mat' name '[' matargs ']' [ '=' matvalues ].
char *name
; /* name of symbol seen */
int symtype
; /* type of symbol */
int vartype
; /* type of variable being defined */
addoplabel(OP_INITSTATIC
, &label
);
definesymbol(name
, symtype
);
addopone(OP_DEBUG
, linenumber());
getmatdeclaration(symtype
);
if (symtype
== SYM_STATIC
)
addopone(OP_DEBUG
, linenumber());
getobjdeclaration(symtype
);
if (symtype
== SYM_STATIC
)
scanerror(T_COMMA
, "Bad syntax for declaration");
if (gettoken() != T_ASSIGN
) {
if (symtype
== SYM_STATIC
)
* Initialize the variable with the expression. If the variable is
* static, arrange for the initialization to only be done once.
addopone(OP_DEBUG
, linenumber());
if (symtype
== SYM_STATIC
)
* statement = IF condition statement [ELSE statement]
* | FOR '(' [assignment] ';' [assignment] ';' [assignment] ')' statement
* | WHILE condition statement
* | DO statement WHILE condition ';'
* | SWITCH condition '{' [caseclause] ... '}'
* | RETURN assignment ';'
* | MAT name '[' value [ ':' value ] [',' value [ ':' value ] ] ']' ';'
* | OBJ type '{' arg [ ',' arg ] ... '}' ] ';'
* | OBJ type name [ ',' name ] ';'
* | PRINT assignment [, assignment ] ... ';'
getstatement(contlabel
, breaklabel
, nextcaselabel
, defaultlabel
)
LABEL
*contlabel
; /* label for continue statement */
LABEL
*breaklabel
; /* label for break statement */
LABEL
*nextcaselabel
; /* label for next case statement */
LABEL
*defaultlabel
; /* label for default case */
LABEL label1
, label2
, label3
, label4
; /* locations for jumps */
addopone(OP_DEBUG
, linenumber());
scanerror(T_NULL
, "Extraneous right brace");
if (contlabel
== NULL_LABEL
) {
scanerror(T_SEMICOLON
, "CONTINUE not within FOR, WHILE, or DO");
addoplabel(OP_JUMP
, contlabel
);
if (breaklabel
== NULL_LABEL
) {
scanerror(T_SEMICOLON
, "BREAK not within FOR, WHILE, or DO");
addoplabel(OP_JUMP
, breaklabel
);
if (gettoken() != T_SYMBOL
) {
scanerror(T_SEMICOLON
, "Missing label in goto");
if (curfunc
->f_name
[0] == '*')
getbody(contlabel
, breaklabel
, nextcaselabel
, defaultlabel
, FALSE
);
addoplabel(OP_JUMPEQ
, &label1
);
getstatement(contlabel
, breaklabel
, NULL_LABEL
, NULL_LABEL
);
if (gettoken() != T_ELSE
) {
addoplabel(OP_JUMP
, &label2
);
getstatement(contlabel
, breaklabel
, NULL_LABEL
, NULL_LABEL
);
case T_FOR
: /* for (a; b; c) x */
if (gettoken() != T_LEFTPAREN
) {
scanerror(T_SEMICOLON
, "Left parenthesis expected");
if (gettoken() != T_SEMICOLON
) { /* have 'a' part */
if (gettoken() != T_SEMICOLON
) {
scanerror(T_SEMICOLON
, "Missing semicolon");
if (gettoken() != T_SEMICOLON
) { /* have 'b' part */
addoplabel(OP_JUMPNE
, &label3
);
addoplabel(OP_JUMP
, breaklabel
);
if (gettoken() != T_SEMICOLON
) {
scanerror(T_SEMICOLON
, "Missing semicolon");
if (gettoken() != T_RIGHTPAREN
) { /* have 'c' part */
if (label1
.l_offset
<= 0)
addoplabel(OP_JUMP
, &label3
);
addoplabel(OP_JUMP
, &label1
);
if (gettoken() != T_RIGHTPAREN
) {
scanerror(T_SEMICOLON
, "Right parenthesis expected");
if (contlabel
== NULL_LABEL
)
getstatement(contlabel
, breaklabel
, NULL_LABEL
, NULL_LABEL
);
addoplabel(OP_JUMP
, contlabel
);
addoplabel(OP_JUMPEQ
, breaklabel
);
getstatement(contlabel
, breaklabel
, NULL_LABEL
, NULL_LABEL
);
addoplabel(OP_JUMP
, contlabel
);
getstatement(contlabel
, breaklabel
, NULL_LABEL
, NULL_LABEL
);
if (gettoken() != T_WHILE
) {
scanerror(T_SEMICOLON
, "WHILE keyword expected for DO statement");
addoplabel(OP_JUMPNE
, &label3
);
clearlabel(nextcaselabel
);
clearlabel(defaultlabel
);
if (gettoken() != T_LEFTBRACE
) {
scanerror(T_SEMICOLON
, "Missing left brace for switch statement");
addoplabel(OP_JUMP
, nextcaselabel
);
getstatement(contlabel
, breaklabel
, nextcaselabel
, defaultlabel
);
addoplabel(OP_JUMP
, breaklabel
);
if (defaultlabel
->l_offset
> 0)
addoplabel(OP_JUMP
, defaultlabel
);
if (nextcaselabel
== NULL_LABEL
) {
scanerror(T_SEMICOLON
, "CASE not within SWITCH statement");
addoplabel(OP_JUMP
, &label1
);
clearlabel(nextcaselabel
);
if (gettoken() != T_COLON
) {
scanerror(T_SEMICOLON
, "Colon expected after CASE expression");
addoplabel(OP_CASEJUMP
, nextcaselabel
);
getstatement(contlabel
, breaklabel
, nextcaselabel
, defaultlabel
);
if (gettoken() != T_COLON
) {
scanerror(T_SEMICOLON
, "Colon expected after DEFAULT keyword");
if (defaultlabel
== NULL_LABEL
) {
scanerror(T_SEMICOLON
, "DEFAULT not within SWITCH statement");
if (defaultlabel
->l_offset
> 0) {
scanerror(T_SEMICOLON
, "Multiple DEFAULT clauses in SWITCH");
addoplabel(OP_JUMP
, &label1
);
getstatement(contlabel
, breaklabel
, nextcaselabel
, defaultlabel
);
scanerror(T_SEMICOLON
, "ELSE without preceeding IF");
getmatdeclaration(SYM_UNDEFINED
);
getobjdeclaration(SYM_UNDEFINED
);
addopptr(OP_PRINTSTRING
, tokenstring());
addopone(OP_PRINT
, (long) PRINT_NORMAL
);
addopptr(OP_QUIT
, tokenstring());
if (nextchar() == ':') { /****HACK HACK ****/
definelabel(tokenstring());
getstatement(contlabel
, breaklabel
,
/* fall into default case */
if (contlabel
|| breaklabel
|| (curfunc
->f_name
[0] != '*')) {
if (isassign(type
) || (curfunc
->f_name
[1] != '\0')) {
scanerror(T_SEMICOLON
, "Semicolon expected");
* Read in an object declaration.
* This is of the following form:
* OBJ type [ '{' id [ ',' id ] ... '}' ] [ objlist ].
* The OBJ keyword has already been read. Symtype is SYM_UNDEFINED if this
* is an OBJ statement, otherwise this is part of a declaration which will
* define new symbols with the specified type.
getobjdeclaration(symtype
)
char *name
; /* name of object type */
int count
; /* number of elements */
int index
; /* current index */
int i
; /* loop counter */
BOOL err
; /* error flag */
int indices
[MAXINDICES
]; /* indices for elements */
if (gettoken() != T_SYMBOL
) {
scanerror(T_SEMICOLON
, "Object type name missing");
name
= addliteral(tokenstring());
if (gettoken() != T_LEFTBRACE
) {
getobjvars(name
, symtype
);
* Read in the definition of the elements of the object.
if (gettoken() != T_SYMBOL
) {
scanerror(T_SEMICOLON
, "Missing element name in OBJ statement");
index
= addelement(tokenstring());
for (i
= 0; i
< count
; i
++) {
if (indices
[i
] == index
) {
scanerror(T_NULL
, "Duplicate element name \"%s\"", tokenstring());
indices
[count
++] = index
;
(void) defineobject(name
, indices
, count
);
getobjvars(name
, symtype
);
scanerror(T_SEMICOLON
, "Bad object element definition");
* Routine to collect a set of variables for the specified object type
* and initialize them as being that type of object.
* objlist = name initlist [ ',' name initlist ] ... ';'.
* If symtype is SYM_UNDEFINED, then this is an OBJ statement where the
* values can be any variable expression, and no symbols are to be defined.
* Otherwise this is part of a declaration, and the variables must be raw
* symbol names which are defined with the specified symbol type.
getobjvars(name
, symtype
)
char *name
; /* object name */
long index
; /* index for object */
index
= checkobject(name
);
scanerror(T_SEMICOLON
, "Object %s has not been defined yet", name
);
if (symtype
== SYM_UNDEFINED
)
(void) getidexpr(TRUE
, TRUE
);
if (gettoken() != T_SYMBOL
) {
scanerror(T_SEMICOLON
, "Missing object variable name");
definesymbol(symname
, symtype
);
usesymbol(symname
, FALSE
);
addopone(OP_OBJCREATE
, index
);
scanerror(T_SEMICOLON
, "Bad OBJ statement");
* Read a matrix definition declaration for a one or more dimensional matrix.
* The MAT keyword has already been read. This also handles an optional
* matrix initialization list enclosed in braces. Symtype is SYM_UNDEFINED
* if this is part of a MAT statement which handles any variable expression.
* Otherwise this is part of a declaration and only a symbol name is allowed.
getmatdeclaration(symtype
)
if (symtype
== SYM_UNDEFINED
)
(void) getidexpr(FALSE
, TRUE
);
if (gettoken() != T_SYMBOL
) {
scanerror(T_COMMA
, "Missing matrix variable name");
definesymbol(name
, symtype
);
if (gettoken() != T_LEFTBRACKET
) {
scanerror(T_SEMICOLON
, "Missing left bracket for MAT");
* If there are no bounds given for the matrix, then they must be
* implicitly defined by a list of initialization values. Put in
* a dummy number in the opcode stream for the bounds and remember
* its location. After we know how many values are in the list, we
* will patch the correct value back into the opcode.
if (gettoken() == T_RIGHTBRACKET
) {
patchpc
= curfunc
->f_opcodecount
+ 1;
addopone(OP_NUMBER
, (long) -1);
addopone(OP_MATCREATE
, dim
);
scanerror(T_NULL
, "Initialization required for implicit matrix bounds");
index
= addqconstant(itoq(count
- 1));
math_error("Cannot allocate constant");
curfunc
->f_opcodes
[patchpc
] = index
;
* This isn't implicit, so we expect expressions for the bounds.
if (gettoken() != T_LEFTBRACKET
) {
addopone(OP_MATCREATE
, dim
);
/* proceed into comma case */
scanerror(T_SEMICOLON
, "Only %ld dimensions allowed", MAXDIM
);
scanerror(T_SEMICOLON
, "Illegal matrix definition");
* Get an optional initialization list for a matrix or object definition.
* Returns the number of elements that are in the list, or -1 on parse error.
* This assumes that the address of a matrix or object variable is on the
* stack, and so this routine will pop it off when complete.
* initlist = [ '=' '{' assignment [ ',' assignment ] ... '}' ].
if (gettoken() != T_ASSIGN
) {
oldmode
= tokenmode(TM_DEFAULT
);
if (gettoken() != T_LEFTBRACE
) {
scanerror(T_SEMICOLON
, "Missing brace for initialization list");
(void) tokenmode(oldmode
);
for (index
= 0; ; index
++) {
addopone(OP_ELEMINIT
, index
);
(void) tokenmode(oldmode
);
scanerror(T_SEMICOLON
, "Bad initialization list");
(void) tokenmode(oldmode
);
* condition = '(' assignment ')'.
if (gettoken() != T_LEFTPAREN
) {
scanerror(T_SEMICOLON
, "Missing left parenthesis for condition");
if (gettoken() != T_RIGHTPAREN
) {
scanerror(T_SEMICOLON
, "Missing right parenthesis for condition");
* Get an expression list consisting of one or more expressions,
* separated by commas. The value of the list is that of the final expression.
* This is the top level routine for parsing expressions.
* Returns flags describing the type of assignment or expression found.
* exprlist = assignment [ ',' assignment ] ...
while (gettoken() == T_COMMA
) {
* Get an assignment (or possibly just an expression).
* Returns flags describing the type of assignment or expression found.
* assignment = lvalue '=' assignment
* | lvalue '+=' assignment
* | lvalue '-=' assignment
* | lvalue '*=' assignment
* | lvalue '/=' assignment
* | lvalue '%=' assignment
* | lvalue '//=' assignment
* | lvalue '&=' assignment
* | lvalue '|=' assignment
* | lvalue '<<=' assignment
* | lvalue '>>=' assignment
* | lvalue '^=' assignment
* | lvalue '**=' assignment
int type
; /* type of expression */
long op
; /* opcode to generate */
case T_ASSIGN
: op
= 0; break;
case T_PLUSEQUALS
: op
= OP_ADD
; break;
case T_MINUSEQUALS
: op
= OP_SUB
; break;
case T_MULTEQUALS
: op
= OP_MUL
; break;
case T_DIVEQUALS
: op
= OP_DIV
; break;
case T_SLASHSLASHEQUALS
: op
= OP_QUO
; break;
case T_MODEQUALS
: op
= OP_MOD
; break;
case T_ANDEQUALS
: op
= OP_AND
; break;
case T_OREQUALS
: op
= OP_OR
; break;
case T_LSHIFTEQUALS
: op
= OP_LEFTSHIFT
; break;
case T_RSHIFTEQUALS
: op
= OP_RIGHTSHIFT
; break;
case T_POWEREQUALS
: op
= OP_POWER
; break;
scanerror(T_NULL
, "Missing operator");
scanerror(T_NULL
, "Illegal assignment");
return (EXPR_RVALUE
| EXPR_ASSIGN
);
return (EXPR_RVALUE
| EXPR_ASSIGN
);
* Get a possible conditional result expression (question mark).
* Flags are returned indicating the type of expression found.
* altcond = orcond [ '?' orcond ':' altcond ].
int type
; /* type of expression */
LABEL donelab
; /* label for done */
LABEL altlab
; /* label for alternate expression */
if (gettoken() != T_QUESTIONMARK
) {
addoplabel(OP_JUMPEQ
, &altlab
);
if (gettoken() != T_COLON
) {
scanerror(T_SEMICOLON
, "Missing colon for conditional expression");
addoplabel(OP_JUMP
, &donelab
);
* Get a possible conditional or expression.
* Flags are returned indicating the type of expression found.
* orcond = andcond [ '||' andcond ] ...
int type
; /* type of expression */
LABEL donelab
; /* label for done */
while (gettoken() == T_OROR
) {
addoplabel(OP_CONDORJUMP
, &donelab
);
* Get a possible conditional and expression.
* Flags are returned indicating the type of expression found.
* andcond = relation [ '&&' relation ] ...
int type
; /* type of expression */
LABEL donelab
; /* label for done */
while (gettoken() == T_ANDAND
) {
addoplabel(OP_CONDANDJUMP
, &donelab
);
* Get a possible relation (equality or inequality), or just an expression.
* Flags are returned indicating the type of relation found.
* relation = sum '==' sum
int type
; /* type of expression */
long op
; /* opcode to generate */
case T_EQ
: op
= OP_EQ
; break;
case T_NE
: op
= OP_NE
; break;
case T_LT
: op
= OP_LT
; break;
case T_GT
: op
= OP_GT
; break;
case T_LE
: op
= OP_LE
; break;
case T_GE
: op
= OP_GE
; break;
* Get an expression made up of sums of products.
* Flags indicating the type of expression found are returned.
* sum = product [ {'+' | '-'} product ] ...
int type
; /* type of expression found */
long op
; /* opcode to generate */
case T_PLUS
: op
= OP_ADD
; break;
case T_MINUS
: op
= OP_SUB
; break;
* Get the product of arithmetic or expressions.
* Flags indicating the type of expression found are returned.
* product = orexpr [ {'*' | '/' | '//' | '%'} orexpr ] ...
int type
; /* type of value found */
long op
; /* opcode to generate */
case T_MULT
: op
= OP_MUL
; break;
case T_DIV
: op
= OP_DIV
; break;
case T_MOD
: op
= OP_MOD
; break;
case T_SLASHSLASH
: op
= OP_QUO
; break;
* Get an expression made up of arithmetic or operators.
* Flags indicating the type of expression found are returned.
* orexpr = andexpr [ '|' andexpr ] ...
int type
; /* type of value found */
while (gettoken() == T_OR
) {
* Get an expression made up of arithmetic and operators.
* Flags indicating the type of expression found are returned.
* andexpr = shiftexpr [ '&' shiftexpr ] ...
int type
; /* type of value found */
while (gettoken() == T_AND
) {
* Get a shift or power expression.
* Flags indicating the type of expression found are returned.
* shift = term '^' shiftexpr
int type
; /* type of value found */
long op
; /* opcode to generate */
case T_POWER
: op
= OP_POWER
; break;
case T_LEFTSHIFT
: op
= OP_LEFTSHIFT
; break;
case T_RIGHTSHIFT
: op
= OP_RIGHTSHIFT
; break;
* Flags indicating the type of value found are returned.
* | lvalue '[' assignment ']'
* | function [ '(' [assignment [',' assignment] ] ')' ]
int type
; /* type of term found */
addopone(OP_NUMBER
, tokennumber());
type
= (EXPR_RVALUE
| EXPR_CONST
);
addopone(OP_IMAGINARY
, tokennumber());
type
= (EXPR_RVALUE
| EXPR_CONST
);
addopptr(OP_STRING
, tokenstring());
type
= (EXPR_RVALUE
| EXPR_CONST
);
scanerror(T_NULL
, "Bad ++ usage");
type
= (EXPR_RVALUE
| EXPR_ASSIGN
);
scanerror(T_NULL
, "Bad -- usage");
type
= (EXPR_RVALUE
| EXPR_ASSIGN
);
if (gettoken() != T_RIGHTPAREN
)
scanerror(T_SEMICOLON
, "Missing right parenthesis");
type
= getidexpr(TRUE
, FALSE
);
scanerror(T_NULL
, "Bad index usage");
scanerror(T_NULL
, "Bad element reference");
scanerror(T_NULL
, "Expression contains reserved keyword");
scanerror(T_NULL
, "Missing expression");
scanerror(T_NULL
, "Bad ++ usage");
return (EXPR_RVALUE
| EXPR_ASSIGN
);
scanerror(T_NULL
, "Bad -- usage");
return (EXPR_RVALUE
| EXPR_ASSIGN
);
* Read in an identifier expressions.
* This is a symbol name followed by parenthesis, or by square brackets or
* element refernces. The symbol can be a global or a local variable name.
* Returns the type of expression found.
getidexpr(okmat
, autodef
)
char name
[SYMBOLSIZE
+1]; /* symbol name */
/* fall into default case */
usesymbol(name
, autodef
);
* Now collect as many element references and matrix index operations
* as there are following the id.
scanerror(T_NULL
, "Function calls not allowed as expressions");
* Read in a filename for a read or write command.
* Both quoted and unquoted filenames are handled here.
* The name must be terminated by an end of line or semicolon.
* Returns TRUE if the filename was successfully parsed.
getfilename(name
, msg_ok
, once
)
BOOL msg_ok
; /* TRUE => ok to print error messages */
BOOL
*once
; /* non-NULL => set to TRUE of -once read */
/* look at the next token */
(void) tokenmode(TM_NEWLINES
| TM_ALLSYMS
);
scanerror(T_SEMICOLON
, "Filename expected");
strcpy(name
, tokenstring());
/* determine if we care about a possible -once option */
/* we care about a possible -once option */
if (strcmp(name
, "-once") == 0) {
/* look for the filename */
strcpy(name
, tokenstring());
/* look at the next token */
"Missing semicolon after filename");
* Read the show command and display useful information.
if ((gettoken() != T_SHOW
) || (gettoken() != T_SYMBOL
)) {
scanerror(T_SEMICOLON
, "Bad syntax for SHOW command");
strcpy(name
, tokenstring());
scanerror(T_SEMICOLON
, "Bad syntax for SHOW command");
switch ((int) stringindex("builtins\0builtin\0globals\0global\0functions\0function\0objfuncs\0objfunc\0memory\0", name
)) {
scanerror(T_NULL
, "Unknown SHOW parameter \"%s\"", name
);
* Read in a set of matrix index arguments, surrounded with square brackets.
* This also handles double square brackets for 'fast indexing'.
if (gettoken() != T_LEFTBRACKET
) {
scanerror(T_NULL
, "Matrix indexing expected");
* Parse all levels of the array reference
* Look for the 'fast index' first.
if (gettoken() == T_LEFTBRACKET
) {
if ((gettoken() != T_RIGHTBRACKET
) ||
(gettoken() != T_RIGHTBRACKET
)) {
scanerror(T_NULL
, "Bad fast index usage");
* Normal indexing with the indexes separated by commas.
* Initialize the flag in the opcode to assume that the array
* element will only be referenced for reading. If the parser
* finds that the element will be referenced for writing, then
* it will call writeindexop to change the flag in the opcode.
if (gettoken() != T_LEFTBRACKET
) {
addoptwo(OP_INDEXADDR
, (long) dim
,
/* proceed into comma case */
scanerror(T_NULL
, "Too many dimensions for array reference");
scanerror(T_NULL
, "Missing right bracket in array reference");
* Get an element of an object reference.
* The leading period which introduces the element has already been read.
index
= findelement(name
);
scanerror(T_NULL
, "Element \"%s\" is undefined", name
);
addopone(OP_ELEMADDR
, index
);
* Read in a single symbol name and copy its value into the given buffer.
* Returns TRUE if a valid symbol id was found.
scanerror(T_NULL
, "Reserved keyword used as symbol name");
scanerror(T_NULL
, "Symbol name expected");
strncpy(buf
, tokenstring(), SYMBOLSIZE
);
* Define a symbol name to be of the specified symbol type. This also checks
* to see if the symbol was already defined in an incompatible manner.
definesymbol(name
, symtype
)
switch (symboltype(name
)) {
if (symtype
== SYM_LOCAL
)
(void) addglobal(name
, (symtype
== SYM_STATIC
));
scanerror(T_COMMA
, "Variable \"%s\" is already defined", name
);
* Check a symbol name to see if it is known and generate code to reference it.
* The symbol can be either a parameter name, a local name, or a global name.
* If autodef is true, we automatically define the name as a global symbol
* if it is not yet known.
char *name
; /* symbol name to be checked */
switch (symboltype(name
)) {
addopone(OP_LOCALADDR
, (long) findlocal(name
));
addopone(OP_PARAMADDR
, (long) findparam(name
));
addopptr(OP_GLOBALADDR
, (char *) findglobal(name
));
* The symbol is not yet defined.
* If we are at the top level and we are allowed to, then define it.
if ((curfunc
->f_name
[0] != '*') || !autodef
) {
scanerror(T_NULL
, "\"%s\" is undefined", name
);
(void) addglobal(name
, FALSE
);
addopptr(OP_GLOBALADDR
, (char *) findglobal(name
));
* Get arguments for a function call.
* The name and beginning parenthesis has already been seen.
* callargs = [ [ '&' ] assignment [',' [ '&' ] assignment] ] ')'.
char *name
; /* name of function */
long index
; /* function index */
long op
; /* opcode to add */
int argcount
; /* number of arguments */
index
= getbuiltinfunc(name
);
index
= adduserfunc(name
);
if (gettoken() == T_RIGHTPAREN
) {
addopfunction(op
, index
, 0);
addrflag
= (gettoken() == T_AND
);
scanerror(T_NULL
, "Taking address of non-variable");
if (!addrflag
&& (op
!= OP_CALL
))
builtincheck(index
, argcount
);
addopfunction(op
, index
, argcount
);
scanerror(T_SEMICOLON
, "Missing right parenthesis in function call");