#pragma prototyped
#include <stdarg.h>
#include "libgraph.h"
#include "parser.h"
#include "triefa.cP"
#include "agxbuf.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif
#define InfileName (InputFile?InputFile:"<unknown>")
static FILE *Lexer_fp;
static char *LexPtr,*TokenBuf;
static int LineBufSize;
static uchar In_comment;
static uchar Comment_start;
static uchar Start_html_string;
static int Line_number;
static char* InputFile;
static gets_f Lexer_gets;
void agreadline(int n) { Line_number = n-1; }
void agsetfile(char* f) { InputFile = f; Line_number = 0; }
void aglexinit(FILE* fp, gets_f mygets)
{
Lexer_fp = fp;
Lexer_gets = mygets;
LexPtr = NULL;
if (AG.linebuf == NULL) {
LineBufSize = BUFSIZ;
AG.linebuf = N_NEW(LineBufSize,char);
TokenBuf = N_NEW(LineBufSize,char);
}
(Lexer_gets)(AG.linebuf,0,fp);
}
static char *
skip_wscomments(char* p)
{
do {
while (isspace(*p)) p++;
while (In_comment && p[0]) {
while (p[0] && (p[0] != '*')) p++;
if (p[0]) {
if (p[1] == '/') {In_comment = FALSE; p += 2; break;}
else p++;
}
}
if (p[0] == '/') {
if (p[1] == '/') while (*p) p++;
else {
if (p[1] == '*') {
In_comment = TRUE; Comment_start = Line_number;
p += 2; continue;
}
else break;
}
}
else {if (!isspace(*p)) break;}
} while (p[0]);
return p;
}
static char *
scan_token(char* p, char* token)
{
char *q;
q = token;
if (p == '\0') return NULL;
while (ISALNUM(*p)) {
*q++ = *p++;
}
*q = '\0';
return p;
}
static char *
scan_num(char* p, char* token)
{
char *q,*z;
int saw_rp = FALSE;
int saw_digit = FALSE;
z = p;
q = token;
if (*z == '-') *q++ = *z++;
if (*z == '.') {saw_rp = TRUE; *q++ = *z++;}
while (isdigit(*z)) {saw_digit = TRUE; *q++ = *z++;}
if ((*z == '.') && (saw_rp == FALSE)) {
saw_rp = TRUE; *q++ = *z++;
while (isdigit(*z)) {saw_digit = TRUE; *q++ = *z++;}
}
*q = '\0';
if (saw_digit && *z && ((isalpha(*z)) || (*z == '_'))) {
char* endp = z+1;
char c;
while ((c = *endp) && ((isalpha(c)) || (c == '_'))) endp++;
*endp = '\0';
agerr (AGWARN, "%s:%d: ambiguous \"%s\" splits into two names: \"%s\" and \"%s\"\n",
InfileName,Line_number, p, token, z);
*endp = c;
}
if (saw_digit == FALSE) z = NULL;
return z;
}
static char *
quoted_string(char* p, char* token)
{
char quote,*q;
quote = *p++;
q = token;
while ((*p) && (*p != quote)) {
if (*p == '\\') {
if (*(p+1) == quote) p++;
else {if (*(p+1) == '\\') *q++ = *p++;}
}
*q++ = *p++;
}
if (*p == '\0')
agerr (AGWARN, "%s:%d: string ran past end of line\n",
InfileName,Line_number);
else p++;
*q = 0;
return p;
}
int myaglex(void)
{
int rv = aglex();
fprintf(stderr,"returning %d\n",rv);
if (rv == T_symbol) fprintf(stderr,"string val is %s\n",aglval.str);
return rv;
}
static char *lex_gets(void)
{
char *clp;
int len,curlen;
len = curlen = 0;
do {
if (curlen + SMALLBUF >= LineBufSize) {
LineBufSize += BUFSIZ;
AG.linebuf = realloc(AG.linebuf,LineBufSize);
TokenBuf = realloc(TokenBuf,LineBufSize);
}
clp = (Lexer_gets)(AG.linebuf + curlen + 1, LineBufSize-curlen-1 , Lexer_fp);
if (clp == NULL) break;
len = strlen(clp);
if (clp[len-1] == '\n') {
if ((clp[0] == '#') && (curlen == 0)) {
if (sscanf(clp+1,"%d",&Line_number) == 0) Line_number++;
clp[0] = 0;
len = 1;
continue;
}
Line_number++;
if ((len > 1) && (clp[len-2] == '\\')) {
len = len - 2;
clp[len] = '\0';
}
}
curlen += len;
} while (clp[len-1] != '\n');
if (curlen > 0) return AG.linebuf + 1;
else return NULL;
}
static char *
html_pair(char* p, agxbuf* tokp)
{
unsigned char c;
int depth = 1;
while (1) {
while ((c = *p)) {
if (c == '>') {
depth--;
if (depth == 0) return p;
}
else if (c == '<')
depth++;
agxbputc(tokp, c);
p++;
}
if ((p = lex_gets()) == NULL) {
agerr (AGWARN, "non-terminated HTML string starting line %d, file %s\n",
Start_html_string, InfileName);
return 0;
}
}
}
static char *
html_string(char* p, agxbuf* token)
{
Start_html_string = Line_number;
p = html_pair (p+1, token);
if (p) p++;
return p;
}
int agtoken(char* p)
{
TFA_Init();
while (*p) {
TFA_Advance(*p++);
}
return TFA_Definition();
}
int aglex(void)
{
int token;
char *tbuf,*p;
agxbuf xb;
if (AG.accepting_state) {
AG.accepting_state = FALSE;
return EOF;
}
do {
if ((LexPtr == NULL) || (LexPtr[0] == '\0'))
if ((LexPtr = lex_gets()) == NULL) {
if (In_comment) agerr (AGWARN, "nonterminated comment in line %d\n",Comment_start);
return EOF;
}
LexPtr = skip_wscomments(LexPtr);
} while (LexPtr[0] == '\0');
tbuf = TokenBuf;
if (LexPtr[0] == '\"') {
LexPtr = quoted_string(LexPtr,tbuf);
aglval.str = agstrdup(tbuf);
return T_qsymbol;
}
if (LexPtr[0] == '<') {
agxbinit (&xb, LineBufSize, (unsigned char*)TokenBuf);
LexPtr = html_string(LexPtr,&xb);
aglval.str = agstrdup_html(agxbuse(&xb));
agxbfree (&xb);
return T_symbol;
}
if (AG.edge_op && (strncmp(LexPtr,AG.edge_op,strlen(AG.edge_op)) == 0)) {
LexPtr += strlen(AG.edge_op);
return T_edgeop;
}
if ((p = scan_num(LexPtr,tbuf))) {
LexPtr = p;
aglval.str = agstrdup(tbuf);
return T_symbol;
}
else {
if (ispunct(LexPtr[0]) && (LexPtr[0] != '_'))
return *LexPtr++;
else LexPtr = scan_token(LexPtr,tbuf);
}
token = agtoken(tbuf);
if (token == -1) {
aglval.str = agstrdup(tbuf);
token = T_symbol;
}
return token;
}
static void error_context(void)
{
char *p;
char c;
char* buf = AG.linebuf+1;
if (LexPtr == NULL) return;
agerr (AGPREV, "context: ");
for (p = LexPtr - 1; (p > buf) && (isspace(*p) == FALSE); p--);
if (buf < p) {
c = *p;
*p = '\0';
agerr (AGPREV, buf);
*p = c;
}
agerr (AGPREV, " >>> ");
c = *LexPtr;
*LexPtr = '\0';
agerr (AGPREV, p);
*LexPtr = c;
agerr (AGPREV, " <<< ");
agerr (AGPREV, LexPtr);
}
void agerror(char *msg)
{
if (AG.syntax_errors++) return;
agerr (AGERR, "%s:%d: %s near line %d\n",
InfileName, Line_number, msg,Line_number);
error_context();
}
agerrlevel_t agerrno;
static agerrlevel_t agerrlevel = AGWARN;
static long aglast;
static FILE* agerrout;
void
agseterr (agerrlevel_t lvl)
{
agerrlevel = lvl;
}
char*
aglasterr ()
{
long endpos;
long len;
char* buf;
if (!agerrout) return 0;
fflush (agerrout);
endpos = ftell (agerrout);
len = endpos - aglast;
buf = malloc (len+1);
fseek (agerrout, aglast, SEEK_SET);
fread (buf, sizeof(char), len, agerrout);
buf[len] = '\0';
fseek (agerrout, endpos, SEEK_SET);
return buf;
}
int
agerr (agerrlevel_t level, char* fmt, ...)
{
va_list args;
agerrlevel_t lvl;
lvl = (level == AGPREV ? agerrno : (level == AGMAX) ? AGERR : level);
va_start(args, fmt);
agerrno = lvl;
if (lvl >= agerrlevel) {
if (level != AGPREV)
fprintf (stderr, "%s: ", (level == AGERR) ? "Error" : "Warning");
vfprintf(stderr, fmt, args);
va_end(args);
return 0;
}
if (!agerrout) {
agerrout = tmpfile ();
if (!agerrout) return 1;
}
if (level != AGPREV) aglast = ftell (agerrout);
vfprintf(agerrout, fmt, args);
va_end(args);
return 0;
}