home *** CD-ROM | disk | FTP | other *** search
- /* pars.c
-
- Parser and error recovery functions.
- This file should be run through lr1p to activate or suppress
- parser debugging features.
-
- */
-
-
- #include <stdio.h>
- #include <ctype.h>
- #include "decl.h"
-
- int cstate;
- int stack[STACKSIZE+1]; /* the state stack */
-
- int stackx= 0;
- semrectype *semstack[STACKSIZE+1];
- static char errsym[9]= "ErrSymAA";
-
- /* .................... */
- static void copy_stack(mstack, mstackx, mcstate,
- stack, stackx, cstate, jstx)
- int mstack[], mstackx, mcstate,
- stack[], *stackx, *cstate, jstx;
- {
- if ((jstx<0) || (jstx>mstackx)) abort_trap("ERROR RECOVERY BUG");
- memcpy((char *) stack, (char *) mstack, (jstx+1)*sizeof(int));
- *stackx = jstx;
- *cstate = (jstx == mstackx) ? mcstate : mstack[jstx+1];
- }
-
- /*......................*/
- static void err_pushread(cstate, stack, stackx)
- int cstate, stack[], *stackx;
- /* do the push part of a READSTATE. */
- {
- (*stackx)++;
- if (*stackx>STACKSIZE)
- abort_trap("stack overflow");
- stack[*stackx] = cstate;
- }
-
- /*...............*/
- static int trial_parse(cstate, stack, stackx)
- int *cstate, stack[], stackx;
- /* parses from current read state through the inserted and the
- error token; if successful, returns 1. */
- {
- int rx;
- int trial= 1;
-
- while (*cstate!=0) {
- #if DEBUG == 1
- stack[stackx+1]= *cstate;
- #endif
- if (*cstate < READSTATE) {
- /* a reduce state */
-
- #if DEBUG == 1
- if (debug_level > 3)
- stk_dump("E*Reduce", stack, stackx, debug_level);
- #endif
- if (popno[*cstate] == 0) {
- /* empty production */
- err_pushread(stk_state[statex[*cstate]], stack, &stackx);
- *cstate = stk_tostate[statex[*cstate]];
- }
- else {
- /* non-empty production */
- stackx = stackx - popno[*cstate] + 1;
- rx = statex[*cstate]; /* compute the GOTO state */
- *cstate = stack[stackx];
- while ((stk_state[rx]!=*cstate) &&
- (stk_state[rx]!=0)) rx++;
- *cstate = stk_tostate[rx];
- }
- }
- else if (*cstate < LOOKSTATE) {
- /* a read state */
- next_token(); /* need a token now */
- #if DEBUG == 1
- if (debug_level > 3)
- stk_dump("E*Read", stack, stackx, debug_level);
- #endif
- rx = statex[*cstate];
- while (toknum[rx] &&
- toknum[rx]!=token) rx++;
- if (toknum[rx]) {
- /* did read something */
- err_pushread(*cstate, stack, &stackx);
- *cstate = tostate[rx];
- tokenread(); /* scan the token */
- if (tokenx>1) return trial; /* successful */
- }
- else return 0; /* failure */
- }
- else {
- /* lookahead state */
- next_token(); /* need a token now */
- #if DEBUG == 1
- if (debug_level > 3)
- stk_dump("E*Look", stack, stackx, debug_level);
- #endif
- rx = statex[*cstate];
- while (toknum[rx] &&
- toknum[rx]!=token) rx++;
- *cstate = tostate[rx];
- }
- }
- return(trial);
- }
-
- /*.................*/
- static void incr_errsym()
- /* Note that this procedure assumes ASCII. */
- { int slen= strlen(errsym);
-
- if (errsym[slen-1] >= 'Z') {
- errsym[slen-2]++; /* incrementing a char */
- errsym[slen-1]= 'A';
- }
- else
- errsym[slen-1]++;
- }
-
- /*.................*/
- static semrectype *make_default(tokx)
- int tokx;
- /* creates a default token semantics data structure */
- { semrectype *tsemp;
-
- switch (tokx) {
- case IDENT_TOKX:
- tsemp= new_sem(IDENT, USER);
- tsemp->usem.symp = makesym(errsym, SYMERR);
- incr_errsym();
- break;
- case INT_TOKX:
- tsemp= new_sem(FIXED, INTVAR);
- tsemp->usem.numval = 1;
- break;
- case REAL_TOKX:
- tsemp= new_sem(FLOAT, REALVAR);
- tsemp->usem.rval = 1.0;
- break;
- case STR_TOKX:
- tsemp= new_sem(STRNG, STRVAR);
- tsemp->usem.strx = "ERROR";
- break;
- default:
- tsemp= new_sem(OTHER, SYMERR);
- break;
- } /* switch tokx */
- return tsemp;
- }
-
- /* .............. */
- static int error_recovery(mstack, mstackx, mcstate)
- int mstack[], *mstackx, mcstate;
- { int stack[STACKSIZE+1], /* local copy of stack */
- stackx, /* local stack pointer */
- cstate, /* local state */
- jstx, /* temporary stack limit */
- rx; /* index into TOKNUM table */
-
- #if DEBUG == 1
- if (debug_level > 3) printf("Going into ERROR RECOVERY\n");
- #endif
- while (1) {
- jstx = *mstackx;
- while (jstx>=0) {
- copy_stack(mstack, *mstackx, mcstate,
- stack, &stackx, &cstate, jstx);
- rx = statex[cstate];
- while (toknum[rx]) {
- /* scan through legal next tokens */
- #if DEBUG == 1
- if (debug_level > 3) printf("...starting trial parse\n");
- #endif
- tokary[0] = toknum[rx]; /* the insertion */
- tokenx = 0;
- if (trial_parse(&cstate, stack, stackx))
- goto got_it; /* it clicked! */
- rx++;
- if (toknum[rx])
- copy_stack(mstack, *mstackx, mcstate,
- stack, &stackx, &cstate, jstx);
- }
- jstx--; /* reduce stack */
- }
- if (token == STOP_TOKX) {
- /* empty stack, no more tokens */
- cstate = 0; /* halt state */
- tokenx = 2;
- jstx = 0; /* bottom of stack */
- goto finish;
- }
- tokenx = 2;
- next_token();
- }
- got_it: /* found a solution */
- copy_stack(mstack, *mstackx, mcstate,
- stack, &stackx, &cstate, jstx);
- lsempary[0]= make_default(tokary[0]);
- tokenx = 0; /* forces a `real' rescan of the insertion */
- if (jstx<*mstackx)
- cstate = stack[jstx+1];
- else
- cstate = mcstate; /* cstate returned */
- finish:
- *mstackx = jstx;
- #if DEBUG == 1
- if (debug_level > 3) printf("Ending error recovery\n");
- #endif
- return(cstate);
- }
-
- #define MSG2 ", expecting:"
- #define MSG1 "Found "
-
- /*.....................*/
- static void show_expecting(cstate)
- { int len, rx;
-
- printf(MSG1);
-
- if (token == IDENT_TOKX &&
- lsemp->usem.symp)
- printf("%s", lsemp->usem.symp->sym);
- else printf("%s", tokstring[token]);
-
- printf(MSG2);
- len= strlen(MSG2);
- rx=statex[cstate];
- while(toknum[rx] && len < 50) {
- printf(" %s", tokstring[toknum[rx]]);
- len += 1+ strlen(tokstring[toknum[rx]]);
- rx++;
- }
-
- if (toknum[rx]) printf("...\n");
- else printf("\n");
- }
-
- /*......................*/
- static void parse_pushread(cstate, semp)
- int cstate;
- semrectype *semp;
- /* do the push part of a READSTATE. */
- {
- stackx++;
- if (stackx>STACKSIZE)
- abort_trap("stack overflow");
- semstack[stackx] = semp;
- stack[stackx] = cstate;
- }
-
- /* .............. */
- void parser() /* Carries out a complete parse, until
- the halt state is seen -- same as empty stack */
- { int rx;
- semrectype *tsemp;
- void init_sem(), end_sem();
-
- init_sem();
- cstate = START_STATE;
- stackx = -1;
- tsemp=NULL;
- parse_pushread(ISTK_STATE, tsemp);
- while (cstate!=0) {
- #if DEBUG == 1
- stack[stackx+1]= cstate;
- #endif
- if (cstate < READSTATE) {
- /* a reduce state */
- #if DEBUG == 1
- if (debug_level > 0)
- stk_dump("Reduce", stack, stackx, debug_level);
- else if (prodtrap && set_member(cstate, prodtrap))
- stk_dump("Reduce", stack, stackx, 2);
- #endif
- tsemp= apply(cstate); /* the semantics action */
- if (popno[cstate]) {
- /* non-empty production:
- semantics is preserved on a unit production A --> w,
- where |w| = 1, unless something is in TSEMP. Note that
- if w is nonterminal, the production may be bypassed. */
- if (popno[cstate]==1) {
- if (tsemp) semstack[stackx]= tsemp;
- }
- else {
- stackx += 1-popno[cstate];
- semstack[stackx] = tsemp;
- }
- /* compute the GOTO state */
- rx = statex[cstate];
- cstate = stack[stackx];
- while (stk_state[rx]!=cstate && stk_state[rx]) rx++;
- cstate = stk_tostate[rx];
- }
- else { /* empty production */
- parse_pushread(stk_state[statex[cstate]], tsemp);
- cstate = stk_tostate[statex[cstate]];
- }
- }
- else if (cstate < LOOKSTATE) {
- /* a read state */
- next_token(); /* need next token now */
- #if DEBUG == 1
- if (debug_level > 2)
- stk_dump("Read", stack, stackx, debug_level);
- #endif
- rx = statex[cstate];
- while (toknum[rx] && toknum[rx]!=token) rx++;
- if (toknum[rx]) { /* found the token */
- parse_pushread(cstate, lsemp);
- cstate = tostate[rx];
- tokenread(); /* token has been scanned */
- }
- else {
- if (err_count<=0) {
- error("syntax error");
- show_expecting(cstate);
- err_count= 3; /* don't report errors for a few tokens */
- /* lex.c is supposed to decrement err_count if > 0, once
- for each token */
- }
- cstate = error_recovery(stack, &stackx, cstate);
- }
- }
- else {
- /* lookahead state */
- next_token(); /* need another token now */
- #if DEBUG == 1
- if (debug_level > 2)
- stk_dump("Look", stack, stackx, debug_level);
- #endif
- rx = statex[cstate];
- while (toknum[rx] && toknum[rx]!=token) rx++;
- cstate = tostate[rx];
- }
- }
- next_token();
- if (token != STOP_TOKX) {
- err_count= 0;
- error("No end-of-file seen with HALT state");
- }
- end_sem();
- }
-