?? engine.c
字號(hào):
/* parser suite - and / or / nothing / something parsers parser = [token] -> ([token],status) implemented as sideeffecting on [token], returns status.*/# include "cc.h"/* for debugging: allow some error codes to be listed out by evaluate() * before terminating */# define MAXERRS 10/* can choose that the runtime stack be remade just in time every * time that it is needed. Uncomment next line if wanted. There * is a 20% slowdown.# define DYNAMIC_STACK_RESIZING */int p_evaluate ()/* * This is the interpreter. It runs the instruction block * starting at the (global) pc point with the evaluation stack pointer * at (global) value, and returns the address of the next block of code when * it exits. */{ static ACTION *a; static OPCODE n; static int nargs=0; /* counting args of an action */ static int nerrs=0; /* how many times we've blown it */ static PARAM args[MAXARGS]; /* local stack for action args *//* int pc; *//* use global program counter now *//* STACKVALUE *value; *//* & global stack pointer instead */ /* reset the evaluation stack */# ifdef DYNAMIC_STACK_RESIZING extern void mkstack(), freestack();/* precc_data.stacksize = 3*((int)(pstr-buffer)); */ if (stack == NULL) mkstack (); if (stack == NULL){ fprintf(stderr,"error: not enough memory (%d) for runtime stack\n", precc_data.stacksize); p_exit (1); }# endif value = &stack[0];loop: /* place a stop at the end of program space for safety if worried */ /* pcode(program[maxprogramsize-1])=EXIT; */#ifndef __MSDOS__ instr=program[pc++]; n=Opcode(instr); switch (n)#else /* do it quickly to avoid MSDOS bug */ switch (n = Opcode(instr=program[pc++]))#endif { case CNST: /* this is a literal */ /* there is no need to do this now! Actions don't read the attribute stack any more */ if (precc_data.stacktokens) pushvalue(Value(instr)); break; case NOP: /* treat it as a exit */ /* fallthrough*/ case EXIT: /* end of code block */# ifdef DYNAMIC_STACK_RESIZING freestack ();# endif return (pc); case INCR: /* increment stack pointer */ /* this instruction should never be generated any more */ /* value+=(int)Param(instr); */ break; case PARM: /* we want to try using our own local stack .. */ args[nargs++] = Param(instr); /* PARMs always come together before a FUNC. */ /* The rightmost arg is first to appear. */ break; case FUNC: /* we are using our own local arg stack: */# define ARG(N) (args[N])# define PREPARE(N) a = Action(instr); if (a) switch(nargs) { /* I ASSUME args are evaluated left to right */ case 16: PREPARE(16); (*a) (ARG(15),ARG(14),ARG(13),ARG(12), ARG(11),ARG(10),ARG(9),ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 15: PREPARE(15); (*a) (ARG(14),ARG(13),ARG(12), ARG(11),ARG(10),ARG(9),ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 14: PREPARE(14); (*a) (ARG(13),ARG(12), ARG(11),ARG(10),ARG(9),ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 13: PREPARE(13); (*a) (ARG(12), ARG(11),ARG(10),ARG(9),ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 12: PREPARE(12); (*a) (ARG(11),ARG(10),ARG(9),ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 11: PREPARE(11); (*a) (ARG(10),ARG(9),ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 10: PREPARE(10); (*a) (ARG(9),ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 9: PREPARE(9); (*a) (ARG(8), ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 8: PREPARE(8); (*a) (ARG(7),ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 7: PREPARE(7); (*a) (ARG(6),ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 6: PREPARE(6); (*a) (ARG(5),ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 5: PREPARE(5); (*a) (ARG(4), ARG(3),ARG(2),ARG(1),ARG(0)); break; case 4: PREPARE(4); (*a) (ARG(3),ARG(2),ARG(1),ARG(0)); break; case 3: PREPARE(3); (*a) (ARG(2),ARG(1),ARG(0)); break; case 2: PREPARE(2); (*a) (ARG(1),ARG(0)); break; case 1: PREPARE(1); (*a) (ARG(0)); break; case 0: PREPARE(0); (*a) (); break; default: fprintf(stderr, "error: too many args (%d) in action call\n", nargs); fprintf(stderr," : program counter: %d\n",pc); fprintf(stderr," : line number : %d\n",yylineno); p_exit(1); }# undef PREPARE# undef ARG nargs=0; /* used up all the args */ break; default: fprintf(stderr,"\"engine\" module reports a client has overwritten the\n"); fprintf(stderr,"program area it is interpreting. This foreign code will be\n"); fprintf(stderr,"skipped for now but other insertions may not be detected\n"); fprintf(stderr,"and could cause a program crash. The following may be\n"); fprintf(stderr,"useful for debugging purposes:\n\n"); fprintf(stderr,"error: illegal opcode (%d)\n",n); fprintf(stderr," : program counter(%d)\n",pc); fprintf(stderr," : line number (%d)\n",yylineno); if (nerrs++ < MAXERRS) break; /* allow a retry */ fprintf(stderr,"engine: Too many errors (%u)\n",MAXERRS); p_exit(1); return (pc); } goto loop;}void readerror(n)/* raise an error because the read buffer has overflowed */int n;{ fprintf(stderr, "\"engine\" module reports that the read buffer has overflowed.\n"); fprintf(stderr, "It is currently set at %d tokens and it has read %d tokens.\n", precc_data.readbuffersize, n); fprintf(stderr,"To prevent a reoccurrence, insert more cut marks (!) in the definition\n"); fprintf(stderr,"script or increase the READBUFFERSIZE macro definition.\n"); p_exit(1);}/* get1token() is the ONLY place I call yylex() - it is the * interface with the lexer and I am trying to give it most * rights over pstr and maxp too. */TOKEN get1token()/* Yylex() a token into the NEXT position for pstr if we are currently at pstr=maxp, and increment pstr. Otherwise just increment pstr and return the token we see. Also get the matching attribute into the lvbuff, increase maxp if needed. Return EOF for fail and the token otherwise. Note that pstr is always incremented by this call. */{ extern int yytchar; if (++pstr <= maxp) return *pstr; /* there was a read ahead token available */ if (yytchar==EOF) /* we got EOF before already */ return (TOKEN)EOF; /* a check that I never used to do, for speed, * but which seemed to be the cause of most bangs. */ if (pstr - buffer >= precc_data.readbuffersize) readerror(pstr - buffer); yybuffer=pstr; /* we give yylex its buffer */ *pstr = yylex(); /* we read yylex's return token */ /* just in case yylex forgot to tell us */ if (yytchar==EOF) return (TOKEN)EOF; /* we read yylex's stashed attribute */ lvbuff[(int)(pstr - buffer)] = yylval; maxp=pstr; /* we're only here because we had maxp < pstr */ return *pstr; /* everybody happy */}void realignbuffer()/* set pstr back to buffer so that the token we have just read now * seems to be in the first buffer position. */{ int n; /* the number of readahead tokens */ n = (int)(maxp - pstr); /* get the first token */ *buffer = *pstr; *lvbuff = lvbuff[(int)(pstr - buffer)]; /* now get the rest */ if (n>0) { memcpy(buffer+1,pstr+1,n*sizeof(TOKEN)); memcpy(lvbuff+1,lvbuff+(int)(pstr - buffer) + 1,n*sizeof(VALUE)); } pstr = buffer; maxp = pstr + n;}VOID p_runline (p)/* discharge actions and run parser p */PARSER *p;{ static STATUS tok; /* maxp = pstr = buffer; * - is now set by our caller */ pc = 0; /* program start address */ fptr = fstack+1; /* frame stack zeroed -- hooray ! */ tok = (*p) (); /* call the parser designated as entry point */ if (GOODSTATUS(tok)) { /* same as p_uniq0() */ pushEXIT; pc = 0; /* program start address */ pc = p_evaluate (); /* evaluate starts with (pc=0) */ pc=0; passcount++; /* if an error occurred, you might * want to look at program[pc-1] now */ if (*pstr) zer_error();/* incomplete parse */ } else bad_error() ; /* failed parse */}VOID p_run (p)/* Read lines from terminal, parse them, and if they are good according to p, execute the program that p built up. If the line is bad, re-echo it - thats the default error action, anyhow.*/PARSER *p;{ /* yylineno=0; - no longer set; inherit globals instead */ /* passcount=0; - no longer set; inherit globals instead */ p_entry = 0; /* the error parser */ while (1) switch(setjmp(jmpb)) /* longjmp here with 1 on error */ { case 0: /* normal continuation */ precc_begin (); /* user defined setup stuff */ if(!pstr) /* not set yet! It's the */ { /* first time through */ pstr = maxp = buffer; /* or - 1 ? */ *pstr = 0; /* establish canonical situation */ } /* else we got here with pstr set but *pstr = 0 because the * parse read everything successfully, including a final EOL, * so we have to skip the 0 and get another token. Then we * realign the buffer so that the new token is first. What a * good idea! */ if (*pstr == 0) /* increment pstr */ { if (get1token() == (TOKEN)EOF) { /* passed EOF */ precc_end (); return; } } /* But can we get here successfully with *pstr nonzero? and * if so what do we do with the token? That would be a ZER_ERROR * which would have invoked the error handler and jumped elsewhere. * * I think we just realign so that the token is first, which means * we are in danger of reparsing it, but the alternative is to * throw it away. To throw it away, remove the if(!*pstr) above. */ else /* debug trap - seems never to be sprung */ { pstr = pstr; } /* now we have a genuine token, make it first */ realignbuffer(); p_runline (p); break; default: /* error action */ /* we had an error, which means that there are probably read * ahead tokens to deal with. Now we are about to apply our * reserve parser to them. It had better be very forgiving * or we will be in trouble. */ /* should we pull a token to prevent same error again? * maybe, but why? It's the error parser's lookout. */ /* we realign the buffer because there will be no backtrack */ realignbuffer(); if (p_entry) p_runline (p_entry); /* I hope that ate everything OK, and it is time to behave * normally again. */ break; } /* go round the loop */}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -