static char * eat_string(int starting_line) { int c; char buffer[500]; char *ptr = buffer; for (;;) { /* * Get the next input character, handling EOF: */ c = input(); if (!c) { unput(c); report_parse_error("unterminated string found beginning", starting_line); return(0); } /* * Deal with special characters ('\\', '"', and '\n'): */ if (c=='\\') { c = eat_escape_code(); if (!c) continue; } else if (c == '"') { *ptr = 0; return(string_Copy(buffer)); } else if (c == '\n') { unput(c); /* fix line # reference to right line # */ report_parse_error("carriage return found in string", yylineno); return(0); } /* * Add the character c to the current string: */ *ptr = c; ptr++; /* * If out of buffer space, do a recursive call then * concatanate the result to the string read in so far to get the * entire string and return that: */ if (ptr>buffer+sizeof(buffer)-20) { string rest_of_string, result; rest_of_string = eat_string(starting_line); if (!rest_of_string) return(0); *ptr = 0; result = string_Concat(buffer, rest_of_string); free(rest_of_string); return(result); } } }
int regexpr(void) { int c; static char *buf = 0; static int bufsz = 500; char *bp; if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) FATAL("out of space for rex expr"); bp = buf; for ( ; (c = input()) != '/' && c != 0; ) { if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, 0)) FATAL("out of space for reg expr %.10s...", buf); if (c == '\n') { SYNTAX( "newline in regular expression %.10s...", buf ); unput('\n'); break; } else if (c == '\\') { *bp++ = '\\'; *bp++ = input(); } else { *bp++ = c; } } *bp = 0; if (c == 0) SYNTAX("non-terminated regular expression %.10s...", buf); yylval.s = tostring(buf); unput('/'); RET(REGEXPR); }
int gettok(char **pbuf, int *psz) /* get next input token */ { int c; char *buf = *pbuf; int sz = *psz; char *bp = buf; c = input(); if (c == 0) return 0; buf[0] = c; buf[1] = 0; if (!isalnum(c) && c != '.' && c != '_') return c; *bp++ = c; if (isalpha(c) || c == '_') { /* it's a varname */ for ( ; (c = input()) != 0; ) { if (bp-buf >= sz) if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) FATAL( "out of space for name %.10s...", buf ); if (isalnum(c) || c == '_') *bp++ = c; else { *bp = 0; unput(c); break; } } *bp = 0; } else { /* it's a number */ char *rem; /* read input until can't be a number */ for ( ; (c = input()) != 0; ) { if (bp-buf >= sz) if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) FATAL( "out of space for number %.10s...", buf ); if (isdigit(c) || c == 'e' || c == 'E' || c == '.' || c == '+' || c == '-') *bp++ = c; else { unput(c); break; } } *bp = 0; strtod(buf, &rem); /* parse the number */ unputstr(rem); /* put rest back for later */ rem[0] = 0; } *pbuf = buf; *psz = sz; return buf[0]; }
static char * eat_show_line(int test_for_endshow) { int c; int saw_escape_code = 0; int starting_line = yylineno; char buffer[200]; /* This must be large enough to hold "endshow" */ char *ptr = buffer; while (yylineno == starting_line) { c = input(); if (!c) { unput(c); *ptr = '\0'; return(string_Copy(buffer)); } else if (c == '\\') { saw_escape_code = 1; c = eat_escape_code(); if (!c) continue; } *ptr = c; ptr++; if ((ptr==buffer+strlen("endshow")) && test_for_endshow) if (!strncmp(buffer, "endshow", strlen("endshow")) && !saw_escape_code) { c = input(); unput(c); if (!is_identifier_char(c)) return(0); } if (ptr>buffer+sizeof(buffer)-2) { string the_line; string rest_of_line = eat_show_line(0); *ptr = '\0'; the_line = string_Concat(buffer, rest_of_line); free(rest_of_line); return(the_line); } } *ptr = '\0'; return(string_Copy(buffer)); }
getarg(char *p) /* pick up single argument, store in p, return length */ { int n, c, npar; n = npar = 0; for ( ;; ) { c = input9(); if (c == EOF) ERROR "end of file in getarg!" FATAL; if (npar == 0 && (c == ',' || c == ')')) break; if (c == '"') /* copy quoted stuff intact */ do { *p++ = c; n++; } while ((c = input9()) != '"' && c != EOF); else if (c == '(') npar++; else if (c == ')') npar--; n++; *p++ = c; } *p = 0; unput(c); return(n + 1); }
void getstr(char *s, int n) { register int c; register char *p; p = s; while ((c = input()) == ' ' || c == '\n') ; if (c == EOF) { *s = 0; return; } while (c != ' ' && c != '\t' && c != '\n' && c != '{' && c != '}' && c != '"' && c != '~' && c != '^') { if (!display && c == righteq) break; if (c == '(' && p > s) { /* might be defined(...) */ *p = '\0'; if (lookup(deftbl, s) != NULL) break; } if (c == '\\') if ((c = input()) != '"') *p++ = '\\'; *p++ = c; if (--n <= 0) ERROR "token %.20s... too long", s FATAL; c = input(); } unput(c); *p = '\0'; yylval = (int) s; }
void unputstr(const char *s) /* put a string back on input */ { int i; for (i = strlen(s)-1; i >= 0; i--) unput(s[i]); }
int main() { Pvoid_t PJArray = (Pvoid_t) NULL; PPosition_type pos = new_position(); PState_DFS state = new_state(); load_pjarray (&PJArray); for (int f = 0; f < LEN * LEN; ++f) { if (pos->taken[f] == N) { put (pos, state, f); if (_winning (pos, state, &PJArray)) { show (pos); } unput (pos, f); } } save_pjarray (PJArray); Word_t Rc_word; JLFA (Rc_word, PJArray); printf ( "put %lu ins %lu hit %lu Judy-bytes %lu\n" , _cnt_put, _cnt_ins, _cnt_hit, Rc_word ); release_position (pos); release_state (state); }
void unputString(const char* textp, size_t length) { // Add characters to input stream in back-to-front order const char* cp = textp; for (cp += length - 1; length--; cp--) { unput(*cp); } }
char * ifstat(double expr, char *thenpart, char *elsepart) { if (expr) { unput('\n'); pushsrc(Free, thenpart); pushsrc(pString, thenpart); unput('\n'); if (elsepart) free(elsepart); return thenpart; /* to be freed later */ } else { free(thenpart); if (elsepart) { unput('\n'); pushsrc(Free, elsepart); pushsrc(pString, elsepart); unput('\n'); } return elsepart; } }
/* Flex != lex #undef input #define input s_input #undef unput #define unput(c) s_unput(c) char s_input(void) { int c; if (g_buf_index <=0) c = getc(g_fd); else c = g_buf[--g_buf_index]; if (c==EOF) {return '~';} printf("%d :%c\n",c,c); return c; } */ int yywrap() { char c; return 1; c = input(); if (c == '~') return 1; else { unput(c); return 0; } }
char *ifstat(double expr, char *thenpart, char *elsepart) { dprintf("if %g then <%s> else <%s>\n", expr, thenpart, elsepart? elsepart : ""); if (expr) { unput('\n'); pushsrc(Free, thenpart); pushsrc(String, thenpart); unput('\n'); if (elsepart) free(elsepart); return thenpart; /* to be freed later */ } else { free(thenpart); if (elsepart) { unput('\n'); pushsrc(Free, elsepart); pushsrc(String, elsepart); unput('\n'); } return elsepart; } }
static char eat_escape_code(void) { int c, coded_char; c = input(); switch (c) { case 0: /* i.e., EOF */ unput(c); return(c); case '\n': return(0); case 'n': return('\n'); case 't': return('\t'); case 'b': return('\b'); case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': coded_char = c - '0'; c = input(); if (!is_octal_digit(c)) { unput(c); return(coded_char); } coded_char = coded_char*8 + c-'0'; c = input(); if (!is_octal_digit(c)) { unput(c); return(coded_char); } return(coded_char*8 + c-'0'); default: return(c); } }
void forloop(char *var, double from, double to, int op, double by, char *str) /* set up a for loop */ { dprintf("# for %s from %g to %g by %c %g \n", var, from, to, op, by); if (++forp >= forstk+10) ERROR "for loop nested too deep" FATAL; forp->var = var; forp->to = to; forp->op = op; forp->by = by; forp->str = str; setfval(var, from); nextfor(); unput('\n'); }
get_comment() { char c; int n; char txt[80]; n = 0; while( (c = input()) != '\n' ) { txt[n] = c; n++; } txt[n] = 0; if (displ_sw) printf("#%s\n",txt); unput('\n'); return(NUL_TKN); }
void forloop(char *var, double from, double to, int op, double by, char *str) { if (++forp >= forstk+10) fatal("for loop nested too deep"); /* note: actually we here want to take a vector variable and construct its */ /* values directly, then access them one at a time below; the current */ /* version is a temporary concession to old pic's version of the 'for' */ forp->sym = findvar(var, VARNAME); if (forp->sym->s_dim && forp->sym->s_val.a) free(forp->sym->s_val.a); forp->sym->s_dim = 0; forp->sym->s_val.f = from; forp->to = to; if (by == 0.) fatal("step size of 0 not allowed"); /* For additive or subtractive step, make sure step is positive. Otherwise, make sure step is greater than 1 in absolute value. */ if ((op == ' ' || op == '+') && by < 0.) { op = '-'; by = -by; } else if (op == '-' && by < 0.) { op = '+'; by = -by; } else if (op == '*' && fabs(by) < 1.) { op = '/'; by = 1 / by; } else if (op == '/' && fabs(by) < 1.) { op = '*'; by = 1 / by; } forp->op = op; forp->by = by; forp->str = str; nextfor(); unput('\n'); }
static uint8_t _winning (PPosition_type pos, PState_DFS state, Pvoid_t* PJArray) { if (pos->winner != N) { return 1; } Word_t const Index = encode (pos); { PWord_t PValue; JLG (PValue, *PJArray, Index); if (PValue) { ++_cnt_hit; return *PValue != pos->player; } } for (int f = 0; f < LEN * LEN; ++f) { if (pos->taken[f] == N) { put (pos, state, f); const uint8_t w = _winning (pos, state, PJArray); unput (pos, f); if (w) { insert (PJArray, Index, pos->player); return 0; } } } insert (PJArray, Index, 1 - pos->player); return 1; }
static int handle_show(void) { int c; int start_line_no = yylineno; /* * Eat up ' ' and '\t's after show. If the next character is a newline, * eat it. This is so we don't get an extra newline when we call * eat_til_endshow: */ while (c=input(), c==' ' || c=='\t') ; if (c!='\n') unput(c); yylval.text = eat_til_endshow(start_line_no); if (yylval.text) return(SHOW); else return(ERROR); }
void include(void) { char name[100]; FILE *fin; int c; extern int errno; while ((c = input()) == ' ') ; unput(c); cstr(name, c == '"', sizeof(name)); /* gets it quoted or not */ if ((fin = fopen(name, "r")) == NULL) ERROR "can't open file %s", name FATAL; errno = 0; curfile++; curfile->fin = fin; curfile->fname = strsave(name); curfile->lineno = 0; printf(".lf 1 %s\n", curfile->fname); pushsrc(File, curfile->fname); }
comment() { char c, c1; #ifdef AST printf("<COMMENT>"); #endif loop: while ((c = input()) != '*' && c != 0) #ifdef AST putchar(c) #endif ; if ((c1 = input()) != '/' && c != 0) { unput(c1); goto loop; } #ifdef AST printf("</COMMENT>\n"); #endif }
void comment() { char c, c1; output('/'); output('*'); loop: while ((c = input()) != '*' && c != 0) output(c); if ((c1 = input()) != '/' && c != 0) { unput(c1); goto loop; } if (c != 0) { output('*'); output(c1); } }
static char * eat_til_endshow(int start_line_no) { register int c; string text_so_far = string_Copy(""); string next_line; for (;;) { /* * Skip the spaces & tabs at the start of the current line: */ while ((c=input()), c==' ' || c=='\t') ; unput(c); /* * Handle unterminated shows: */ if (!c) { report_parse_error("unterminated show beginning", start_line_no); free(text_so_far); return(0); } /* * Read in rest of the line (including the <cr> at end), allowing * for escape codes and checking for "endshow{nonalpha}" at the * start of the line. (Note: \<newline> is considered the * end of a line here!) */ next_line = eat_show_line(1); if (!next_line) /* i.e., is this the endshow line? */ return(text_so_far); text_so_far = string_Concat2(text_so_far, next_line); free(next_line); } }
int string(void) { int c, n; char *s, *bp; static char *buf = 0; static int bufsz = 500; if (buf == 0 && (buf = (char *) malloc(bufsz)) == NULL) FATAL("out of space for strings"); for (bp = buf; (c = input()) != '"'; ) { if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, 0)) FATAL("out of space for string %.10s...", buf); switch (c) { case '\n': case '\r': case 0: SYNTAX( "non-terminated string %.10s...", buf ); lineno++; if (c == 0) /* hopeless */ FATAL( "giving up" ); break; case '\\': c = input(); switch (c) { case '"': *bp++ = '"'; break; case 'n': *bp++ = '\n'; break; case 't': *bp++ = '\t'; break; case 'f': *bp++ = '\f'; break; case 'r': *bp++ = '\r'; break; case 'b': *bp++ = '\b'; break; case 'v': *bp++ = '\v'; break; case 'a': *bp++ = '\007'; break; case '\\': *bp++ = '\\'; break; case '0': case '1': case '2': /* octal: \d \dd \ddd */ case '3': case '4': case '5': case '6': case '7': n = c - '0'; if ((c = peek()) >= '0' && c < '8') { n = 8 * n + input() - '0'; if ((c = peek()) >= '0' && c < '8') n = 8 * n + input() - '0'; } *bp++ = n; break; case 'x': /* hex \x0-9a-fA-F + */ { char xbuf[100], *px; for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) { if (isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) *px++ = c; else break; } *px = 0; unput(c); sscanf(xbuf, "%x", &n); *bp++ = n; break; } default: *bp++ = c; break; } break; default: *bp++ = c; break; } } *bp = 0; s = tostring(buf); *bp++ = ' '; *bp++ = 0; yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab); RET(STRING); }
int yylex(void) { int c; static char *buf = 0; static int bufsize = 500; if (buf == 0 && (buf = (char *) malloc(bufsize)) == NULL) FATAL( "out of space in yylex" ); if (sc) { sc = 0; RET('}'); } if (reg) { reg = 0; return regexpr(); } /* printf("top\n"); */ for (;;) { c = gettok(&buf, &bufsize); /* printf("gettok [%s]\n", buf); */ if (c == 0) return 0; if (isalpha(c) || c == '_') return word(buf); if (isdigit(c)) { yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab); /* should this also have STR set? */ RET(NUMBER); } yylval.i = c; switch (c) { case '\n': /* {EOL} */ RET(NL); case '\r': /* assume \n is coming */ case ' ': /* {WS}+ */ case '\t': break; case '#': /* #.* strip comments */ while ((c = input()) != '\n' && c != 0) ; unput(c); break; case ';': RET(';'); case '\\': if (peek() == '\n') { input(); } else if (peek() == '\r') { input(); input(); /* \n */ lineno++; } else { RET(c); } break; case '&': if (peek() == '&') { input(); RET(AND); } else RET('&'); case '|': if (peek() == '|') { input(); RET(BOR); } else RET('|'); case '!': if (peek() == '=') { input(); yylval.i = NE; RET(NE); } else if (peek() == '~') { input(); yylval.i = NOTMATCH; RET(MATCHOP); } else RET(NOT); case '~': yylval.i = MATCH; RET(MATCHOP); case '<': if (peek() == '=') { input(); yylval.i = LE; RET(LE); } else { yylval.i = LT; RET(LT); } case '=': if (peek() == '=') { input(); yylval.i = EQ; RET(EQ); } else { yylval.i = ASSIGN; RET(ASGNOP); } case '>': if (peek() == '=') { input(); yylval.i = GE; RET(GE); } else if (peek() == '>') { input(); yylval.i = APPEND; RET(APPEND); } else { yylval.i = GT; RET(GT); } case '+': if (peek() == '+') { input(); yylval.i = INCR; RET(INCR); } else if (peek() == '=') { input(); yylval.i = ADDEQ; RET(ASGNOP); } else RET('+'); case '-': if (peek() == '-') { input(); yylval.i = DECR; RET(DECR); } else if (peek() == '=') { input(); yylval.i = SUBEQ; RET(ASGNOP); } else RET('-'); case '*': if (peek() == '=') { /* *= */ input(); yylval.i = MULTEQ; RET(ASGNOP); } else if (peek() == '*') { /* ** or **= */ input(); /* eat 2nd * */ if (peek() == '=') { input(); yylval.i = POWEQ; RET(ASGNOP); } else { RET(POWER); } } else RET('*'); case '/': RET('/'); case '%': if (peek() == '=') { input(); yylval.i = MODEQ; RET(ASGNOP); } else RET('%'); case '^': if (peek() == '=') { input(); yylval.i = POWEQ; RET(ASGNOP); } else RET(POWER); case '$': /* BUG: awkward, if not wrong */ c = gettok(&buf, &bufsize); if (isalpha(c)) { if (strcmp(buf, "NF") == 0) { /* very special */ unputstr("(NF)"); RET(INDIRECT); } c = peek(); if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) { unputstr(buf); RET(INDIRECT); } yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab); RET(IVAR); } else if (c == 0) { /* */ SYNTAX( "unexpected end of input after $" ); RET(';'); } else { unputstr(buf); RET(INDIRECT); } case '}': if (--bracecnt < 0) SYNTAX( "extra }" ); sc = 1; RET(';'); case ']': if (--brackcnt < 0) SYNTAX( "extra ]" ); RET(']'); case ')': if (--parencnt < 0) SYNTAX( "extra )" ); RET(')'); case '{': bracecnt++; RET('{'); case '[': brackcnt++; RET('['); case '(': parencnt++; RET('('); case '"': return string(); /* BUG: should be like tran.c ? */ default: RET(c); } } }
int gettok(char **pbuf, int *psz) /* get next input token */ { int c, retc; char *buf = *pbuf; int sz = *psz; char *bp = buf; c = input(); if (c == 0) return 0; buf[0] = c; buf[1] = 0; if (!isalnum(c) && c != '.' && c != '_') return c; *bp++ = c; if (isalpha(c) || c == '_') { /* it's a varname */ for ( ; (c = input()) != 0; ) { if (bp-buf >= sz) if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) FATAL( "out of space for name %.10s...", buf ); if (isalnum(c) || c == '_') *bp++ = c; else { *bp = 0; unput(c); break; } } *bp = 0; retc = 'a'; /* alphanumeric */ } else { /* maybe it's a number, but could be . */ char *rem; /* read input until can't be a number */ for ( ; (c = input()) != 0; ) { if (bp-buf >= sz) if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, 0)) FATAL( "out of space for number %.10s...", buf ); if (isdigit(c) || c == 'e' || c == 'E' || c == '.' || c == '+' || c == '-') *bp++ = c; else { unput(c); break; } } *bp = 0; strtod(buf, &rem); /* parse the number */ if (rem == buf) { /* it wasn't a valid number at all */ buf[1] = 0; /* return one character as token */ retc = buf[0]; /* character is its own type */ unputstr(rem+1); /* put rest back for later */ } else { /* some prefix was a number */ unputstr(rem); /* put rest back for later */ rem[0] = 0; /* truncate buf after number part */ retc = '0'; /* type is number */ } } *pbuf = buf; *psz = sz; return retc; }
int peek(void) { int c = input(); unput(c); return c; }
yylook() { register struct yysvf *yystate, **lsp; register struct yywork *yyt; struct yysvf *yyz; int yych; struct yywork *yyr; /* # ifdef LEXDEBUG int debug; # endif */ char *yylastch; /* start off machines */ /* # ifdef LEXDEBUG debug = 1; # else debug = 0; # endif */ # ifdef LEXDEBUG #define debug 1 # else #define debug 0 #endif #ifdef YYDEBUG fprintf(yyout,"yylook()\n"); # endif if (!yymorfg) yylastch = yytext; else { yymorfg=0; yylastch = yytext+yyleng; } #ifdef YYDEBUG fprintf(yyout,"yylook: yymorfg=%d\n",yymorfg); # endif for(;;) { #ifdef YYDEBUG fprintf(yyout,"yylook: (outer loop)"); printchar("yyprevious",yyprevious); # endif lsp = yylstate; yyestate = yystate = yybgin; if (yyprevious==YYNEWLINE) yystate++; testbreak=0; for (;;) { # ifdef LEXDEBUG fprintf(yyout,"yylook: (inner loop) state %d\n",yystate-yysvec-1); # endif if(testbreak==5) { fprintf(yyout,"yylook: error, aborted after 5 loops\n"); exit(0); } testbreak++; yyt = yystate->yystoff; /* fprintf(yyout,"yylook: yyt offs: %02x\n",yyt-yycrank); */ if(yyt == yycrank) { /* may not be any transitions */ yyz = yystate->yyother; if(yyz == 0)break; if(yyz->yystoff == yycrank)break; } *yylastch++ = yych = input(); # ifdef LEXDEBUG fprintf(yyout,"yylook: input "); printchar("yych",yych); # endif tryagain: # ifdef LEXDEBUG /* fprintf(yyout,"yylook: yych=%02x yymatch[yych]=%02x\n",yych,yymatch[yych]); */ fprintf(yyout,"yylook: tryagain\n"); # endif yyr = yyt; /* fprintf(yyout,"yylook: yyr offs: %02x\n",yyr-yycrank); */ if ( yyt > yycrank) { yyt = yyr + yych; if (yyt <= yytop && yyt->verify+yysvec == yystate) { if(yyt->advance+yysvec == YYLERR) /* error transitions */ { # ifdef LEXDEBUG fprintf(yyout,"yylook: unput (1) "); printchar("*yylastch",*yylastch); # endif unput(*--yylastch); break; } *lsp++ = yystate = yyt->advance+yysvec; # ifdef LEXDEBUG fprintf(yyout,"yylook: continue (1)\n"); # endif goto contin; } # ifdef LEXDEBUG fprintf(yyout,"yylook: ( yyt > yycrank)\n"); # endif } # ifdef YYOPTIM else if(yyt < yycrank) /* r < yycrank */ { yyt = yyr = yycrank+(yycrank-yyt); # ifdef LEXDEBUG fprintf(yyout,"yylook: compressed state\n"); # endif yyt = yyt + yych; if(yyt <= yytop && yyt->verify+yysvec == yystate) { # ifdef LEXDEBUG fprintf(yyout,"yylook: (1)\n"); # endif if(yyt->advance+yysvec == YYLERR) /* error transitions */ { # ifdef LEXDEBUG fprintf(yyout,"yylook: unput (2) "); printchar("*yylastch",*yylastch); # endif unput(*--yylastch); break; } *lsp++ = yystate = yyt->advance+yysvec; # ifdef LEXDEBUG fprintf(yyout,"yylook: continue (2)\n"); # endif goto contin; } # ifdef LEXDEBUG /* fprintf(yyout,"yylook: yych=%02x yymatch[yych]=%02x\n",yych,yymatch[yych]); fprintf(yyout,"yylook: yyt offs: %02x\n",yyt-yycrank); fprintf(yyout,"yylook: yyr offs: %02x\n",yyr-yycrank); */ # endif yyt = yyr + YYU(yymatch[yych]); # ifdef LEXDEBUG /* fprintf(yyout,"yylook: yyt offs: %02x <= yytop offs: %02x\n",yyt-yycrank,yytop-yycrank); fprintf(yyout,"yylook: yyt->verify=%04x yysvec=%04x (yyt->verify+yysvec)=%04x == yystate=%04x\n",yyt->verify,yysvec,(yyt->verify+yysvec),yystate); */ fprintf(yyout,"yylook: try fall back character\n"); # endif if(yyt <= yytop && yyt->verify+yysvec == yystate) { # ifdef LEXDEBUG fprintf(yyout,"yylook: (2a)\n"); # endif if(yyt->advance+yysvec == YYLERR) /* error transition */ { # ifdef LEXDEBUG /* cc65 compiles this ?! fprintf(yyout,"yylook: unput (3) ",); */ fprintf(yyout,"yylook: unput (3) "); printchar("*yylastch",*yylastch); # endif unput(*--yylastch); break; } *lsp++ = yystate = yyt->advance+yysvec; # ifdef LEXDEBUG /* fprintf(yyout,"yylook: yyt offs: %02x yyt->advance=%d\n",yyt-yycrank,yyt->advance); */ fprintf(yyout,"yylook: continue (3)\n"); # endif goto contin; } # ifdef LEXDEBUG fprintf(yyout,"yylook: (2)\n"); # endif } if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank) { # ifdef LEXDEBUG fprintf(yyout,"yylook: fall back to state %d\n",yystate-yysvec-1); # endif goto tryagain; } # endif else { # ifdef LEXDEBUG fprintf(yyout,"yylook: unput (4) "); printchar("*yylastch",*yylastch); # endif unput(*--yylastch); break; } contin: # ifdef LEXDEBUG fprintf(yyout,"yylook: contin state=%d\n",yystate-yysvec-1); # endif ; } # ifdef LEXDEBUG if((*(lsp-1)-yysvec-1)<0) { fprintf(yyout,"yylook: stopped (end)\n"); } else { fprintf(yyout,"yylook: stopped at %d with\n",*(lsp-1)-yysvec-1); } # endif while (lsp-- > yylstate) { *yylastch-- = 0; if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0) { yyolsp = lsp; if(yyextra[*yyfnd]) /* must backup */ { while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate) { lsp--; # ifdef LEXDEBUG fprintf(yyout,"yylook: unput (5) "); printchar("*yylastch",*yylastch); # endif unput(*yylastch--); } } yyprevious = YYU(*yylastch); yylsp = lsp; yyleng = yylastch-yytext+1; yytext[yyleng] = 0; # ifdef LEXDEBUG fprintf(yyout,"\nyylook: match action %d\n",*yyfnd); fprintf(yyout,"yylook: done loops: %d\n",testbreak); # endif return(*yyfnd++); } unput(*yylastch); } if (yytext[0] == 0 /* && feof(yyin) */) { yysptr=yysbuf; # ifdef LEXDEBUG fprintf(yyout,"yylook: done loops: %d\n",testbreak); # endif return(0); } yyprevious = yytext[0] = input(); # ifdef LEXDEBUG fprintf(yyout,"yylook: input "); printchar("yyprevious",yyprevious); # endif if (yyprevious>0) output(yyprevious); yylastch=yytext; # ifdef LEXDEBUG /* if(debug)putchar('\n'); */ # endif } # ifdef LEXDEBUG fprintf(yyout,"yylook: done loops: %d\n",testbreak); fprintf(yyout,"yylook: return <void>\n"); # endif }
int yylex(void) { register int c, last_char; register char *ptr; int start_line_no; int_dictionary_binding *binding; char varname[MAX_IDENTIFIER_LENGTH+1]; for (;;) { switch (c = input()) { /* * Skip whitespace: */ case ' ': case '\t': case '\n': continue; /* * '#' comments out everything up to the and including * the next <cr>: */ case '#': while ( (c=input()) && (c!='\n') ) ; if (!c) unput(c); continue; /* * Handle c-style comments. Note that "/[^*]" is not the start * of any valid token. */ case '/': start_line_no = yylineno; /* verify that next character is a '*': */ if ((c=input()) != '*') return(ERROR); /* Scan until "*\/" or <EOF>: */ for (last_char=0; ; last_char=c) { c = input(); if (c == '/' && (last_char=='*')) break; if (!c) { unput(c); report_parse_error("unterminated c style comment found beginning", start_line_no); return(ERROR); } } continue; /* * The following characters lex as themselves: * '+', '|', '&', '(', ')', '.', ',' and <EOF>: */ case 0: case '+': case '|': case '&': case '(': case ')': case '.': case ',': return(c); /* * Handle "=[^~=]", "=~", and "==": */ case '=': switch (c = input()) { case '~': return(REGEQ); case '=': return(EQ); default: unput(c); return('='); } /* * Handle "![^~=]", "!~", and "!=": */ case '!': switch (c = input()) { case '~': return(REGNEQ); case '=': return(NEQ); default: unput(c); return('!'); } /* * Handle identifiers and keywords: * * Note that the below set of characters is hard coded from * is_identifier_char from parser.h. */ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '_': /* * Read in the first MAX_IDENTIFIER_LENGTH characters of the * identifier into varname null terminated. Eat * the rest of the characters of the identifier: */ for (ptr = varname;;) { if (ptr<varname+MAX_IDENTIFIER_LENGTH) *(ptr++) = c; c = input(); if (!is_identifier_char(c)) break; } unput(c); *ptr = '\0'; /* * Look up the identifier in the keyword dictionary. * If its a match, return the keyword's #. In the case * of show, call handle_show to do more processing. * If not a match, treat as a variable name. */ binding = int_dictionary_Lookup(keyword_dict, varname); if (!binding) { yylval.text = string_Copy(varname); return(VARNAME); } if (binding->value == SHOW) return(handle_show()); else return(binding->value); /* * Handle "${identifier}". Note that $ followed by a * non-identifier character is not the start of any valid token. */ case '$': c = input(); if (!is_identifier_char(c)) return(ERROR); /* * Read in the first MAX_IDENTIFIER_LENGTH characters of the * identifier into varname null terminated. Eat * the rest of the characters of the identifier: */ for (ptr = varname;;) { if (ptr<varname+MAX_IDENTIFIER_LENGTH) *(ptr++) = c; c = input(); if (!is_identifier_char(c)) break; } unput(c); *ptr = '\0'; yylval.text = string_Copy(varname); return(VARREF); /* * Handle constant strings: */ case '"': yylval.text = eat_string(yylineno); if (yylval.text) return(STRING); else return(ERROR); /* * All other characters do not start valid tokens: */ default: return(ERROR); } } }
yylook() #endif { register struct yysvf *yystate, **lsp; register struct yywork *yyt; struct yysvf *yyz; int yych, yyfirst; struct yywork *yyr; # ifdef LEXDEBUG int debug; # endif char *yylastch; /* start off machines */ # ifdef LEXDEBUG debug = 0; # endif yyfirst=1; if (!yymorfg) yylastch = yytext; else { yymorfg=0; yylastch = yytext+yyleng; } for(;;){ lsp = yylstate; yyestate = yystate = yybgin; if (yyprevious==YYNEWLINE) yystate++; for (;;){ # ifdef LEXDEBUG if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1); # endif yyt = yystate->yystoff; if(yyt == yycrank && !yyfirst){ /* may not be any transitions */ yyz = yystate->yyother; if(yyz == 0)break; if(yyz->yystoff == yycrank)break; } #ifndef __cplusplus *yylastch++ = yych = input(); #else *yylastch++ = yych = lex_input(); #endif if(yylastch > &yytext[YYLMAX]) { fprintf(yyout,"Input string too long, limit %d\n",YYLMAX); exit(1); } yyfirst=0; tryagain: # ifdef LEXDEBUG if(debug){ fprintf(yyout,"char "); allprint(yych); putchar('\n'); } # endif yyr = yyt; if ( (int)yyt > (int)yycrank){ yyt = yyr + yych; if (yyt <= yytop && yyt->verify+yysvec == yystate){ if(yyt->advance+yysvec == YYLERR) /* error transitions */ {unput(*--yylastch);break;} *lsp++ = yystate = yyt->advance+yysvec; if(lsp > &yylstate[YYLMAX]) { fprintf(yyout,"Input string too long, limit %d\n",YYLMAX); exit(1); } goto contin; } } # ifdef YYOPTIM else if((int)yyt < (int)yycrank) { /* r < yycrank */ yyt = yyr = yycrank+(yycrank-yyt); # ifdef LEXDEBUG if(debug)fprintf(yyout,"compressed state\n"); # endif yyt = yyt + yych; if(yyt <= yytop && yyt->verify+yysvec == yystate){ if(yyt->advance+yysvec == YYLERR) /* error transitions */ {unput(*--yylastch);break;} *lsp++ = yystate = yyt->advance+yysvec; if(lsp > &yylstate[YYLMAX]) { fprintf(yyout,"Input string too long, limit %d\n",YYLMAX); exit(1); } goto contin; } yyt = yyr + YYU(yymatch[yych]); # ifdef LEXDEBUG if(debug){ fprintf(yyout,"try fall back character "); allprint(YYU(yymatch[yych])); putchar('\n'); } # endif if(yyt <= yytop && yyt->verify+yysvec == yystate){ if(yyt->advance+yysvec == YYLERR) /* error transition */ {unput(*--yylastch);break;} *lsp++ = yystate = yyt->advance+yysvec; if(lsp > &yylstate[YYLMAX]) { fprintf(yyout,"Input string too long, limit %d\n",YYLMAX); exit(1); } goto contin; } } if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){ # ifdef LEXDEBUG if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1); # endif goto tryagain; } # endif else {unput(*--yylastch);break;} contin: # ifdef LEXDEBUG if(debug){ fprintf(yyout,"state %d char ",yystate-yysvec-1); allprint(yych); putchar('\n'); } # endif ; } # ifdef LEXDEBUG if(debug){ fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1); allprint(yych); putchar('\n'); } # endif while (lsp-- > yylstate){ *yylastch-- = 0; if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){ yyolsp = lsp; if(yyextra[*yyfnd]){ /* must backup */ while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){ lsp--; unput(*yylastch--); } } yyprevious = YYU(*yylastch); yylsp = lsp; yyleng = yylastch-yytext+1; yytext[yyleng] = 0; # ifdef LEXDEBUG if(debug){ fprintf(yyout,"\nmatch "); sprint(yytext); fprintf(yyout," action %d\n",*yyfnd); } # endif return(*yyfnd++); } unput(*yylastch); } if (yytext[0] == 0 /* && feof(yyin) */) { yysptr=yysbuf; return(0); } #ifndef __cplusplus yyprevious = yytext[0] = input(); if (yyprevious>0) output(yyprevious); #else yyprevious = yytext[0] = lex_input(); if (yyprevious>0) lex_output(yyprevious); #endif yylastch=yytext; # ifdef LEXDEBUG if(debug)putchar('\n'); # endif } }
/* LEXICON -- Simple "conversational mode" lexical analyser. Lexical analysis * in the CL is carried out by a dual mode lexical analyser. In conversational * mode there are few tokens and few special characters; arguments are * delimited by whitespace and may contain nonalphanumeric characters. Few * strings have to be quoted. In computational mode the arithmetic operators * are recognized and arguments must be delimited by commas. Computational * mode is in effect whenever the parenlevel is nonzero. * * The two modes are implemented with two separate lexical analyzers. Gettok * implements conversational mode, while computational mode is implemented with * a LEX finite state automaton. Gettok recognizes the following special chars: * * [ \t] argument delimiter * ["'] string * \n newline * \ single character escape * ! os escape * # comment * & spawn background job * ( lparen * + plus (switch) * - minus (switch) * ; eost * = equals * += add and set * -= subtract and set * *= multiply and set * /= divide and set * < redirin * > redir * >& allredir * >> append * >>& allappend * >(G|I|P|)+ graphics stream redirection * { lbrace * | pipe * |& allpipe * } rbrace * [ beginning of index list * ] end of index list * * The history metacharacter ^ is processed before input is passed to the * lexical analyser. Any sequence of nonwhite characters that does not form * one of the recognized tokens is returned as a string. */ int lexicon (void) { char *bkgerr = "ERROR: cannot submit background job inside {}\n"; register int ch, cch; register int token; int stringtok, identifier, setlevel; int clswitch; char *op, *index(); /* Return pushed back token if any. */ if (pbtoken) { token = pbtoken; pbtoken = 0; return (token); } /* Skip leading whitespace. If whitespace is seen and we are in an * argument list (according to the parser) set flag to output the * comma argument delimiter if the next token begins an argument. * If whitespace or = is seen (except whitespace at the beginning of * a command) then set LHS to false, turning [] off as conversational * mode metacharacters (they will be automatically turned on when * compute mode is entered in an expression). */ while (ch = input()) if (ch == ' ' || ch == '\t') { space: if (lexcol > 0) lhs = 0; if (inarglist) newarg++; } else if (ch == '\\') { if ((ch = input()) != '\n') { unput (ch); break; } else goto space; } else break; /* Start new token. */ if (ch) { unput (ch); yyleng = 0; if (!inarglist) newarg = 0; } else return (0); /* Identify and accumulate next token. Simple tokens are returned as * integer constants, more complex tokens as operand structures in * yylval. */ while (ch = input()) { lexcol++; switch (ch) { case '&': /* An ampersand triggers bkg execution in command mode, unless * it occurs in a token such as >& or >>&, in which case we * never get here. */ if (!newtoken) { unput (ch); goto tokout_; } else { while (ch = input()) { if (ch == ' ' || ch == '\t') continue; else { char bkgmsg[SZ_LINE+1]; int n = SZ_LINE; op = bkgmsg; unput (ch); if (bracelevel) { eprintf (bkgerr); return ('#'); } while (--n >= 0 && (*op = input()) != '\n') op++; *op = EOS; bkg_init (bkgmsg); return (Y_NEWLINE); } } return (0); } case ';': case '\n': lexcol = 0; lhs = 1; goto etok_; case '\t': case ' ': if (lexcol > 0) lhs = 0; goto etok_; case '[': case ']': /* [] are recognized as command mode metacharacters only * on the left hand side of an assignment statement. */ if (!lhs) goto deposit_; /* Fall through */ case '{': case '}': /* We want to distinguish here between the use of {} for * the set selection operator in template strings, and the * conventional compound statement operator. The distinction * is that { is recognized as a token only if occurs at the * beginning of a token, and } is recognized as a separate * token when inside a token only if it matches a { in the * same token. Hence, alpha{xxx} is a single token in command * mode, whereas {xxx} is 3 tokens, the same as { xxx }, * and xxx} is the same as xxx }. Usage is completely * unambiguous if the { or } is preceded by a space. */ if (newtoken) return (ch); if (stringtok) { if (ch == '{') setlevel++; else if (setlevel == 0) goto etok_; /* } does not match { */ else --setlevel; goto deposit_; } /* fall through */ case '=': etok_: if (!newtoken) { unput (ch); goto tokout_; } else if (ch == '\n') { return (Y_NEWLINE); } else if (ch == '=') { token = ch; lhs = 0; goto eatwhite_; } else return (ch); case '?': /* ?, ?? menu commands, recognized only at beginning of stmt */ if (lexcol > 1) { goto deposit_; } else if (ch = input()) { if (ch == '?') return (crackident ("??")); else { unput (ch); return (crackident ("?")); } } else return (0); case '+': case '-': /* Plus and minus are recognized as the switch operators for * boolean parameters only if encountered while accumulating * a token and if followed by an argument delimiter, i.e., * space, tab, newline, or semicolon. If found at the beginning * of a token they are returned as a separate token and will be * interpreted by the parser as unary plus or minus. */ if (newtoken) { if (newarg) { cch = input(); if (cch == 0) return (0); unput (cch); if (ch == '-' && isdigit (cch)) { unput (ch); newarg = 0; return (','); } else { /* Not number; treat +- as a string char. */ goto deposit_; } } else { cch = input(); if (cch == 0) return (0); if (cch == '=') { if (ch == '+') return (YOP_AOADD); else return (YOP_AOSUB); } else if (isdigit (cch)) { unput (cch); return (ch); } else { unput (cch); goto deposit_; } } } else if (cch = input()) { clswitch = (isspace (cch) || cch == ';'); if (cch == '=') { unput(cch); unput (ch); goto tokout_; } unput (cch); if (clswitch) { pbtoken = ch; goto tokout_; } else goto deposit_; } else return (0); case '"': case '\'': if (!newtoken) { unput (ch); goto tokout_; } else if (newarg) { unput (ch); newarg = 0; return (','); } else { traverse (ch); yylval = addconst (yytext, OT_STRING); return (Y_CONSTANT); } case '\\': if (ch = input()) { if (ch == '\n') continue; else if (index ("&;=+-\"'\\#><()|", ch) != NULL) goto deposit_; /* put ch in string */ else goto escape_; /* put \ch in string */ } else return (0); case '!': /* OS escape is only recognized when the ! occurs as the first * token in a statement. */ if (lexcol > 1) goto deposit_; /* Accumulate command. Newline may be escaped to enter a long * command, but all other escapes are passed on unmodified. */ while ((ch = input()) && ch != '\n') { if (ch == '\\') if (ch = input()) { if (ch == '\n') continue; else yytext[yyleng++] = '\\'; } else break; yytext[yyleng++] = ch; } if (ch) unput (ch); yytext[yyleng] = '\0'; yylval = addconst (yytext, OT_STRING); return (Y_OSESC); case '#': /* Discard the comment line. */ while ((ch = input()) && ch != '\n') ; if (ch) { unput (ch); continue; } else return (0); case '>': case '<': case '(': /* These characters are alike in that they all begin a new * argument when found in an argument list. */ if (!newtoken) { unput (ch); goto tokout_; } else if (newarg) { unput (ch); newarg = 0; return (','); } else if (ch == '<') { token = ch; goto eatwhite_; } else if (ch == '>') { ch = input(); if (ch == 0) { return ('>'); } else if (ch == '>') { ch = input(); if (ch == 0) { return (Y_APPEND); } else if (ch == 'G' || ch == 'I' || ch == 'P') { op = yytext; *op++ = '>'; *op++ = '>'; *op++ = ch; goto gsredir_; } else if (ch == '&') { token = Y_ALLAPPEND; goto eatwhite_; } else { unput (ch); token = Y_APPEND; goto eatwhite_; } } else if (ch == 'G' || ch == 'I' || ch == 'P') { /* Graphics stream redirection. */ op = yytext; *op++ = '>'; *op++ = ch; gsredir_: ch = input(); while (ch == 'G' || ch == 'I' || ch == 'P') { *op++ = ch; ch = input(); } unput (ch); *op = EOS; yylval = addconst (yytext, OT_STRING); token = Y_GSREDIR; goto eatwhite_; } else if (ch == '&') { token = Y_ALLREDIR; goto eatwhite_; } else { unput (ch); token = '>'; goto eatwhite_; } } else return ('('); case '|': if (!newtoken) { unput (ch); goto tokout_; } else if (ch = input()) { if (ch == '&') return (Y_ALLPIPE); else { unput (ch); return ('|'); } } else return (0); case '*': case '/': cch = input(); if (cch == 0) return (0); if (newtoken) { if (cch == '=') return ((ch=='*') ? YOP_AOMUL:YOP_AODIV); else { unput (cch); goto deposit_; } } else { if (cch == '=') { unput (cch); unput (ch); goto tokout_; } else { unput (cch); goto deposit_; } } /* The following cases are included to force the compiler * to compile the case as an ASCII jump table. */ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': /* fall through to default */ default: goto deposit_; escape_: /* Deposit a character preceded by the escape character. */ if (!newarg) { unput (ch); ch = '\\'; } deposit_: /* If the last token returned was a string argument and we * are starting a second, a delimiter token must be returned * to delimit the two arguments. Check for chars not legal * in an identifier so that we can know whether to return * CONSTANT or call crackident() which returns IDENT if not * a reserved keyword. */ if (newtoken) { identifier = 1; stringtok = 1; setlevel = 0; if (newarg) { unput (ch); newarg = 0; return (','); } } yytext[yyleng++] = ch; if (ch == '[') { while ((ch = input()) != ']') yytext[yyleng++] = ch; yytext[yyleng++] = ch; } else if (ch == '\\') yytext[yyleng++] = ch = input(); else if (!(isalnum(ch) || ch == '_' || ch == '$' || ch == '.')) identifier = 0; } } tokout_: yytext[yyleng] = '\0'; if (isdigit (yytext[0]) || yytext[0] == '.' && isdigit (yytext[1])) { int token, toklen; token = c_lexnum (yytext, &toklen); if (token != LEX_NONNUM && toklen == yyleng) { switch (token) { case LEX_REAL: yylval = addconst (yytext, OT_REAL); break; default: yylval = addconst (yytext, OT_INT); break; } return (Y_CONSTANT); } } if (identifier) return (crackident (yytext)); else { yylval = addconst (yytext, OT_STRING); return (Y_CONSTANT); } eatwhite_: /* Control transfers here after a token has been identified which is * followed by an associated argument (e.g. > file or < file). Our * function is to discard any whitespace following the current token * in order to make whitespace optional in the input at this point. * This makes "> file" (for example) equivalent to ">file". */ newarg = 0; while ((ch = input()) && (ch == ' ' || ch == '\t')) ; if (ch) { unput (ch); return (token); } else return (0); }