/* l2xiscan.c LTX2X Interpreter lexing routines */
/* Written by: Peter Wilson, CUA
[email protected] */
/* This code is partly based on algorithms presented by Ronald Mak in */
/* "Writing Compilers & Interpreters", John Wiley & Sons, 1991 */
#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include "l2xicmon.h"
#include "l2xierr.h"
#include "l2xiscan.h"
#include "l2xiidbg.h"
#ifndef l2xicpr_h
#include "l2xicpr.h" /* before/after token code lists */
#endif
#define EOF_CHAR 257
#define TAB_SIZE 8
#define QUOTE_CHAR '\''
#define MIN_RESERVED_WORD_LENGTH 2
#define MAX_RESERVED_WORD_LENGTH 15
/* US_CHAR is for ltx2x, adding undescore character */
#define US_CHAR '_'
/* CHARACTER CODES */
typedef enum{
LETTER,
DIGIT,
QUOTE,
SPECIAL,
EOF_CODE,
USCORE, /* for ltx2x underscore */
} CHAR_CODE;
#define EOS '\0'
/* RESERVED WORD TABLES */
typedef struct {
char *string;
TOKEN_CODE token_code;
} RW_STRUCT;
RW_STRUCT rw_2[] = {
{"if", IF}, /* P&E */
{"in", IN}, /* P&E */
{"of", OF}, /* P&E */
{"or", OR}, /* P&E */
{"to", TO}, /* P&E */
{"as", XAS},
{"by", XBY},
{"pi", XPI},
{NULL, 0 },
};
RW_STRUCT rw_3[] = {
{"and", AND}, /* P&E */
{"div", DIV}, /* P&E */
{"end", END}, /* P&E */
{"for", FOR}, /* P&E */
{"mod", MOD}, /* P&E */
{"not", NOT}, /* P&E */
{"set", SET}, /* P&E */
{"var", VAR}, /* P&E */
{"bag", XBAG},
{"use", XUSE},
{"xor", XXOR},
{NULL, 0 },
};
RW_STRUCT rw_4[] = {
{"case", CASE}, /* P&E */
{"else", ELSE}, /* P&E */
{"file", FFILE},
{"then", THEN}, /* P&E */
{"type", TYPE}, /* P&E */
{"with", WITH}, /* P&E */
{"from", XFROM},
{"list", XLIST},
{"real", XREAL},
{"rule", XRULE},
{"skip", XSKIP},
{"like", XLIKE},
{"self", XSELF},
{"true", XTRUE},
{"call", XCALL},
{NULL, 0 },
};
RW_STRUCT rw_5[] = {
{"array", ARRAY}, /* P&E */
{"begin", BEGIN}, /* P&E */
{"until", UNTIL}, /* P&E */
{"while", WHILE}, /* P&E */
{"alias", XALIAS},
{"fixed", XFIXED},
{"local", XLOCAL},
{"model", XMODEL},
{"oneof", XONEOF},
{"query", XQUERY},
{"where", XWHERE},
{"andor", XANDOR},
{"false", XFALSE},
{"notes", XNOTES},
{"subof", XSUBOF},
{"supof", XSUPOF},
{"using", XUSING},
{NULL, 0 },
};
RW_STRUCT rw_6[] = {
{"repeat", REPEAT}, /* P&E */
{"binary", XBINARY},
{"derive", XDERIVE},
{"end_if", XEND_IF},
{"entity", XENTITY},
{"escape", XESCAPE},
{"number", XNUMBER},
{"return", XRETURN},
{"schema", XSCHEMA},
{"select", XSELECT},
{"string", XSTRING},
{"unique", XUNIQUE},
{"import", XIMPORT},
{NULL, 0 },
};
RW_STRUCT rw_7[] = {
{"boolean", XBOOLEAN},
{"context", XCONTEXT},
{"generic", XGENERIC},
{"integer", XINTEGER},
{"inverse", XINVERSE},
{"logical", XLOGICAL},
{"subtype", XSUBTYPE},
{"const_e", XCONST_E},
{"unknown", XUNKNOWN},
{"purpose", XPURPOSE},
{"the_day", THE_DAY},
{NULL, 0 },
};
RW_STRUCT rw_8[] = {
{"end_code", ENDCODE}, /* for ltx2x */
{"function", FUNCTION}, /* P&E */
{"abstract", XABSTRACT},
{"constant", XCONSTANT},
{"end_case", XEND_CASE},
{"end_rule", XEND_RULE},
{"end_type", XEND_TYPE},
{"optional", XOPTIONAL},
{"criteria", XCRITERIA},
{"the_year", THE_YEAR},
{NULL, 0 },
};
RW_STRUCT rw_9[] = {
{"procedure", PROCEDURE}, /* P&E */
{"aggregate", XAGGREGATE},
{"end_alias", XEND_ALIAS},
{"end_local", XEND_LOCAL},
{"end_model", XEND_MODEL},
{"otherwise", XOTHERWISE},
{"reference", XREFERENCE},
{"supertype", XSUPERTYPE},
{"end_notes", XEND_NOTES},
{"objective", XOBJECTIVE},
{"parameter", XPARAMETER},
{"test_case", XTEST_CASE},
{"the_month", THE_MONTH},
{NULL, 0 },
};
RW_STRUCT rw_10[] = {
{"end_entity", XEND_ENTITY},
{"end_repeat", XEND_REPEAT},
{"end_schema", XEND_SCHEMA},
{"references", XREFERENCES},
{NULL, 0},
};
RW_STRUCT rw_11[] = {
{"end_context", XEND_CONTEXT},
{"enumeration", XENUMERATION},
{"end_purpose", XEND_PURPOSE},
{"realization", XREALIZATION},
{"schema_data", XSCHEMA_DATA},
{NULL, 0},
};
RW_STRUCT rw_12[] = {
{"end_constant", XEND_CONSTANT},
{"end_function", XEND_FUNCTION},
{"end_criteria", XEND_CRITERIA},
{NULL, 0},
};
RW_STRUCT rw_13[] = {
{"end_procedure", XEND_PROCEDURE},
{"end_objective", XEND_OBJECTIVE},
{"end_parameter", XEND_PARAMETER},
{"end_test_case", XEND_TEST_CASE},
{NULL, 0},
};
RW_STRUCT rw_14[] = {
{"end_references", XEND_REFERENCES},
{NULL, 0},
};
RW_STRUCT rw_15[] = {
{"end_realization", XEND_REALIZATION},
{"end_schema_data", XEND_SCHEMA_DATA},
{NULL, 0},
};
RW_STRUCT *rw_table[] = {
NULL, NULL, rw_2, rw_3, rw_4, rw_5, rw_6, rw_7, rw_8, rw_9,
rw_10, rw_11, rw_12, rw_13, rw_14, rw_15,
};
/* token lists */
/* Tokens that start or follow a statement */
TOKEN_CODE statement_start_list[] = {BEGIN, CASE, IF, REPEAT,
IDENTIFIER, XRETURN, XSKIP, XESCAPE, 0};
TOKEN_CODE statement_end_list[] = {SEMICOLON, TO, ENDCODE, END_OF_FILE, 0};
/* Tokens that start a declaration */
TOKEN_CODE declaration_start_list[] = {XENTITY, TYPE, XRULE, XCONSTANT,
XLOCAL, PROCEDURE, FUNCTION,
0};
TOKEN_CODE follow_indexes_list[] = {OF, IDENTIFIER, ARRAY, XBAG, XLIST, SET,
XBINARY, XBOOLEAN, XINTEGER, XLOGICAL,
XNUMBER, XREAL, XSTRING, XGENERIC,
SEMICOLON, ENDCODE, END_OF_FILE, 0};
/* Operator tokens */
TOKEN_CODE rel_op_list[] = {LT, LE, EQUAL, NE, GE, GT, COLONEQUALCOLON,
COLONNEQCOLON, IN, XLIKE, 0};
TOKEN_CODE add_op_list[] = {PLUS, MINUS, OR, XXOR, 0};
TOKEN_CODE mult_op_list[] = {STAR, SLASH, DIV, MOD, AND, 0};
TOKEN_CODE follow_header_list[] = {SEMICOLON, ENDCODE, END_OF_FILE, 0};
TOKEN_CODE follow_proc_id_list[] = {LPAREN, SEMICOLON, ENDCODE, END_OF_FILE, 0};
TOKEN_CODE follow_func_id_list[] = {LPAREN, COLON, SEMICOLON, END_OF_FILE, 0};
/* Tokens that follow a formal parameter list */
TOKEN_CODE follow_parms_list[] = {RPAREN, SEMICOLON, ENDCODE, END_OF_FILE, 0};
/* Tokens that follow an actual parameter list */
TOKEN_CODE follow_parm_list[] = {COMMA, RPAREN, 0};
/* Tokens that can follow an expression */
TOKEN_CODE follow_expr_list[] = {OF, SEMICOLON, ENDCODE, END_OF_FILE, 0};
/* Tokens that can start or follow a case label */
TOKEN_CODE case_label_start_list[] = {IDENTIFIER, NUMBER_LITERAL, PLUS, MINUS,
STRING_LITERAL, XOTHERWISE, 0};
TOKEN_CODE follow_case_label_list[] = {COLON, SEMICOLON, 0};
/* Tokens that follow declarations in SETUP code */
TOKEN_CODE ltx2x_follow_decls_list[] = {SEMICOLON, BEGIN, CASE, IF, REPEAT,
IDENTIFIER, ENDCODE, 0};
/* Tokens that follow declarations in procedures/functions */
TOKEN_CODE follow_decls_list[] = {SEMICOLON, BEGIN, CASE, IF, REPEAT,
IDENTIFIER, XRETURN, XEND_FUNCTION,
XEND_PROCEDURE, ENDCODE, END_OF_FILE, 0};
/* The tokens for simple types */
TOKEN_CODE simple_type_list[] = {XBINARY, XBOOLEAN, XINTEGER, XLOGICAL,
XNUMBER, XREAL, XSTRING, XGENERIC, 0};
/* the tokens of constants */
TOKEN_CODE constant_list[] = {QUERY_CHAR, XCONST_E, XFALSE, XPI, XSELF, XTRUE,
XUNKNOWN, THE_DAY, THE_MONTH, THE_YEAR, 0};
/* The tokens of aggregates */
TOKEN_CODE aggregation_type_list[] = {ARRAY, SET, XAGGREGATE, XBAG, XLIST, 0};
TOKEN_CODE follow_min_bound_list[] = {COLON, NUMBER_LITERAL, LPAREN, MINUS,
PLUS, 0};
/* The tokens that can follow an entity's explicit attributes */
TOKEN_CODE follow_attributes_list[] = {XDERIVE, XUNIQUE, XINVERSE, XWHERE,
XEND_ENTITY, 0};
/* GLOBALS */
/* char ch; */
int ch;
TOKEN_CODE token; /* code of current token */
LITERAL literal; /* value of a literal */
int buffer_offset; /* char offset into source buffer */
int level = 0; /* current nesting level */
int line_number = 0; /* current source line number */
BOOLEAN print_flag = TRUE; /* TRUE to print source lines */
BOOLEAN block_flag = FALSE; /* TRUE iff parsing a block */
BOOLEAN in_comment = FALSE; /* TRUE iff in an EXPRESS comment */
BOOLEAN in_eol_comment = FALSE; /* TRUE iff in an EXPRESS eol comment */
int num_opencom = 0; /* # of open EXPRESS comment markers */
char source_buffer[MAX_SOURCE_LINE_LENGTH]; /* source file buffer */
char token_string[MAX_TOKEN_STRING_LENGTH]; /* token string */
char word_string[MAX_TOKEN_STRING_LENGTH]; /* single-cased token string */
char *bufferp = source_buffer; /* ptr to source buffer */
char *tokenp = token_string; /* ptr to token string */
int digit_count; /* total # of digits in number */
BOOLEAN count_error; /* TRUE iff too many digits in number */
/* int page_number = 0; current o/p page number */
/* int line_count = MAX_LINES_PER_PAGE; # of lines on current o/p page */
char source_name[MAX_FILE_NAME_LENGTH]; /* name of source file */
char date[DATE_STRING_LENGTH]; /* current date and time */
FILE *source_file;
/* CHAR_CODE char_table[256]; ----------- add two to this */
CHAR_CODE char_table[258]; /* ----------- added two to this */
/* array of string representation of token codes */
char *tok_code_strs[] = {
#define sctc(a, b, c) b,
#include "l2xisctc.h"
#undef sctc
};
/* MACROS */
/* char_code(ch) return the character code of ch */
#define char_code(ch) char_table[ch]
/* FORWARDS */
/* init_tok_code_strs(); */
/***************************************************************************/
/* init_scanner(name) Initialise the scanner globals and open source */
/* file. */
/***************************************************************************/
/* init_scanner(afil) Initialise the scanner globals and set the source */
/* file. */
init_scanner(afil)
FILE *afil; /* source file */
{
int ich;
/*
* sprintf(dbuffer,"\n init_scanner called with name = %s\n", name);
* debug_print(dbuffer);
*/
/* initialise character table */
for (ich = 0; ich < 256; ++ich) char_table[ich] = SPECIAL;
for (ich = '0'; ich <= '9'; ++ich) char_table[ich] = DIGIT;
for (ich = 'A'; ich <= 'Z'; ++ich) char_table[ich] = LETTER;
for (ich = 'a'; ich <= 'z'; ++ich) char_table[ich] = LETTER;
char_table[QUOTE_CHAR] = QUOTE;
char_table[US_CHAR] = USCORE;
char_table[EOF_CHAR] = EOF_CODE;
source_file = afil;
/* get the first character */
bufferp = "";
get_char();
debug_print(" init_scanner: All done\n");
return;
} /* end init_scanner */
/***************************************************************************/
/***************************************************************************/
/* quit_scanner() no more scanning */
quit_scanner()
{
/* close_source_file(); */
} /* end quit_scanner */
/***************************************************************************/
/* CHARACTER ROUTINES */
/***************************************************************************/
/* get_char() set ch to next char from the source buffer */
get_char()
{
BOOLEAN get_source_line();
/* if current source line exhausted, get next line */
/* if file exhausted, set ch to EOF character and return */
if (*bufferp == EOS) {
if (!get_source_line()) {
ch = EOF_CHAR;
return;
}
bufferp = source_buffer;
buffer_offset = 0;
}
ch = *bufferp++;
/* special character processing */
/* tab --- up buffer offset to next multiple of TAB_SIZE, and replace */
/* ch with a blank */
/* newline -- replace ch with a blank */
/* { (start of comment) -- skip over comment and replace with a blank */
switch (ch) {
case '\t': {
buffer_offset += TAB_SIZE - buffer_offset%TAB_SIZE;
ch = ' ';
break;
}
case '\n': {
++buffer_offset;
ch = ' ';
break;
}
case '-': { /* start of eol comment? */
if (*bufferp == '-') { /* yest, an eol comment */
skip_eol_comment();
ch = ' ';
}
else {
++buffer_offset;
}
break;
}
case '(': { /* start of long comment? */
if (*bufferp == '*') { /* yes, a long comment */
skip_long_comment();
ch = ' ';
}
else {
++buffer_offset;
}
break;
}
default: {
++buffer_offset;
break;
}
} /* end switch */
} /* end get_char */
/***************************************************************************/
/***************************************************************************/
/* skip_comment() skip over a comment and set ch to 'end of comment' char */
skip_comment()
{
do {
get_char();
} while ((ch != '}') && (ch != EOF_CHAR));
} /* end skip_coment */
/***************************************************************************/
/***************************************************************************/
/* skip_eol_comment() skip over an EXPRESS eol comment */
skip_eol_comment()
{
/* skip to the next line */
if (!get_source_line()) {
ch = EOF_CHAR;
return;
}
bufferp = source_buffer;
buffer_offset = 0;
return;
} /* end SKIP_EOL_COMMENT */
/***************************************************************************/
/***************************************************************************/
/* skip_long_comment() skip over an EXPRESS long comment */
skip_long_comment()
{
BOOLEAN get_source_line();
num_opencom = 1;
/* update buffer pointers to the * after the ( */
*bufferp++;
++buffer_offset;
while (num_opencom > 0) {
/* if current source line exhausted, get next line */
/* if file exhausted, set ch to EOF character and return */
if (*bufferp == EOS) {
if (!get_source_line()) {
ch = EOF_CHAR;
return;
}
bufferp = source_buffer;
buffer_offset = 0;
}
ch = *bufferp++;
switch (ch) {
case '(': { /* start of long comment? */
if (*bufferp == '*') { /* yes */
num_opencom++;
*bufferp++;
++buffer_offset;
}
break;
}
case '*': { /* end of long comment? */
if (*bufferp == ')') { /* yes */
num_opencom--;
*bufferp++;
++buffer_offset;
}
break;
}
default: {
break;
}
} /* end switch */
++buffer_offset;
} /* end while */
return;
} /* end SKIP_LONG_COMMENT */
/***************************************************************************/
/***************************************************************************/
/* skip_blanks skip past any blanks at current location in source */
/* buffer and set ch to next non-blank char */
skip_blanks()
{
while (ch == ' ') get_char();
} /* end skip_blanks */
/***************************************************************************/
/* TOKEN ROUTINES */
/* after a token has been extracted, ch is the first char after the token */
/***************************************************************************/
/* get_token extract next token from source buffer */
get_token()
{
entry_debug("get_token");
scan_source_debug();
skip_blanks();
tokenp = token_string;
switch (char_code(ch)) {
case LETTER: {
get_word();
break;
}
case DIGIT: {
get_number();
break;
}
case QUOTE: {
get_string();
break;
}
case EOF_CODE: {
token = END_OF_FILE;
break;
}
default: {
get_special();
break;
}
} /* end switch */
scan_token_debug();
/* for the interpeter: If parsing a block, crunch the token code */
/* and append it to the code buffer */
if (block_flag) crunch_token();
exit_debug("get_token");
} /* end get_token */
/***************************************************************************/
/***************************************************************************/
/* get_word extract a word, shift into single case. If not a reserved */
/* set token to IDENTIFIER */
/* for ltx2x, added underscore as an allowed word character */
get_word()
{
BOOLEAN is_reserved_word();
entry_debug("get_word");
scan_source_debug();
/* extract the word */
while ((char_code(ch) == LETTER) ||
(char_code(ch) == DIGIT) ||
(char_code(ch) == USCORE)) {
*tokenp++ = ch;
get_char();
}
*tokenp = EOS;
shift_word();
if (!is_reserved_word()) token = IDENTIFIER;
exit_debug("get_word");
} /* end get_word */
/***************************************************************************/
/***************************************************************************/
/* shift_word() copy a word token into word_string with all letters */
/* in the same (lower? higher?) case */
shift_word()
{
int offset = 'a' - 'A'; /* offset to downshift a letter */
char *wp = word_string;
char *tp = token_string;
/* copy word into word_string, shifting as we go */
do {
*wp++ = (*tp >= 'A') && (*tp <= 'Z') /* check for wrong case letter */
? *tp + offset /* shift and copy */
: *tp; /* or just copy */
++tp;
} while (*tp != EOS);
*wp = EOS;
} /* end shift_word */
/***************************************************************************/
/***************************************************************************/
/* get_number extract a number token and set literal to its value. */
/* set token to NUMBER_LITERAL */
get_number()
{
int whole_count = 0; /* # of digits in whole part */
int decimal_offset = 0; /* # of digits to move decimal */
char exponent_sign = '+';
int exponent = 0; /* value of exponent */
XPRSAREAL nvalue = 0.0; /* value of number */
XPRSAREAL evalue = 0.0; /* value of exponent */
BOOLEAN saw_dotdot = FALSE; /* TRUE if found .. */
entry_debug("get_number");
digit_count = 0;
count_error = FALSE;
token = NO_TOKEN;
literal.type = INTEGER_LIT;
/* extract the whole part of the number */
accumulate_value(&nvalue, INVALID_NUMBER);
if (token == ERROR) {
exit_debug("get_number");
return;
}
whole_count = digit_count;
/* if current char is a . then either start of fraction or .. */
if (ch == '.') {
get_char();
if (ch == '.') {
/* have a .. token, backup bufferp so that the token can be */
/* extracted next */
saw_dotdot = TRUE;
--bufferp;
}
else { /* start of a fraction */
literal.type = REAL_LIT;
*tokenp++ = '.';
/* accumulate fraction part */
accumulate_value(&nvalue, INVALID_FRACTION);
if (token == ERROR) return;
decimal_offset = whole_count - digit_count;
}
}
/* extract the exponent part, if any. None if seen a .. */
if (!saw_dotdot && ((ch == 'E') || (ch == 'e'))) {
literal.type = REAL_LIT;
*tokenp++ = ch;
get_char();
/* get sign, if any */
if ((ch == '+') || (ch == '-')) {
*tokenp++ = exponent_sign = ch;
get_char();
}
/* extract the exponent and accumulate into evalue */
accumulate_value(&evalue, INVALID_EXPONENT);
if (token == ERROR) return;
if (exponent_sign == '-') evalue = -evalue;
}
/* Too many digits? */
if (count_error) {
error(TOO_MANY_DIGITS);
token = ERROR;
exit_debug("get_number");
return;
}
/* adjust the number's value using decimal_offset and exponent */
exponent = evalue + decimal_offset;
if ((exponent + whole_count < -MAX_EXPONENT) ||
(exponent + whole_count > MAX_EXPONENT)) {
error(REAL_OUT_OF_RANGE);
token = ERROR;
exit_debug("get_number");
return;
}
if (exponent != 0) {
nvalue = nvalue*pow(10.0, (double) exponent);
}
/* set the literal's value */
if (literal.type == INTEGER_LIT) {
if ((nvalue < -MAX_INTEGER) ||
(nvalue > MAX_INTEGER)) {
error(INTEGER_OUT_OF_RANGE);
token = ERROR;
exit_debug("get_number");
return;
}
literal.value.integer = (XPRSAINT) nvalue;
}
else {
literal.value.real = nvalue;
}
*tokenp = EOS;
token = NUMBER_LITERAL;
exit_debug("get_number");
} /* end get_number */
/***************************************************************************/
/***************************************************************************/
/* get_string() Extract a string token. Set token to STRING_LITERAL. */
/* Quotes are stored as part of token_string, but not */
/* as part of literal.value.string */
get_string()
{
char *sp = literal.value.string;
*tokenp++ = QUOTE_CHAR;
get_char();
/* extract the string (two consecutive quotes represent a single quote) */
while (ch != EOF_CHAR) {
if (ch == QUOTE_CHAR) {
*tokenp++ = ch;
get_char();
if (ch != QUOTE_CHAR) break;
}
*tokenp++ = ch;
*sp++ = ch;
get_char();
}
*tokenp = EOS;
*sp = EOS;
token = STRING_LITERAL;
literal.type = STRING_LIT;
sprintf(dbuffer, "Scanned string: sp = %s, tokenp = %s\n",
literal.value.string, token_string);
debug_print(dbuffer);
} /* end get_string */
/***************************************************************************/
/***************************************************************************/
/* get_special() Extract a special token. Most are single chars, but some */
/* are multiple. Set appropriate token value */
get_special()
{
*tokenp++ = ch;
switch (ch) {
case ')': token = RPAREN; get_char(); break;
case '+': token = PLUS; get_char(); break;
case '[': token = LBRACKET; get_char(); break;
case ']': token = RBRACKET; get_char(); break;
case ';': token = SEMICOLON; get_char(); break;
case ',': token = COMMA; get_char(); break;
case '.': token = PERIOD; get_char(); break;
case '/': token = SLASH; get_char(); break;
/* extra for EXPRESS */
case '{': token = LBRACE; get_char(); break;
case '}': token = RBRACE; get_char(); break;
case '?': token = QUERY_CHAR; get_char(); break;
case '%': token = PERCENT; get_char(); break;
case '\\': token = BACKSLASH; get_char(); break;
case '@': token = COMMERCIAL_AT; get_char(); break;
case '!': token = EXCLAMATION; get_char(); break;
case '"': token = DOUBLEQUOTE; get_char(); break;
case '*': { /* * (EXPRESS or ** or *) */
get_char();
if (ch == '*') {
*tokenp++ = '*';
token = STARSTAR;
get_char();
}
else if (ch == ')') {
*tokenp++ = ')';
token = STARPAREN;
get_char();
}
else {
token = STAR;
}
break;
}
case '-': { /* - (EXPRESS or -- or -> ) */
get_char();
if (ch == '-') {
*tokenp++ = '-';
token = MINUSMINUS;
get_char();
}
else if (ch == '>') {
*tokenp++ = '>';
token = MINUSGT;
get_char();
}
else {
token = MINUS;
}
break;
}
case '=': { /* = (EXPRESS == ) */
get_char();
if (ch == '=') {
*tokenp++ = '=';
token = EQUALEQUAL;
get_char();
}
else {
token = EQUAL;
}
break;
}
case ':': { /* : or := (EXPRESS or :=: or :<>: ) */
get_char();
if (ch == '=') {
*tokenp++ = '=';
token = COLONEQUAL;
get_char();
if (ch == ':') {
*tokenp++ = ':';
token = COLONEQUALCOLON;
get_char();
}
}
else if (ch == '<') {
get_char();
if (ch == '>') {
get_char();
if (ch == ':') {
*tokenp++ = '<';
*tokenp++ = '>';
*tokenp++ = ':';
token = COLONNEQCOLON;
get_token();
}
}
}
else {
token = COLON;
}
break;
}
case '<': { /* < or <= or <> (EXPRESS-I <- ) */
get_char();
if (ch == '=') {
*tokenp++ = '=';
token = LE;
get_char();
}
else if (ch == '>') {
*tokenp++ = '>';
token = NE;
get_char();
}
else if (ch == '-') {
*tokenp++ = '-';
token = LTMINUS;
get_char();
}
else {
token = LT;
}
break;
}
case '>': { /* > or >= */
get_char();
if (ch == '=') {
*tokenp++ = '=';
token = GE;
get_char();
}
else token = GT;
break;
}
case '(': { /* ( (EXPRESS (* ) */
get_char();
if (ch == '*') {
*tokenp++ = '*';
token = PARENSTAR;
get_char();
}
else {
token = LPAREN;
}
break;
}
case '|': { /* (EXPRESS | or || ) */
get_char();
if (ch == '|') {
*tokenp++ = '|';
token = BARBAR;
get_char();
}
else {
token = BAR;
}
break;
}
default: {
token = ERROR;
get_char();
break;
}
} /* end switch */
*tokenp = EOS;
} /* end get_special */
/***************************************************************************/
/***************************************************************************/
/* accumulate_value(valuep, error_code) Extract a number part (digits) */
/* and accumulate its value. */
/* Error if first char not a digit */
accumulate_value(valuep, error_code)
XPRSAREAL *valuep;
ERROR_CODE error_code;
{
XPRSAREAL value = *valuep;
/* error if first char not a digit */
if (char_code(ch) != DIGIT) {
error(error_code);
token = ERROR;
return;
}
/* accumulate the value, provided not too many digits */
do {
*tokenp++ = ch;
if (++digit_count <= MAX_DIGIT_COUNT) value = 10*value + (ch - '0');
else count_error = TRUE;
get_char();
} while (char_code(ch) == DIGIT); /* end do */
*valuep = value;
} /* end accumulate_value */
/***************************************************************************/
/* TOKEN TESTERS */
/***************************************************************************/
/* token_in(token_list) If the current token is in token_list */
/* return TRUE, else FALSE. */
BOOLEAN token_in(token_list)
TOKEN_CODE token_list[];
{
TOKEN_CODE *atokenp;
if (token_list == NULL) return(FALSE);
for (atokenp = &token_list[0]; *atokenp; ++atokenp) {
if (token == *atokenp) return(TRUE);
}
return(FALSE);
} /* end */
/***************************************************************************/
/***************************************************************************/
/* synchronize(token_list1, token_list2, token_list3) If the current token */
/* is not in any of the lists, flag it as an error. Then skip tokens */
/* until one of those in the lists is found */
synchronize(token_list1, token_list2, token_list3)
TOKEN_CODE token_list1[], token_list2[], token_list3[];
{
BOOLEAN error_flag = (!token_in(token_list1)) &&
(!token_in(token_list2)) &&
(!token_in(token_list3));
if (error_flag) {
/* error(token == END_OF_FILE ? UNEXPECTED_END_OF_FILE
* : UNEXPECTED_TOKEN);
*/
if (token == END_OF_FILE) error(UNEXPECTED_END_OF_FILE);
else if (token == ENDCODE) error(UNEXPECTED_ENDCODE);
else error(UNEXPECTED_TOKEN);
/* skip tokens to synchronize */
while ((!token_in(token_list1)) &&
(!token_in(token_list2)) &&
(!token_in(token_list3)) &&
((token != END_OF_FILE) || (token != ENDCODE))) {
get_token();
}
}
} /* end synchronize */
/***************************************************************************/
/***************************************************************************/
/* is_reserved_word() If token is a reserved word, set token and */
/* return TRUE, else return FALSE */
BOOLEAN is_reserved_word()
{
int word_length = strlen(word_string);
RW_STRUCT *rwp;
/* is length in range? */
if ((word_length >= MIN_RESERVED_WORD_LENGTH) &&
(word_length <= MAX_RESERVED_WORD_LENGTH)) { /* check in approp. word list */
for (rwp = rw_table[word_length]; rwp->string != NULL; ++rwp) {
if (strcmp(word_string, rwp->string) == 0) {
token = rwp->token_code;
return(TRUE);
}
}
}
return(FALSE);
} /* end is_reserved_word */
/***************************************************************************/
/* SOURCE FILE ROUTINES */
/***************************************************************************/
/* open_source_file(name) Open the named file and fetch the first char */
open_source_file(name)
char *name;
{
if ((name == NULL) || ((source_file = fopen(name, "r")) == NULL)) {
error(FAILED_SOURCE_FILE_OPEN);
exit(-FAILED_SOURCE_FILE_OPEN);
}
/* get the first character */
bufferp = "";
get_char();
} /* end open_source_file */
/***************************************************************************/
/***************************************************************************/
/* close_source_file() */
close_source_file()
{
fclose(source_file);
} /* end close_source_file */
/***************************************************************************/
/***************************************************************************/
/* get_source_line() Read the next line from the source file. If there is */
/* one, print it out and return TRUE. */
/* return FALSE for end of file */
BOOLEAN get_source_line()
{
char print_buffer[MAX_SOURCE_LINE_LENGTH + 9];
entry_debug("get_source_line");
if ((fgets(source_buffer, MAX_SOURCE_LINE_LENGTH, source_file)) != NULL) {
++line_number;
if (print_flag) {
sprintf(print_buffer, "%4d %d: %s", line_number, level, source_buffer);
print_line(print_buffer);
}
exit_debug("get_source_line");
return(TRUE);
}
exit_debug("get_source_line");
return(FALSE);
} /* end get_source_line */
/***************************************************************************/
/* PRINTOUT ROUTINES */
/***************************************************************************/
/* print_line(line) Print out a line. */
print_line(line)
char line[];
{
char save_ch;
char *save_chp = NULL;
entry_debug("print_line");
if (strlen(line) > MAX_PRINT_LINE_LENGTH) {
save_chp = &line[MAX_PRINT_LINE_LENGTH];
save_ch = *save_chp;
*save_chp = EOS;
}
/* fprintf(filout, "%s", line); */
/* ltx2x change, print to stdout, not o/p file */
/* printf("%s", line); just print to error file */
fprintf(ferr, "%s", line); /* PW addition -> error file */
if (save_chp) *save_chp = save_ch;
exit_debug("print_line");
return;
} /* end print_line */
/***************************************************************************/
/***************************************************************************/
/* tok_code_to_str(tok) Returns a string wrt a TOKEN_CODE */
char *tok_code_to_str(tok)
TOKEN_CODE tok;
{
if ((tok >= NO_TOKEN) && (tok <= EOTC)) return(tok_code_strs[tok]);
return(NULL);
} /* end tok_code_to_str */
/***************************************************************************/