/* shell.slex - small lex description for VxWorks shell */
/*
modification history
--------------------
01s,30may88,dnw  changed to v4 names.
01r,28may88,dnw  changed calls to atoi() and atof() to sscanf().
01q,18mar88,gae  allowed '^' to occur in strings.
01p,18nov87,gae  added T_UNKNOWN for undefined symbols.
		 made shell float types default to double.
01o,28oct87,gae  got rid of string type.
01n,20oct87,gae  fixed lexScan() bug - used MAX_SHELL_LINE for temp. buffer.
		   added scanning of octal chars, eg. '\377'.
01m,07aug87,gae  fixed final state of octal.
		 changed type specifiers to conventional C type casting.
01l,01jun87,gae  added interpretation of bytes, words, floats, doubles.
		 added type specifiers a la assembler, .[bwfdls].
		 fixed table for "*=".
01k,09jan87,gae  fixed '^', and '\^'.
01j,24dec86,gae  added '->' back into table accidentally removed in 01h.
01i,24nov86,llk  deleted SYSTEM conditional compiles.
01h,08oct86,gae  added C assignment operators.
01g,04jun86,dnw  changed sstLib calls to symLib.
01f,11oct85,dnw  de-linted.
01e,19jun85,dnw  added conditional compilation for BSD 4.2 load modules.
01d,10sep84,dnw  included routines from lexLib directly in this module.
		 fixed bug in automatic parens insertion.
01c,29aug84,jlf  changed to treat "_" as a normal alphabetic character.
01b,18aug84,dnw  changed to recognize and discard "/* .... " style comments.
		 changed to treat ';' like a NL for automatic insertion of ().
01a,02aug84,dnw  written
*/
int lexNclasses;
TINY lexClass [];
#define RETRACT		lexRetract (); string[--nChars] = EOS
TINY lexStateTable [];
typedef enum		/* states for automatic insertion of parens in yylex */
    {
    FIRST_LEXEME,
    NORMAL,
    P_OPEN,
    P_OPEN_DONE,
    P_CLOSE,
    P_CLOSE_DONE,
    } AUTO_STATE;
LOCAL AUTO_STATE autoState;		/* state of auto parens mods */
LOCAL char *nextChar;			/* ptr to next input char in line */
LOCAL char tempStrings [MAX_SHELL_LINE];/* storage for strings while parsing */
LOCAL char *nextTempString;		/* ptr to free space in tempStrings */
/* forward declaration */
LOCAL int typeCast ();
/*******************************************************************************
*
* lexNewLine - initialize for lexical scan of new line
*/
LOCAL VOID lexNewLine (line)
    char *line;
    {
    lexInit ();
    nextChar = line;
    nextTempString = tempStrings;
    autoState = FIRST_LEXEME;
    }
/*******************************************************************************
*
* yylex - get next lexeme for yacc
*
* This routine is called by yacc to get the next input lexeme.
* In addition to simply calling lexScan to do the scan, this routine
* also handles the automatic insertion of parens around the arguements
* of a "top-level" routine call.  If the first lexeme scanned from a new
* line is a T_SYMBOL (text id) and the second lexeme is NOT a '(',
* then the second lexeme is withheld and a '(' returned instead.
* The withheld lexeme is returned next.  Scanning then proceeds normally
* until a NL (newline) lexeme is scanned.  The NL is withheld and a
* ')' is returned instead, with the NL being returned next.
*/
LOCAL int yylex ()
    {
    static int heldCode;
    FAST int code;
    switch (autoState)
	{
        case FIRST_LEXEME:		/* first lex scan of new line */
	    code = lexScan ();
	    autoState = (code == T_SYMBOL) ? P_OPEN : NORMAL;
	    break;
	case NORMAL:			/* parens not required to be inserted */
	    code = lexScan ();
	    if (code == ';')
		autoState = FIRST_LEXEME;
	    break;
	case P_OPEN:			/* looking for '(' */
	    code = lexScan ();
	    if (code == '(')
		autoState = NORMAL;
	    else
		{
		heldCode = code;
		code = '(';
		autoState = P_OPEN_DONE;
		}
	    break;
	case P_OPEN_DONE:		/* artificial '(' has been returned */
	    if ((heldCode == NL) || (heldCode == ';'))
		{
		code = ')';
		autoState = P_CLOSE_DONE;
		}
	    else
		{
		code = heldCode;
		autoState = P_CLOSE;
		}
	    break;
	case P_CLOSE:			/* looking for NL or ';' */
	    code = lexScan ();
	    if ((code == NL) || (code == ';'))
		{
		heldCode = code;
		code = ')';
		autoState = P_CLOSE_DONE;
		}
	    break;
	case P_CLOSE_DONE:		/* artificial ')' has been returned */
	    code = heldCode;
	    autoState = FIRST_LEXEME;
	    break;
	}
    return (code);
    }
