|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 6053 (0x17a5) Types: TextFile Notes: UNIX file Names: »lex.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code └─⟦f4b8d8c84⟧ UNIX Filesystem └─⟦this⟧ »cmd/bc/lex.c«
#include <stdio.h> #include <ctype.h> #include <setjmp.h> #include "bc.h" #include "yy.h" /* * Add declarations which yacc should really put in bc.lex.h. */ extern YYSTYPE yylval; /* * The jump buffer lexenv is used to hold the environment in * yylex that will be returned to if there is some lexical * error. */ static jmp_buf lexenv; /* * Yylex is the lexical analyzer for bc. */ yylex() { register int ch; register int nexteq; register FILE *inf = infile; static int newline = TRUE; /* TRUE iff at start of line */ char *getword(), *getqs(); if (setjmp(lexenv)) return (ERROR); Again: ch = getc(inf); if (newline && ch == '!') { shell(); goto Again; } while (ch == '\t' || ch == ' ') ch = getc(inf); if (ch == '\n' || ch == EOF) { newline = TRUE; return (ch); } else newline = FALSE; if (!isascii(ch)) lexerr("Illegal character"); if (islower(ch)) return (token(getword(ch))); if (isdigit(ch) || 'A' <= ch && ch <= 'F' || ch == '.') { if (ch == '.') { ch = getc(inf); ungetc(ch, inf); if (! (isascii(ch) && isdigit(ch) || 'A' <= ch && ch <= 'F')) return (DOT); ch = '.'; } yylval.lvalue = getnum(ch); return (NUMBER); } nexteq = next('='); switch (ch) { case '+': return (nexteq ? ADDAB : (next('+') ? INCR : ch)); case '-': return (nexteq ? SUBAB : (next('-') ? DECR : ch)); case '*': return (nexteq ? MULAB : ch); case '%': return (nexteq ? REMAB : ch); case '^': return (nexteq ? EXPAB : ch); case '/': if (!nexteq && next('*')) { do { ch = getc(inf); } while (ch != '*' || !next('/')); goto Again; } return (nexteq ? DIVAB : ch); case '=': return (nexteq ? EQP : ch); case '<': return (nexteq ? LEP : LTP); case '>': return (nexteq ? GEP : GTP); case '!': return (nexteq ? NEP : ch); case '"': yylval.svalue = getqs(); return(STRING); default: if (nexteq) ungetc('=', inf); return(ch); } } /* * Next returns TRUE iff the next character on input is "testc". * If the next character is not "testc" then it is pushed back * for later consumption. */ int next(testc) char testc; { register int ch; register int result; ch = getc(infile); if (! (result = ch == testc)) ungetc(ch, infile); return(result); } /* * Getqs reads in a quoted string. It assumes that the initial * double quote has already been read in and it returns a pointer * to an allocated area where the string has been copyied. */ char * getqs() { register char *ptr; register int ch; char buf[MAXSTRING]; ptr = buf; while ((ch = getc(infile)) != '"') { if (ch == EOF || ch == '\n') lexerr("Unexpected end of quoted string"); if (ptr < &buf[MAXSTRING]) *ptr++ = ch; } if (ptr >= &buf[MAXSTRING]) lexerr("Quoted string too long"); *ptr = '\0'; ptr = (char *)mpalc(1 + ptr - buf); strcpy(ptr, buf); return (ptr); } /* * Token looks up the string pointed to by "word" in the * list of keywords. If the word is found, then it returns * the corresponding value. If not, then it makes sure that * the string is in the string table, sets yylval to a pointer to * the string table entry and returns IDENTIFIER. */ int token(word) char *word; { static struct keyword { char *key; int keyval; } keywords[] = { "auto", AUTO, "break", BREAK, "continue", CONTINUE, "define", DEFINE, "do", DO, "else", ELSE, "for", FOR, "ibase", IBASE, "if", IF, "length", LENGTH_, "obase", OBASE, "quit", QUIT, "return", RETURN_, "scale", SCALE_, "sqrt", SQRT_, "while", WHILE }; register struct keyword *probe; register struct keyword *fwa = keywords; register struct keyword *lwa = &keywords[nel(keywords) - 1]; int cmp; dicent *lookword(); while (fwa <= lwa) { probe = fwa + (lwa - fwa) / 2; cmp = strcmp(word, probe->key); if (cmp > 0) fwa = probe + 1; else if (cmp < 0) lwa = probe - 1; else return (probe->keyval); } yylval.dvalue = lookword(word); return (IDENTIFIER); } /* * Lookword looks up the string str in the string table dictionary. * If it is not already there, then it adds it and initializes the * type fields to indicate it as undefined. * It returns the pointer to the dictionary entry for the string. */ dicent * lookword(str) char *str; { register dicent **father, *probe; register int rel; father = &dictionary; while ( (probe = *father) != NULL) { rel = strcmp(probe->word, str); if (rel == 0) return (probe); father = (rel < 0 ? &probe->left : &probe->right); } probe = (dicent *)mpalc((sizeof *probe) + strlen(str) + 1); probe->left = probe->right = NULL; probe->globalt = probe->localt = UNDEFINED; strcpy(probe->word, str); *father = probe; return (probe); } /* * Getword reads in a word (alphanumeric sequence) which starts * with "ch". It returns a pointer to the string read in. * Note that the pointer is to a static area and hence * the result must be copyied if it is to be used after another * call to getword. */ char * getword(ch) register char ch; { static char word[MAXWORD + 1]; register char *chp = &word[0]; do { if (chp < &word[MAXWORD]) *chp++ = ch; ch = getc(infile); } while (isascii(ch) && isalnum(ch)); ungetc(ch, infile); if (chp >= &word[MAXWORD]) lexerr("Identifier too long"); *chp = '\0'; return (word); } /* * Shell reads in a line from the standard input and forks a shell * to execute it. */ shell() { register char *ptr; register int ch; char buff[MAXSTRING]; ptr = buff; while ((ch = getc(infile)) != '\n' && ch != EOF) if (ptr < &buff[MAXSTRING]) *ptr++ = ch; if (ptr >= &buff[MAXSTRING]) { fprintf(stderr, "! line too long\n"); return; } *ptr = '\0'; fflush(infile); if (system(buff) == NOSHELL) fprintf(stderr, "bc: shell couldn't execute\n"); printf("!\n"); } /* * Lexerr issues the appropriate error message on stderr and * then longjumps back to lex which return ERROR. */ lexerr(str) char *str; { fprintf(stderr, "%r\n", &str); longjmp(lexenv, TRUE); }