444 lines
9.7 KiB
C
444 lines
9.7 KiB
C
/* $NetBSD: llscan.c,v 1.7 2001/11/13 01:10:52 lukem 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.7 2001/11/13 01:10:52 lukem 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()
|
|
{
|
|
while((chtype[ch] == IGNORE) ) {
|
|
ch = getch();
|
|
}
|
|
}
|
|
|
|
void
|
|
llaccept(t)
|
|
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()
|
|
{
|
|
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 0x%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 0x%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 0x%p, currentbuf 0x%x\n",
|
|
buffptr, currentbuf);
|
|
ENDDEBUG
|
|
}
|
|
|
|
int
|
|
getch()
|
|
{
|
|
char c;
|
|
extern FILE *infile;
|
|
extern int lineno;
|
|
|
|
c = fgetc(infile) ;
|
|
if (c == '\n') lineno++;
|
|
if ((int)c == EOF) c = (char)0;
|
|
if (feof(infile)) c = (char) 0;
|
|
IFDEBUG(e)
|
|
fprintf(stdout, "getch: 0x%x\n", c);
|
|
(void) fputc( c, stdout);
|
|
fflush(stdout);
|
|
ENDDEBUG
|
|
|
|
return c;
|
|
}
|
|
|
|
void
|
|
llscan(t)
|
|
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 0x%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);
|
|
}
|
|
}
|