/*******************************************************************************
*
* addTempString - add string to temporary storage
*
* This routine adds the specified string to the during-parse temporary
* string storage.
*/
LOCAL char *addTempString (string)
    char *string;
    {
    char *newString = nextTempString;
    while (*string != EOS)
	string += strToChar (string, nextTempString++);
    *(nextTempString++) = EOS;
    return (newString);
    }
/*******************************************************************************
*
* lexError - report error in lex scan
*/
LOCAL VOID lexError (string, errmsg)
    char *string;
    char *errmsg;
    {
    printf ("%s: %s\n", errmsg, string);
    }
/*******************************************************************************
*
* getNum - interpret scanned string as integer
*/
LOCAL int getNum (string, fmtString, pValue)
    char *string;
    char *fmtString;
    VALUE *pValue;
    {
    pValue->side = RHS;
    pValue->type = T_INT;
    sscanf (string, fmtString, &pValue->value.rv);
    return (NUMBER);
    }
/*******************************************************************************
*
* getFloat - interpret scanned string as float
*/
LOCAL int getFloat (string, pValue)
    char *string;
    VALUE *pValue;
    {
    pValue->side = RHS;
    pValue->type = T_DOUBLE;
    sscanf (string, "%F", &pValue->value.dp);
    return (FLOAT);
    }
/*******************************************************************************
*
* getString - interpret scanned string as quoted string
*/
LOCAL int getString (string, nChars, pValue)
    char *string;
    int nChars;
    VALUE *pValue;
    {
    pValue->side = RHS;
    pValue->type = T_INT;
    string [nChars - 1] = EOS;
    pValue->value.rv = (int)addTempString (&string[1]);
    return (STRING);
    }
/*******************************************************************************
*
* getChar - interpret scanned string as quoted character
*/
LOCAL int getChar (string, nChars, pValue)
    char *string;
    int nChars;
    VALUE *pValue;
    {
    char ch;
    int n = strToChar (&string [1], &ch);
    if (nChars != (n + 2))
	{
	lexError (string, "invalid char"); 
	return (LEX_ERROR);
	}
    pValue->side       = RHS;
    pValue->type       = T_BYTE;
    pValue->value.byte = ch;
    return (CHAR);
    }
/*******************************************************************************
*
* getId - interpret scanned string as identifier or keyword
*/
LOCAL int getId (string, pValue)
    char *string;
    FAST VALUE *pValue;
    {
    char tempString [MAX_SHELL_LINE + 1];
    UTINY type;
    int t = typeCast (string);
    if (t != ERROR)
	{
	pValue->type = (TYPE)t;
	return (TYPECAST);
	}
    tempString[0] = '_';
    strncpy (&tempString[1], string, MAX_SHELL_LINE);
    tempString [MAX_SHELL_LINE] = EOS;
    if ((symFind (sysSymTbl, &tempString[1], 
	 		(char **) &pValue->value.lv, &type) == OK) ||
        (symFind (sysSymTbl, &tempString[0], 
			(char **) &pValue->value.lv, &type) == OK))
	{
	pValue->type = T_INT;
	pValue->side = LHS;
	if ((type & N_TYPE) == N_TEXT)
	    return (T_SYMBOL);
	else
	    return (D_SYMBOL);
	}
    else
	{
	pValue->side = RHS;
	pValue->type = T_UNKNOWN;
	pValue->value.rv = (int)addTempString (string);
	return (U_SYMBOL);
	}
    }
