NetBSD/sys/netiso/xebec/llscan.c

443 lines
9.7 KiB
C

/* $NetBSD: llscan.c,v 1.14 2009/03/18 10:22:44 cegger Exp $ */
/*
* ************************* NOTICE *******************************
* This code is in the public domain. It cannot be copyrighted.
* This scanner was originally written by Keith Thompson for the
* University of Wisconsin Crystal project.
* It was subsequently modified significantly by Nancy Hall at the
* University of Wisconsin for the ARGO project.
* ****************************************************************
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: llscan.c,v 1.14 2009/03/18 10:22:44 cegger Exp $");
#include "xebec.h"
#include "llparse.h"
#include "main.h"
#include <stdio.h>
#include "procs.h"
#include "debug.h"
#include <string.h>
#define EOFILE 0x01
#define UNUSED 0x02
#define IGNORE 0x04
#define OPCHAR 0x8
#define DIGITS 0x10
#define LETTER 0x20
int chtype[128] = {
/* null, soh ^a, stx ^b etx ^c eot ^d enq ^e ack ^f bel ^g */
EOFILE, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
/* bs ^h ht ^i lf ^j vt ^k ff ^l cr ^m so ^n si ^o */
UNUSED, IGNORE, IGNORE, UNUSED, IGNORE, IGNORE, UNUSED, UNUSED,
/* dle ^p dc1 ^q dc2 ^r dc3 ^s dc4 ^t nak ^u syn ^v etb ^w */
UNUSED, UNUSED, UNUSED, UNUSED, EOFILE, UNUSED, UNUSED, UNUSED,
/* can ^x em ^y sub ^z esc ^] fs ^\ gs ^} rs ^` us ^/ */
UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED, UNUSED,
/* ! " # $ % & ' */
IGNORE, UNUSED, OPCHAR, UNUSED, OPCHAR, UNUSED, OPCHAR, OPCHAR,
/* ( ) * + , - . / */
OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR,
/* 0 1 2 3 4 5 6 7 */
DIGITS, DIGITS, DIGITS, DIGITS, DIGITS, DIGITS, DIGITS, DIGITS,
/* 8 9 : ; < = > ? */
DIGITS, DIGITS, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR, OPCHAR,
/* @ A B C D E F G */
UNUSED, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
/* H I J K L M N O */
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
/* P Q R S T U V W */
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
/* X Y Z [ \ ] ^ _ */
LETTER, LETTER, LETTER, OPCHAR, UNUSED, OPCHAR, OPCHAR, LETTER,
/* ` a b c d e f g */
UNUSED, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
/* h i j k l m n o */
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
/* p q r s t u v w */
LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
/* x y z { | } ~ del */
LETTER, LETTER, LETTER, OPCHAR, UNUSED, OPCHAR, UNUSED, UNUSED
};
extern FILE *astringfile;
static char *buffptr;
static char buffer[2][LINELEN];
static int currentbuf = 1;
#define addbuf(x) *buffptr++ = x
static int ch = ' ';
int getch();
extern void AddCurrentEventName();
void
skip(void)
{
while((chtype[ch] == IGNORE) ) {
ch = getch();
}
}
void
llaccept(LLtoken *t)
{
switch(t->llstate) {
case NORMAL:
break;
case INSERT:
fprintf(stderr,"Insert %s\n", llstrings[t->llterm]);
break;
case DELETE:
fprintf(stderr,"Delete %s\n", llstrings[t->llterm]);
break;
}
}
#define TVAL (t->llattrib)
void
dump_buffer(void)
{
register int i;
for(i=0; i<20; i++)
(void) fputc(buffer[currentbuf][i], stderr);
(void) fputc('\n', stderr);
(void) fflush(stderr);
}
int iskey(c, buf)
char *c;
char **buf;
{
register int i;
static struct { char *key_word; int term_type; } keys[] = {
{ "SAME", T_SAME },
{ "DEFAULT", T_DEFAULT },
{ "NULLACTION", T_NULLACTION },
{ "STRUCT", T_STRUCT },
{ "SYNONYM", T_SYNONYM },
{ "TRANSITIONS", T_TRANSITIONS },
{ "STATES", T_STATES },
{ "EVENTS", T_EVENTS },
{ "PCB", T_PCB },
{ "INCLUDE", T_INCLUDE },
{ "PROTOCOL", T_PROTOCOL },
{ 0, 0},
};
for (i = 0; keys[i].key_word ; i++) {
if( !strcmp(c, (*buf = keys[i].key_word) ) ) {
return ( keys[i].term_type );
}
}
*buf = (char *)0;
return(0);
}
void
getstr(o,c)
/* c is the string delimiter
* allow the delimiter to be escaped
* the messy part: translate $ID to
* e->ev_union.ID
* where ID is an event with a non-zero obj_struc
* need we check for the field???
*/
char o,c;
{
register int nested = 1;
register int allow_nesting = (o==c)?-1:1;
IFDEBUG(S)
fprintf(stdout,"getstr: ch=%c, delimiters %c %c\n",
ch,o, c);
fprintf(stdout,"getstr: buffptr %p, currentbuf 0x%x\n",
buffptr, currentbuf);
ENDDEBUG
if( ch == c ) nested--;
while(nested) {
if(ch == '\0') {
fprintf(stderr,
"Eof inside of a string, delims= %c,%c, nesting %d",c,o, nested);
Exit(-1);
/* notreached */
} else if(ch == '$') {
/* might be an attribute */
IFDEBUG(S)
fprintf(stdout,"getstr: atttribute?\n");
ENDDEBUG
/* assume it's an event */
/* addbuf is a macro so this isn't as bad as
* it looks
* add "e->ev_union."
*/
if( (ch = getch()) == '$' ) {
addbuf('e'); addbuf('-'); addbuf('>');
addbuf('e'); addbuf('v'); addbuf('_');
addbuf('u'); addbuf('n'); addbuf('i');
addbuf('o'); addbuf('n');
addbuf('.');
AddCurrentEventName(& buffptr);
} else {
char *obufp = buffptr;
do {
addbuf(ch);
ch = getch();
} while(chtype[ch] & LETTER);
addbuf('\0');
if( !strncmp(obufp, synonyms[PCB_SYN],
strlen(synonyms[PCB_SYN]) )) {
buffptr = obufp;
addbuf('p');
} else if( !strncmp(obufp, synonyms[EVENT_SYN],
strlen(synonyms[EVENT_SYN]))) {
buffptr = obufp;
addbuf('e');
} else {
fprintf(stderr, "Unknown synonym %s\n", obufp);
Exit(-1);
}
if(ch == '.') {
addbuf('-'); addbuf('>');
} else {
/* needs to be checked for nesting */
goto check;
}
}
/* end of attribute handling */
goto skip;
} else if(ch == '\\') {
/* possible escape - this is kludgy beyond belief:
* \ is used to escape open and closing delimiters
* and '$'
* otherwise it's passed through to be compiled by C
*/
ch = getch();
if( (ch != o ) && (ch != c) && (ch != '$') ) {
/* may need to handle case where \ is last char in file... */
/* don't treat is as escape; not open or close so
* don't have to worry about nesting either
*/
addbuf('\\');
}
}
addbuf(ch);
skip:
ch = getch();
check:
if( ch == o ) nested += allow_nesting;
else if( ch == c ) nested--;
if ( (buffptr - buffer[currentbuf]) > LINELEN) {
fprintf(stderr,
"%s too long.\n", (o=='{')?"Action":"Predicate"); /*}*/
fprintf(stderr,
"buffptr, currentbuf %p, 0x%x\n",buffptr,currentbuf );
Exit(-1);
}
IFDEBUG(S)
fprintf(stdout,"loop in getstr: ch 0x%x,%c o=%c,c=%c nested=%d\n",
ch,ch,o,c,nested);
ENDDEBUG
}
addbuf(ch);
addbuf('\0');
IFDEBUG(S)
fprintf(stdout,"exit getstr: got %s\n", buffer[currentbuf]);
fprintf(stdout,"exit getstr: buffptr %p, currentbuf 0x%x\n",
buffptr, currentbuf);
ENDDEBUG
}
int
getch(void)
{
int c;
extern FILE *infile;
extern int lineno;
c = fgetc(infile);
if (c == '\n') lineno++;
if (c == EOF) c = 0;
if (c & ~0x7f) c = 0;
if (feof(infile)) c = 0;
IFDEBUG(e)
fprintf(stdout, "getch: 0x%x\n", c);
(void) fputc(c, stdout);
fflush(stdout);
ENDDEBUG
return c;
}
void
llscan(LLtoken *t)
{
char c;
t->llstate = NORMAL;
++currentbuf;
currentbuf&=1;
again:
buffptr = &buffer[currentbuf][0];
skip();
switch(chtype[ch]) {
case EOFILE:
t->llterm = T_ENDMARKER;
break;
case UNUSED:
fprintf(stderr, "Illegal character in input - 0x%x ignored.", ch);
ch = getch();
goto again;
case OPCHAR:
switch(ch) {
case '/':
/* possible comment : elide ; kludge */
IFDEBUG(S)
fprintf(stdout, "Comment ch=%c\n", ch);
ENDDEBUG
c = getch();
if (c != '*') {
fprintf(stderr,"Syntax error : character(0x%x) ignored", ch);
ch = c;
goto again;
} else {
register int state = 2, whatchar=0;
static int dfa[3][3] = {
/* done seen-star middle */
/* star */ { 0, 1, 1 },
/* / */ { 0, 0, 2 },
/* other */ { 0, 2, 2 }
};
while( state ) {
if( (c = getch()) == (char)0)
break;
whatchar = (c=='*')?0:(c=='/'?1:2);
IFDEBUG(S)
fprintf(stdout,
"comment: whatchar = %d, c = 0x%x,%c, oldstate=%d",
whatchar, c,c, state);
ENDDEBUG
state = dfa[whatchar][state];
IFDEBUG(S)
fprintf(stdout, ", newstate=%d\n", state);
ENDDEBUG
}
if(state) {
fprintf(stderr,
"Syntax error: end of file inside a comment");
Exit(-1);
} else ch = getch();
}
IFDEBUG(S)
fprintf(stdout, "end of comment at 0x%x,%c\n",ch,ch);
ENDDEBUG
goto again;
case '*':
t->llterm = T_STAR;
break;
case ',':
t->llterm = T_COMMA;
break;
case ';':
t->llterm = T_SEMI;
break;
case '<':
t->llterm = T_LANGLE;
break;
case '=':
t->llterm = T_EQUAL;
break;
case '[':
t->llterm = T_LBRACK;
break;
case ']':
t->llterm = T_RBRACK;
break;
#ifdef T_FSTRING
case '"':
t->llterm = T_FSTRING;
addbuf(ch);
ch = getch();
getstr('"', '"');
TVAL.FSTRING.address = stash(buffer[currentbuf]);
break;
#endif /* T_FSTRING */
case '(':
t->llterm = T_PREDICATE;
getstr(ch, ')' );
TVAL.PREDICATE.address = buffer[currentbuf];
break;
case '{':
t->llterm = T_ACTION;
getstr(ch, '}');
TVAL.ACTION.address = buffer[currentbuf];
break;
default:
fprintf(stderr,"Syntax error : character(0x%x) ignored", ch);
ch = getch();
goto again;
}
ch = getch();
break;
case LETTER:
do {
addbuf(ch);
ch = getch();
} while(chtype[ch] & (LETTER | DIGITS));
addbuf('\0');
t->llterm = iskey(buffer[currentbuf], &TVAL.ID.address);
if(!t->llterm) {
t->llterm = T_ID;
TVAL.ID.address = buffer[currentbuf];
}
IFDEBUG(S)
fprintf(stdout, "llscan: id or keyword %p, %s\n",
TVAL.ID.address, TVAL.ID.address);
ENDDEBUG
break;
default:
fprintf(stderr, "Snark in llscan: chtype=0x%x, ch=0x%x\n",
chtype[ch], ch);
}
}