/* * Define a user named label to have the offset of the next opcode. * * given: * name label name */ void definelabel(char *name) { register LABEL *lp; /* current label */ long i; /* current label index */ i = findstr(&labelnames, name); if (i >= 0) { lp = &labels[i]; if (lp->l_offset >= 0) { scanerror(T_NULL, "Label \"%s\" is multiply defined", name); return; } setlabel(lp); return; } if (labelcount >= MAXLABELS) { scanerror(T_NULL, "Too many labels in use"); return; } lp = &labels[labelcount++]; lp->l_chain = -1L; lp->l_offset = (long)curfunc->f_opcodecount; lp->l_name = addstr(&labelnames, name); clearopt(); }
static Boolean getfds(int fd[2], int c, int default0, int default1) { int n; fd[0] = default0; fd[1] = default1; if (c != '[') { UNGETC(c); return TRUE; } if ((unsigned int) (n = GETC() - '0') > 9) { scanerror("expected digit after '['"); return FALSE; } while ((unsigned int) (c = GETC() - '0') <= 9) n = n * 10 + c; fd[0] = n; switch (c += '0') { case '=': if ((unsigned int) (n = GETC() - '0') > 9) { if (n != ']' - '0') { scanerror("expected digit or ']' after '='"); return FALSE; } fd[1] = CLOSED; } else { while ((unsigned int) (c = GETC() - '0') <= 9) n = n * 10 + c; if (c != ']' - '0') { scanerror("expected ']' after digit"); return FALSE; } fd[1] = n; } break; case ']': break; default: scanerror("expected '=' or ']' after digit"); return FALSE; } return TRUE; }
/* * Check to make sure that all labels are defined. */ void checklabels(void) { register LABEL *lp; /* label being checked */ long i; /* counter */ for (i = labelcount, lp = labels; --i >= 0; lp++) { if (lp->l_offset >= 0) continue; scanerror(T_NULL, "Label \"%s\" was never defined", lp->l_name); } }
static void getpair(int c) { int n; fd_left = fd_right = UNSET; if (c != '[') { ugchar(c); return; } if ((unsigned int) (n = gchar() - '0') > 9) { scanerror("expected digit after '['"); return; } while ((unsigned int) (c = gchar() - '0') <= 9) n = n * 10 + c; fd_left = n; c += '0'; switch (c) { default: scanerror("expected '=' or ']' after digit"); return; case ']': return; case '=': if ((unsigned int) (n = gchar() - '0') > 9) { if (n != ']' - '0') { scanerror("expected digit or ']' after '='"); return; } fd_right = CLOSED; } else { while ((unsigned int) (c = gchar() - '0') <= 9) n = n * 10 + c; if (c != ']' - '0') { scanerror("expected ']' after digit"); return; } fd_right = n; } } }
/* * Add the offset corresponding to the specified user label name to the * opcode table for a function. If the label is not yet defined, then a * chain of undefined offsets is built using the offset value, and it * will be fixed up when the label is defined. * * given: * name user symbol name */ void addlabel(char *name) { register LABEL *lp; /* current label */ long i; /* counter */ for (i = labelcount, lp = labels; --i >= 0; lp++) { if (strcmp(name, lp->l_name)) continue; uselabel(lp); return; } if (labelcount >= MAXLABELS) { scanerror(T_NULL, "Too many labels in use"); return; } lp = &labels[labelcount++]; lp->l_offset = -1L; lp->l_chain = -1L; lp->l_name = addstr(&labelnames, name); uselabel(lp); }
int s_yylex() { register c; register char *cp; int f; char delim; if (yylineno == 0) incrlineno(); while(1) { /* * skip white space */ if (c = lookaheadchar ) { lookaheadchar = 0; } else c = readkey(); cp = yytext; while (c == ' ' || c == '\t' || c == 0 || c == 12 /* FF */) { c = readkey(); } yytext[0] = c; yytext[1] = yytext[2] = 0; if( isascii(c) && (isalpha( c ) || c == '_') ) { do { *cp++ = c; c = readkey(); } while (isascii(c) && (isalnum(c) || c == '_')); *cp = 0; lookaheadchar = c; c = look_kw(yytext); clearla(); if (c == 0) { yylval.strval = allocstring(yytext); return (YID); } return c; } else if( isascii(c) && isdigit(c) ) { f = 0; do { *cp++ = c; c = readkey(); } while (isascii(c) && isdigit(c)); if (c == '.') { c = readkey(); if (c == '.') { *cp = 0; lookaheadchar = YDOTDOT; yylval.strval = allocstring(yytext); return (YINT); } infpnumb: f++; *cp++ = '.'; if (!isascii(c) || !isdigit(c)) { scanerror("syntax error: digits required after decimal point"); *cp++ = '0'; } else while (isdigit(c)) { *cp++ = c; c = readkey(); } } if (c == 'e' || c == 'E') { f++; *cp++ = c; if ((c = lookaheadchar) == 0) c = readkey(); if (c == '+' || c == '-') { *cp++ = c; c = readkey(); } if (!isascii(c) || !isdigit(c)) { scanerror("syntax error: digits required in exponent"); *cp++ = '0'; } else while (isascii(c) && isdigit(c)) { *cp++ = c; c = readkey(); } } *cp = 0; lookaheadchar = c; clearla(); yylval.strval = allocstring(yytext); if (f) return (YNUMB); return (YINT); } printt2("Select on char %d - %c\n", c, c ); switch (c) { case EOF: return 0; case ' ': case '\t': case 12: /* form feed */ break; case '"': case '\'': *cp++ = delim = c; do { do { c = readkey(); if (c == '\n' || c == EOFCHAR) { scanerror("syntax error: unmatched quote for string" ); if (cp == yytext) *cp++ = ' ', cp++; return YILLCH; } *cp++ = c; } while (c != delim); c = readkey(); } while (c == delim); if( c == '^' || c== '#' ) { par_error( "Can't imbed ^A or #nnn codes in strings. Try concatenating strings together\n" ); } *--cp = 0; #ifndef TURBO if (cp == yytext && delim == '\'') { scanerror("syntax error: null string not allowed"); *cp++ = ' '; *cp++ = 0; } #endif lookaheadchar = c; clearla(); /* len of 2 means 1 char and 1 quote char */ if (delim == '"' || strlen(yytext) != 2) { yylval.strval = allocstring(yytext); return (YSTRING); } else { yylval.intval = yytext[1]; return (YCHAR); } case '.': c = readkey(); if (c == '.') return (YDOTDOT); if (isdigit(c)) { scanerror("syntax error: digits required before decimal point"); *cp++ = '0'; goto infpnumb; } lookaheadchar = c; clearla(); return '.'; case '\n': break; case '{': /* { ... } comment */ delim = '{'; comment: c = readkey(); #ifdef TURBO if (c == '$' && turbo_flag) { f = scanturbo(); if (f >= 0) return f; } else #endif if (c == '+') { /* Stubs generated by alist, we know they use {} */ f = scanstub(); if (f == YC_BLCOMMENT) { /* Kludge - throw away to keep grammar LALR. * Doesn't matter since they will be generated * in all appropriate places anyway. */ continue; /* outer while loop */ } if (f >= 0) return f; } else { for (;;) { if (delim=='{' && c == '}') { break; } if (c == '\n') { /* Break into one line pieces */ *cp++ = 0; savecomment(yytext); cp = yytext; *cp = 0; } else { *cp++ = c; if (c <= 0) { /* nonterminated comment */ /* This "can't happen" */ fatal("Bug - nonterm comment"); } } c = readkey(); if (delim=='(' && c == ')' && cp[-1] == '*') { *--cp = 0; break; } } *cp++ = 0; } /* * Comments generated by the lister for procedure or * function calls (in parens, ending in =) are ignored. */ if (parendepth <= 0 || cp[-2] != '=') savecomment(yytext); clearla(); cp = yytext; *cp = 0; if (allowcom) return 0; break; case ':': if ((c=readkey()) == '=') { *++cp = c; return YCOLEQUALS; } lookaheadchar = c; clearla(); return ':'; case '(': if ((c=readkey()) == '*') { delim = '('; goto comment; } lookaheadchar = c; clearla(); parendepth++; return '('; case ')': parendepth--; return ')'; case '$': while( isxdigit(c = readkey()) ) *++cp = c; *++cp = 0; lookaheadchar = c; if( strlen(yytext) <= 1 ) return YILLCH; yylval.strval = allocstring(yytext); return YINT; case '#': c = readkey(); if( c == '$' ) { unsigned hxnum; while( isxdigit(c = readkey()) ) hxnum = (hxnum << 4) + ((c > '9') ? 9 : 0) + (c & 0xf); lookaheadchar = c; yylval.intval = hxnum; return YCHAR; } else while (isdigit(c)) { *++cp = c; c = readkey(); } *++cp = 0; lookaheadchar = c; yylval.intval = atoi(&yytext[1]); return YCHAR; case '^': c = readkey(); if (strchr("\\_", c)) { /* others include []@^ */ yylval.intval = c & 0x1f; return YCHAR; } else { lookaheadchar = c; yylval.intval = '^'; return YPTR; } case '@': yylval.intval = '@'; return YPTR; case ';': case ',': case '=': case '*': case '+': case '/': case '-': case '[': case ']': case '<': case '>': case '_': case '\\': case '}': /* for DO..SET */ return c; case YDOTDOT: return YDOTDOT; default: if (c <= 0) return (0); do lookaheadchar = readkey(); while (lookaheadchar == c); clearla(); printt1("illegal char in scanner %o\n", c); return (YILLCH); } } /* big while */ }
extern int yylex(void) { static Boolean dollar = FALSE; int c; size_t i; /* The purpose of all these local assignments is to */ const char *meta; /* allow optimizing compilers like gcc to load these */ char *buf = tokenbuf; /* values into registers. On a sparc this is a */ YYSTYPE *y = &yylval; /* win, in code size *and* execution time */ if (goterror) { goterror = FALSE; return NL; } /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */ meta = (dollar ? dnw : nw); dollar = FALSE; if (newline) { --input->lineno; /* slight space optimization; print_prompt2() always increments lineno */ print_prompt2(); newline = FALSE; } top: while ((c = GETC()) == ' ' || c == '\t') w = NW; if (c == EOF) return ENDFILE; if (!meta[(unsigned char) c]) { /* it's a word or keyword. */ InsertFreeCaret(); w = RW; i = 0; do { buf[i++] = c; if (i >= bufsize) buf = tokenbuf = erealloc(buf, bufsize *= 2); } while ((c = GETC()) != EOF && !meta[(unsigned char) c]); UNGETC(c); buf[i] = '\0'; w = KW; if (buf[1] == '\0') { int k = *buf; if (k == '@' || k == '~') return k; } else if (*buf == 'f') { if (streq(buf + 1, "n")) return FN; if (streq(buf + 1, "or")) return FOR; } else if (*buf == 'l') { if (streq(buf + 1, "ocal")) return LOCAL; if (streq(buf + 1, "et")) return LET; } else if (streq(buf, "~~")) return EXTRACT; else if (streq(buf, "%closure")) return CLOSURE; w = RW; y->str = gcdup(buf); return WORD; } if (c == '`' || c == '!' || c == '$' || c == '\'') { InsertFreeCaret(); if (c == '!') w = KW; } switch (c) { case '!': return '!'; case '`': c = GETC(); if (c == '`') return BACKBACK; UNGETC(c); return '`'; case '$': dollar = TRUE; switch (c = GETC()) { case '#': return COUNT; case '^': return FLAT; case '&': return PRIM; default: UNGETC(c); return '$'; } case '\'': w = RW; i = 0; while ((c = GETC()) != '\'' || (c = GETC()) == '\'') { buf[i++] = c; if (c == '\n') print_prompt2(); if (c == EOF) { w = NW; scanerror("eof in quoted string"); return ERROR; } if (i >= bufsize) buf = tokenbuf = erealloc(buf, bufsize *= 2); } UNGETC(c); buf[i] = '\0'; y->str = gcdup(buf); return QWORD; case '\\': if ((c = GETC()) == '\n') { print_prompt2(); UNGETC(' '); goto top; /* Pretend it was just another space. */ } if (c == EOF) { UNGETC(EOF); goto badescape; } UNGETC(c); c = '\\'; InsertFreeCaret(); w = RW; c = GETC(); switch (c) { case 'a': *buf = '\a'; break; case 'b': *buf = '\b'; break; case 'e': *buf = '\033'; break; case 'f': *buf = '\f'; break; case 'n': *buf = '\n'; break; case 'r': *buf = '\r'; break; case 't': *buf = '\t'; break; case 'x': case 'X': { int n = 0; for (;;) { c = GETC(); if (!isxdigit(c)) break; n = (n << 4) | (c - (isdigit(c) ? '0' : ((islower(c) ? 'a' : 'A') - 0xA))); } if (n == 0) goto badescape; UNGETC(c); *buf = n; break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { int n = 0; do { n = (n << 3) | (c - '0'); c = GETC(); } while (isodigit(c)); if (n == 0) goto badescape; UNGETC(c); *buf = n; break; } default: if (isalnum(c)) { badescape: scanerror("bad backslash escape"); return ERROR; } *buf = c; break; } buf[1] = 0; y->str = gcdup(buf); return QWORD; case '#': while ((c = GETC()) != '\n') /* skip comment until newline */ if (c == EOF) return ENDFILE; /* FALLTHROUGH */ case '\n': input->lineno++; newline = TRUE; w = NW; return NL; case '(': if (w == RW) /* not keywords, so let & friends work */ c = SUB; /* FALLTHROUGH */ case ';': case '^': case ')': case '=': case '{': case '}': w = NW; return c; case '&': w = NW; c = GETC(); if (c == '&') return ANDAND; UNGETC(c); return '&'; case '|': { int p[2]; w = NW; c = GETC(); if (c == '|') return OROR; if (!getfds(p, c, 1, 0)) return ERROR; if (p[1] == CLOSED) { scanerror("expected digit after '='"); /* can't close a pipe */ return ERROR; } y->tree = mk(nPipe, p[0], p[1]); return PIPE; } { char *cmd; int fd[2]; case '<': fd[0] = 0; if ((c = GETC()) == '>') if ((c = GETC()) == '>') { c = GETC(); cmd = "%open-append"; } else cmd = "%open-write"; else if (c == '<') if ((c = GETC()) == '<') { c = GETC(); cmd = "%here"; } else cmd = "%heredoc"; else if (c == '=') return CALL; else cmd = "%open"; goto redirection; case '>': fd[0] = 1; if ((c = GETC()) == '>') if ((c = GETC()) == '<') { c = GETC(); cmd = "%open-append"; } else cmd = "%append"; else if (c == '<') { c = GETC(); cmd = "%open-create"; } else cmd = "%create"; goto redirection; redirection: w = NW; if (!getfds(fd, c, fd[0], DEFAULT)) return ERROR; if (fd[1] != DEFAULT) { y->tree = (fd[1] == CLOSED) ? mkclose(fd[0]) : mkdup(fd[0], fd[1]); return DUP; } y->tree = mkredircmd(cmd, fd[0]); return REDIR; } default: assert(c != '\0'); w = NW; return c; /* don't know what it is, let yacc barf on it */ } }
extern int yylex() { static bool dollar = FALSE; bool saw_meta = FALSE; int c; SIZE_T i; /* The purpose of all these local assignments is to */ char *meta; /* allow optimizing compilers like gcc to load these */ char *buf = realbuf; /* values into registers. On a sparc this is a */ YYSTYPE *y = &yylval; /* win, in code size *and* execution time */ if (errset) { errset = FALSE; return '\n'; } /* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */ meta = (dollar ? dnw : nw); dollar = FALSE; if (newline) { --lineno; /* slight space optimization; print_prompt2() always increments lineno */ print_prompt2(); newline = FALSE; } top: while ((c = gchar()) == ' ' || c == '\t') w = NW; if (c == EOF) return END; if (!meta[(unsigned char) c]) { /* it's a word or keyword. */ checkfreecaret; w = RW; i = 0; read: do { buf[i++] = c; if (c == '?' || c == '[' || c == '*') saw_meta = TRUE; if (i >= bufsize) buf = realbuf = erealloc(buf, bufsize *= 2); } while ((c = gchar()) != EOF && !meta[(unsigned char) c]); while (c == '\\') { if ((c = gchar()) == '\n') { print_prompt2(); c = ' '; /* Pretend a space was read */ break; } else { bs: if (meta != dnw) { /* all words but varnames may have a bslash */ buf[i++] = '\\'; if (i >= bufsize) buf = realbuf = erealloc(buf, bufsize *= 2); if (!meta[(unsigned char) c]) goto read; } else { ugchar(c); c = '\\'; break; } } } ugchar(c); buf[i] = '\0'; w = KW; if (i == 2) { if (*buf == 'i' && buf[1] == 'f') return IF; if (*buf == 'f' && buf[1] == 'n') return FN; if (*buf == 'i' && buf[1] == 'n') return IN; } if (streq(buf, "for")) return FOR; if (streq(buf, "else")) return ELSE; if (streq(buf, "switch")) return SWITCH; if (streq(buf, "while")) return WHILE; if (streq(buf, "case")) return CASE; w = RW; y->word.w = ncpy(buf); if (saw_meta) { char *r, *s; y->word.m = nalloc(strlen(buf) + 1); for (r = buf, s = y->word.m; *r != '\0'; r++, s++) *s = (*r == '?' || *r == '[' || *r == '*'); } else { y->word.m = NULL; } return WORD; } if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') { checkfreecaret; if (c == '!' || c == '@' || c == '~') w = KW; } switch (c) { case '!': return BANG; case '@': return SUBSHELL; case '~': return TWIDDLE; case '`': c = gchar(); if (c == '`') return BACKBACK; ugchar(c); return '`'; case '$': dollar = TRUE; c = gchar(); if (c == '#') return COUNT; if (c == '^') return FLAT; ugchar(c); return '$'; case '\'': w = RW; i = 0; do { buf[i++] = c; if (c == '\n') print_prompt2(); if (c == EOF) { w = NW; scanerror("eof in quoted string"); return HUH; } if (i >= bufsize) buf = realbuf = erealloc(buf, bufsize *= 2); } while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */ ugchar(c); buf[i] = '\0'; y->word.w = ncpy(buf); y->word.m = NULL; return WORD; case '\\': if ((c = gchar()) == '\n') { print_prompt2(); goto top; /* Pretend it was just another space. */ } ugchar(c); c = '\\'; checkfreecaret; c = gchar(); i = 0; goto bs; case '(': if (w == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */ c = SUB; w = NW; return c; case '#': while ((c = gchar()) != '\n') /* skip comment until newline */ if (c == EOF) return END; /* FALLTHROUGH */ case '\n': lineno++; newline = TRUE; /* FALLTHROUGH */ case ';': case '^': case ')': case '=': case '{': case '}': w = NW; return c; case '&': w = NW; c = gchar(); if (c == '&') return ANDAND; ugchar(c); return '&'; case '|': w = NW; c = gchar(); if (c == '|') return OROR; getpair(c); if (errset) return HUH; if ((y->pipe.left = fd_left) == UNSET) y->pipe.left = 1; /* default to fd 1 */ if ((y->pipe.right = fd_right) == UNSET) y->pipe.right = 0; /* default to fd 0 */ if (y->pipe.right == CLOSED) { scanerror("expected digit after '='"); /* can't close a pipe */ return HUH; } return PIPE; case '>': c = gchar(); if (c == '>') { c = gchar(); y->redir.type = rAppend; } else y->redir.type = rCreate; y->redir.fd = 1; goto common; case '<': c = gchar(); if (c == '<') { c = gchar(); if (c == '<') { c = gchar(); y->redir.type = rHerestring; } else { y->redir.type = rHeredoc; } } else y->redir.type = rFrom; y->redir.fd = 0; common: w = NW; getpair(c); if (errset) return HUH; if (fd_right == UNSET) { /* redirection, not dup */ if (fd_left != UNSET) { y->redir.fd = fd_left; return SREDIR; } return (y->redir.type == rFrom || y->redir.type == rCreate) ? REDIR : SREDIR; } else { /* dup; recast yylval */ y->dup.type = y->redir.type; y->dup.left = fd_left; y->dup.right = fd_right; return DUP; } default: w = NW; return c; /* don't know what it is, let yacc barf on it */ } }