/*******************************************************************************
*
* typeCast - determine if string is a keyword type cast
*/
LOCAL int typeCast (string)
    FAST char *string;
    {
    static char *typen [] =
	{"char", "short", "int", "long", "float", "double"};
    static TYPE  typet [] =
	{T_BYTE, T_WORD, T_INT, T_INT, T_FLOAT, T_DOUBLE};
    FAST int ix;
    for (ix = 0; ix < NELEMENTS (typet); ix++)
	{
	if (strcmp (string, typen [ix]) == 0)
	    return ((int)typet [ix]);
	}
    return (ERROR);
    }
/*******************************************************************************
*
* strToChar - get a possibly escaped character from a string
*/
LOCAL int strToChar (string, pChar)
    FAST char *string;
    char *pChar;
    {
    FAST int nchars = 1;
    int num;
    FAST char ch;
    if (*string != '\\')
	{
	*pChar = *string;
	return (nchars);
	}
    string++;
    if ((*string >= '0') && (*string <= '7'))
	{
	sscanf (string, "%o", &num);
	ch = num % 0400;
	while ((*string >= '0') && (*string <= '7'))
	    {
	    ++string;
	    ++nchars;
	    }
	}
    else
	{
	nchars++;
	switch (*string)
	    {
	    case 'n':  ch = '\n'; break;
	    case 't':  ch = '\t'; break;
	    case 'b':  ch = '\b'; break;
	    case 'r':  ch = '\r'; break;
	    case 'f':  ch = '\f'; break;
	    case '\\': ch = '\\'; break;
	    case '\'': ch = '\''; break;
	    case '"':  ch = '"'; break;
	    default:   ch = *string; break;
	    }
	}
    *pChar = ch;
    return (nchars);
    }
/* lexeme scan routines */
#define EMPTY		-2
LOCAL int retractChar;
LOCAL int lastChar;
/*******************************************************************************
*
* lexInit - initialize lex scan routines
*/
LOCAL VOID lexInit ()
    {
    retractChar = EMPTY;
    }
/*******************************************************************************
*
* lexScan - scan input for next lexeme
*/
LOCAL int lexScan ()
    {
    FAST int ch;
    FAST int state;
    int nChars;
    int code;
    BOOL scanContinue;
    char string [MAX_SHELL_LINE + 1];
    do
	{
	/* get first character; use any retracted character first */
	if (retractChar != EMPTY)
	    {
	    ch = retractChar;
	    retractChar = EMPTY;
	    }
	else
	    ch = *(nextChar++);
	/* consume characters until final state reached */
	state = 0;
	for (nChars = 0; nChars < MAX_SHELL_LINE; nChars++)
	    {
	    /* consume character and make state transition */
	    string [nChars] = ch;
	    state = lexStateTable [state * lexNclasses + lexClass [ch + 1]];
	    /* if final state reached, quit; otherwise get next character */
	    if (state < 0)
		{
		nChars++;
		break;
		}
	    ch = *(nextChar++);
	    }
	/* final state reached */
	state = -state;
	string [nChars] = EOS;
	lastChar = ch;
	code = lexActions (state, string, nChars, &scanContinue);
	}
    while (scanContinue);
    return (code);
    }
/*******************************************************************************
*
* lexRetract - retract last character consumed
*/
LOCAL VOID lexRetract ()
    {
    retractChar = lastChar;
    }
