# include "jam.h"
# include "lists.h"
# include "parse.h"
# include "scan.h"
# include "jamgram.h"
# include "jambase.h"
# include "newstr.h"
struct keyword {
char *word;
int type;
} keywords[] = {
#ifdef FATFS
# include "jamgramt.h"
#else
# include "jamgramtab.h"
#endif
{ 0, 0 }
} ;
struct include {
struct include *next;
char *string;
char **strings;
FILE *file;
char *fname;
int line;
char buf[ 512 ];
} ;
static struct include *incp = 0;
static int scanmode = SCAN_NORMAL;
static int anyerrors = 0;
static char *symdump();
# define BIGGEST_TOKEN 10240
void
yymode( n )
int n;
{
scanmode = n;
}
void
yyerror( s )
char *s;
{
if( incp )
printf( "%s: line %d: ", incp->fname, incp->line );
printf( "%s at %s\n", s, symdump( &yylval ) );
++anyerrors;
}
int
yyanyerrors()
{
return anyerrors != 0;
}
void
yyfparse( s )
char *s;
{
struct include *i = (struct include *)malloc( sizeof( *i ) );
i->string = "";
i->strings = 0;
i->file = 0;
i->fname = copystr( s );
i->line = 0;
i->next = incp;
incp = i;
if( !strcmp( s, "+" ) )
i->strings = jambase;
}
int
yyline()
{
struct include *i = incp;
if( !incp )
return EOF;
if( *i->string )
return *i->string++;
if( i->strings )
{
if( !*i->strings )
goto next;
i->line++;
i->string = *(i->strings++);
return *i->string++;
}
if( !i->file )
{
FILE *f = stdin;
if( strcmp( i->fname, "-" ) && !( f = fopen( i->fname, "r" ) ) )
perror( i->fname );
i->file = f;
}
if( i->file && fgets( i->buf, sizeof( i->buf ), i->file ) )
{
i->line++;
i->string = i->buf;
return *i->string++;
}
next:
incp = i->next;
if( i->file && i->file != stdin )
fclose( i->file );
freestr( i->fname );
free( (char *)i );
return EOF;
}
# define yychar() ( *incp->string ? *incp->string++ : yyline() )
# define yyprev() ( incp->string-- )
int
yylex()
{
int c;
char buf[BIGGEST_TOKEN];
char *b = buf;
if( !incp )
goto eof;
c = yychar();
if( scanmode == SCAN_STRING )
{
int nest = 1;
while( c != EOF && b < buf + sizeof( buf ) )
{
if( c == '{' )
nest++;
if( c == '}' && !--nest )
break;
*b++ = c;
c = yychar();
}
if( c != EOF )
yyprev();
if( b == buf + sizeof( buf ) )
{
yyerror( "action block too big" );
goto eof;
}
if( nest )
{
yyerror( "unmatched {} in action block" );
goto eof;
}
*b = 0;
yylval.type = STRING;
yylval.string = newstr( buf );
}
else
{
char *b = buf;
int inquote = 0;
int literal = 0;
int hasquote = 0;
struct keyword *k;
for( ;; )
{
while( c != EOF && isspace( c ) )
c = yychar();
if( c != '#' )
break;
while( ( c = yychar() ) != EOF && c != '\n' )
;
}
if( c == EOF )
goto eof;
while( b < buf + sizeof( buf ) )
{
if( literal )
*b++ = c, literal = 0;
else if( c == '\\' )
literal++;
else if( c == '"' )
inquote = !inquote, hasquote++;
else
*b++ = c;
if( ( c = yychar() ) == EOF || (!inquote && isspace( c )) )
break;
}
if( b == buf + sizeof( buf ) )
{
yyerror( "string too big" );
goto eof;
}
if( inquote )
{
yyerror( "unmatched \" in string" );
goto eof;
}
if( c != EOF )
yyprev();
*b = 0;
yylval.type = ARG;
if( !hasquote &&
*buf != '$' &&
!( isalpha( *buf ) && scanmode == SCAN_PUNCT ) )
{
for( k = keywords; k->word; k++ )
if( *buf == *k->word && !strcmp( k->word, buf ) )
{
yylval.type = k->type;
yylval.string = k->word;
break;
}
}
if( yylval.type == ARG )
yylval.string = newstr( buf );
}
if( DEBUG_SCAN )
printf( "scan %s\n", symdump( &yylval ) );
return yylval.type;
eof:
yylval.type = EOF;
return yylval.type;
}
static char *
symdump( s )
YYSTYPE *s;
{
static char buf[ BIGGEST_TOKEN + 20 ];
switch( s->type )
{
case EOF:
sprintf( buf, "EOF" );
break;
case 0:
sprintf( buf, "unknown symbol %s", s->string );
break;
case ARG:
sprintf( buf, "argument %s", s->string );
break;
case STRING:
sprintf( buf, "string \"%s\"", s->string );
break;
default:
sprintf( buf, "keyword %s", s->string );
break;
}
return buf;
}