|
|
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: 8012 (0x1f4c)
Types: TextFile
Notes: UNIX file
Names: »lex2.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/lex/lex2.c«
/*
* lex2.c
* lexical analyser and utilities
*/
#include "lex.h"
#define CMAX 3
char cbuf[CMAX];
int bufc = 0;
int lstchr = '\n';
int line = 0;
char *
alloc(n)
register n;
{
register char *pc;
if ((pc=malloc(n)) == NULL)
error(outmem);
return (pc);
}
char *
ralloc(pc, n)
char *pc;
{
if ((pc=realloc(pc, n)) == NULL)
error(outmem);
return (pc);
}
/*
* lexical ananlyser for regular expressions
*/
yylex()
{
switch (yylval = next()) {
case '\\':
yylval = escape();
return (LX_CHAR);
case '"':
inquotes = 1-inquotes;
return (LX_OPER);
case EOF:
error(eoferr);
default:
if (inquotes)
if (yylval == '\n')
error("%s in quoted string", illnln);
else
return (LX_CHAR);
}
switch (yylval) {
case '[':
yylval = getclas();
return (LX_CLAS);
case '.':
return (LX_ANYC);
case ' ':
case '\t':
case '\n':
return (LX_TERM);
case '/':
return (indefs? LX_OPER : LX_TERM);
case '$':
if (!indefs && isspace(look(0)))
return (LX_TERM);
case '^':
case '<':
case '(':
case ')':
case '{':
case '*':
case '?':
case '+':
case '|':
return (LX_OPER);
default:
if (!isascii(yylval) || iscntrl(yylval))
error("%s in regular expression", illchr);
return (LX_CHAR);
}
}
/*
* get a backslashed character
*/
escape()
{
register c, i;
switch (c = next()) {
case 'b':
return ('\b');
case 'f':
return ('\f');
case 'n':
return ('\n');
case 'r':
return ('\r');
case 't':
return ('\t');
default:
if (isoctl(c)) {
for (i=0; c-='0', i<2 && isoctl(look(0)); ++i)
c = c * 8 + next();
if (c > MAXUCHAR)
error(illoct);
}
return (c);
}
}
/*
* read and store a class specification
*/
getclas()
{
register unsigned c,d;
register unsigned char *index;
register bit;
register invert;
if (clas == 0) {
classptr = alloc(MAXUCHAR+1);
index = classptr + (c = MAXUCHAR + 1);
while (c--)
*--index = 0;
} else if ((clas % NBCHAR) == 0) {
c = classindex(clas + NBCHAR);
classptr = ralloc(classptr, c);
index = classptr + c;
c = MAXUCHAR + 1;
while (c--)
*--index = 0;
} else
index = classptr + classindex(clas);
bit = classbit(clas);
if (look(0) == '^') {
invert = 1;
next();
} else
invert = 0;
while ((c=next()) != ']') {
if (iscntrl(c))
error("%s in class", illchr);
if (c == EOF)
error(eoferr);
if (c == '.') {
c = index['\n'] & bit;
for (d=0; d<=MAXUCHAR; ++d)
index[d] |= bit;
if (!c)
index['\n'] ^= bit;
} else {
if (c == '\\')
c = escape();
d = c;
if (look(0) == '-')
if (next(), look(0) != ']') {
if ((d=next()) == '\\')
d = escape();
if (d < c)
error(illrng);
} else
index['-'] |= bit;
do {
index[c] |= bit;
} while (c++ < d);
}
}
if (invert) {
for (d=0; d<=MAXUCHAR; ++d)
index[d] ^= bit;
}
return (clas++);
}
/*
* get next character from input
*/
next()
{
static l = '\n';
register c, i;
if (l == '\n')
++line;
if (bufc == 0)
c = lstchr = getc(filein);
else {
c = cbuf[0];
for (i=1; i < bufc; i++)
cbuf[i-1] = cbuf[i];
--bufc;
}
return (l=c);
}
/*
* look into input for the n+1th character
* practically, n never exceeds 2
*/
look(n)
register n;
{
while (bufc <= n)
cbuf[bufc++] = lstchr = getc(filein);
return (cbuf[n]);
}
/*
* delete input up to and including the next newline
*/
dnl()
{
while (next() != '\n')
;
setltype();
}
/*
* eat up white space
*/
eatspc()
{
register c;
while (c=look(0), c==' ' || c=='\t')
next();
if (c == EOF)
error(eoferr);
}
/*
* eat input until white space
*/
eatlbl()
{
register c;
while (c=look(0), !isspace(c))
next();
if (c == '\n')
return (1);
return (0);
}
/*
* copy an input line to the output file
*/
lcopy()
{
register c;
do {
putc(c=next(), fileout);
} while (c != '\n');
setltype();
}
/*
* set external variable ltype to the type of the next line
*/
setltype()
{
ltype = getltype();
}
/*
* return line type based on the first couple of characters
*/
getltype()
{
switch (look(0)) {
case '\t':
case '\n':
case ' ':
return (LN_LSPC);
case EOF:
return (LN_EOFL);
case '%':
switch (look(1)) {
case '%':
return (LN_DLIM);
case '{':
return (LN_LCOM);
case '}':
return (LN_RCOM);
case 's':
case 'S':
return (LN_SCON);
case 'c':
case 'C':
return (LN_CTXT);
case 'x':
case 'X':
return (LN_OPTN);
}
}
return (LN_DFLT);
}
/*
* put out a #line command for the C preprocessor
*/
outlnum(i)
{
loutput(0, "#line %d", line+i);
}
/*
* copy a user-specified action to the output
* make an attempt at keeping track of single quotes,
* double quotes, and braces.
* these items inside comments will blow us away
*/
getactn()
{
register c, bct, quot;
bct = quot = 0;
for (;;) {
if ((c=next()) == EOF)
error(eoferr);
putc(c, fileout);
switch (c) {
case '\\':
if ((c=next()) == EOF)
error(eoferr);
putc(c, fileout);
break;
case '\'':
if (quot>-1)
quot= 1-quot;
break;
case '"':
if (quot< 1)
quot=-1-quot;
break;
case '{':
if (!quot)
++bct;
break;
case '}':
if (!quot)
if (bct==0)
error(actsyn);
else
--bct;
break;
case '\n':
setltype();
if (bct==0)
return;
if (ltype!=LN_LSPC)
error(actsyn);
}
}
}
/*
* read an identifier
*/
char *
getident()
{
register c, i = 0;
register char *pc;
eatspc();
pc = alloc(NCBLK);
while (c=look(0), isalnum(c) || c=='_') {
pc[i++] = next();
if (i%NCBLK == 0)
pc = ralloc((char *)pc, i+NCBLK);
}
pc[i] = '\0';
eatspc();
return (pc);
}
/*
* interpret an identifier as the name of a
* start condition, try to return its value
*/
getstart()
{
register struct def *pd;
register char *pc;
pd = scnstart;
pc = getident();
do {
if (strcmp(pc, pd->d_name) == 0) {
free(pc);
return (pd->d_data);
}
} while ((pd=pd->d_next) != NULL);
error(undstc);
}
/*
* add a string of identifiers to the start condition
* list, numbering them as we go, too bad if they
* are duplicates
*/
addstart()
{
register struct def *pd;
if (eatlbl())
return;
pd = scnstart;
while (look(0) != '\n') {
pd->d_next = alloc(sizeof(struct def));
pd->d_next->d_data = pd->d_data + 1;
pd = pd->d_next;
pd->d_next = NULL;
pd->d_name = getident();
}
}
/*
* like addstart, except with names of contexts
*/
addcontext()
{
register struct def *pd;
if (eatlbl())
return;
pd = ctxstart;
while (pd->d_next != NULL)
pd = pd->d_next;
pd->d_next = alloc(sizeof(struct def));
pd = pd->d_next;
for (;;) {
pd->d_name = getident();
pd->d_data = 0;
if (look(0) == '\n') {
pd->d_next = NULL;
break;
} else {
pd->d_next = alloc(sizeof(struct def));
pd = pd->d_next;
}
}
}
/*
* this is called to mark the context name with its
* associated section of the nfa
*/
markcontext(t)
{
register char *pc;
register struct def *pd;
eatlbl();
pc = getident();
pd = ctxstart;
while ((pd=pd->d_next) != NULL)
if (strcmp(pc, pd->d_name) == 0) {
pd->d_data = t;
free(pc);
return;
}
error(undctx);
}
/*
* read the name of the definition, try
* to return where it starts
*/
getdefn()
{
register char *pc;
register struct def *pd;
pc = getident();
if (look(0) == '}')
next();
else
error("%s in definition name", illchr);
for (pd=defstart; pd!=NULL; pd=pd->d_next)
if (strcmp(pc, pd->d_name) == 0) {
free(pc);
return (pd->d_data);
}
error(unddef);
}
/*
* recursive, costly but elegant
*/
freedef(pd)
register struct def *pd;
{
if (pd != NULL) {
freedef(pd->d_next);
if (pd->d_name != NULL)
free(pd->d_name);
free((char *)pd);
}
}
/*
* cleanup and abort
*/
/* VARARGS */
error(s)
{
fprintf(stderr, "lex: ");
if (line)
fprintf(stderr, "%d: ", line);
fprintf(stderr, "%r\n", &s);
if (filein == stdin)
while (lstchr!='\n' && lstchr!=EOF)
next();
if (fileout != stdout)
unlink(OUTFILE);
exit (1);
}
usage()
{
fprintf(stderr, "Usage: lex [-tv] [filename]\n");
exit (1);
}