int lexActions (state, string, nChars, pContinue)
    int state; char *string; int nChars; BOOL*pContinue;
    {
    *pContinue = FALSE;
    switch (state)
        {
        case 1:
            { RETRACT;	} break;
        case 2:
            { RETRACT;	return (string[0]); } break;
        case 3:
            { 		return (string[0]); } break;
        case 4:
            { 		lexError(string, "invalid number"); return(LEX_ERROR); } break;
        case 5:
            {		lexError(string, "invalid string"); return(LEX_ERROR); } break;
        case 6:
            {		lexError(string, "invalid char");   return(LEX_ERROR); } break;
        case 7:
            { RETRACT;	return (getNum (string, "%o", &yylval)); } break;
        case 8:
            { RETRACT;	return (getNum (&string[2], "%x", &yylval)); } break;
        case 9:
            { RETRACT;	return (getNum (&string[1], "%x", &yylval)); } break;
        case 10:
            { RETRACT;	return (getNum (string, "%d", &yylval)); } break;
        case 11:
            { RETRACT;	return (getFloat (string, &yylval)); } break;
        case 12:
            { RETRACT;	return (getId (string, &yylval)); } break;
        case 13:
            {		return (getString (string, nChars, &yylval)); } break;
        case 14:
            {		return (getChar (string, nChars, &yylval)); } break;
        case 15:
            {		return (OR); } break;
        case 16:
            {		return (AND); } break;
        case 17:
            {		return (EQ); } break;
        case 18:
            {		return (NE); } break;
        case 19:
            {		return (GE); } break;
        case 20:
            {		return (LE); } break;
        case 21:
            { RETRACT;	return (ROT_RIGHT); } break;
        case 22:
            { RETRACT;	return (ROT_LEFT); } break;
        case 23:
            {		return (PTR); } break;
        case 24:
            {		return (INCR); } break;
        case 25:
            {		return (DECR); } break;
        case 26:
            {		return (ADDA); } break;
        case 27:
            {		return (SUBA); } break;
        case 28:
            {		return (MULA); } break;
        case 29:
            {		return (DIVA); } break;
        case 30:
            {		return (MODA); } break;
        case 31:
            {		return (SHLA); } break;
        case 32:
            {		return (SHRA); } break;
        case 33:
            {		return (ANDA); } break;
        case 34:
            {		return (ORA); } break;
        case 35:
            {		return (XORA); } break;
        case 36:
            {		return (NL); } break;
        case 37:
            {		return (ENDFILE); } break;
        }
    *pContinue = TRUE;
    return (0);
    }

int lexNclasses = 27;

TINY lexClass [] =
    {
    26,
    25,  0,  0,  0, 26,  0,  0,  0,  0,  1, 25,  0,  0,  0,  0,  0, 
     0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 
     1, 16, 10,  0, 12, 23, 14, 11,  0,  0, 22, 20,  0, 19,  8, 21, 
     2,  3,  3,  3,  3,  3,  3,  3,  4,  4,  0,  0, 18, 15, 17,  0, 
     0,  5,  5,  5,  5,  5,  5,  7,  7,  7,  7,  7,  7,  7,  7,  7, 
     7,  7,  7,  7,  7,  7,  7,  7,  6,  7,  7,  0,  9,  0, 24,  7, 
     0,  5,  5,  5,  5,  5,  5,  7,  7,  7,  7,  7,  7,  7,  7,  7, 
     7,  7,  7,  7,  7,  7,  7,  7,  6,  7,  7,  0, 13,  0,  0,  0, 
    };

TINY lexStateTable [] =
    {
    -3, 1, 2, 8, 8,11,11,11, 9,-3,12,14, 6,19,20,21,22,23,24,25,26,16,27,28,29,-36,-37,
    -1, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -10,-10, 3, 3,-4,-4, 4,-4,10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,
    -7,-7, 3, 3,-4,-4,-4,-4,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,-7,
    -4,-4, 5, 5, 5, 5,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,
    -8,-8, 5, 5, 5, 5,-4,-4,-4,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,-8,
    -4,-4, 7, 7, 7, 7,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,-4,
    -9,-9, 7, 7, 7, 7,-4,-4,-4,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,
    -10,-10, 8, 8, 8,-4,-4,-4,10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,-10,
    -11,-11,10,10,10,-4,-4,-4,-4,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,
    -11,-11,10,10,10,-4,-4,-4,-4,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,-11,
    -12,-12,11,11,11,11,11,11,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,-12,
    12,12,12,12,12,12,12,12,12,13,-13,12,12,12,12,12,12,12,12,12,12,12,12,12,12,-5,-5,
    12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,-5,-5,
    14,14,14,14,14,14,14,14,14,15,14,-14,14,14,14,14,14,14,14,14,14,14,14,14,14,-6,-6,
    14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,-6,-6,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-29,-2,-2,-2,-2,-2,-2,17,-2,-2,-2,-2,
    17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,17,17,17,17,
    17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 0,17,17,17,17,17,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-15,-2,-34,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-16,-33,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-17,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-18,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-19,-2,30,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-20,-2,-2,31,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-27,-2,-23,-2,-25,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-26,-2,-2,-2,-2,-24,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-28,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-30,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-35,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
    -21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-32,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,-21,
    -22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-31,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,-22,
    };
