/* next error will still return 1 by default */
%{
#include "y.tab.h"
#define FLEX_SCANNER
#include "lint.h"
#include "string.h"
#include "config.h"
#include "exec.h"
#include "interpret.h"
#include "instrs.h"
int strict_types_flag; /* not used with this lexical analyzer... */
int current_line;
int total_lines; /* Used to compute average compiled lines/s */
char *current_file;
extern char *argument_name;
int number(), lookupword(), string(), atoi();
/*
* Flex doesn't handle negative characters, but this change will at least
* not crash the game.
*/
#ifdef YY_FATAL_ERROR
#undef YY_FATAL_ERROR
#define YY_FATAL_ERROR(msg) \
{ \
fputs( msg, stderr ); \
putc( '\n', stderr ); \
error(msg); \
}
#endif
#ifdef FLEX
#define yywrap() 1
#endif
/*
* The number of arguments stated below, are used by the compiler.
* If min == max, then no information has to be coded about the
* actual number of arguments. Otherwise, the actual number of arguments
* will be stored in the byte after the instruction.
* A maximum value of -1 means unlimited maximum value.
*
* If an argument has type 0 (T_INVALID) specified, then no checks will
* be done at run time.
*/
static struct keyword {
char *word;
short token;
char min_args; /* Minimum number of arguments. */
char max_args; /* Maximum number of arguments. */
short ret_type; /* The return type used by the compiler. */
char arg_type1; /* Type of argument 1 */
char arg_type2; /* Type of argument 2 */
} predefs[] = {
#include "efuns.i"
};
/*
I have no idea what these were supposed to do -- Raistlin
{"add_adj" , F_ADD_ADJ },
{"add_subst" , F_ADD_SUBST },
*/
#define NELEM(a) (sizeof (a) / sizeof (a)[0])
static struct keyword reswords[] = {
{ "break", F_BREAK, },
{ "catch", F_CATCH, },
{ "continue", F_CONTINUE, },
{ "do", F_DO, },
{ "else", F_ELSE, },
{ "for", F_FOR, },
{ "if", F_IF, },
{ "inherit", F_INHERIT, },
{ "int", F_INT, },
{ "mixed", F_MIXED, },
{ "nomask", F_NO_MASK, },
{ "object", F_OBJECT, },
{ "parse_command", F_PARSE_COMMAND, },
{ "private", F_PRIVATE, },
{ "protected", F_PROTECTED, },
{ "public", F_PUBLIC, },
{ "return", F_RETURN, },
{ "sscanf", F_SSCANF, },
{ "static", F_STATIC, },
{ "status", F_STATUS, },
{ "string", F_STRING_DECL, },
{ "void", F_VOID, },
{ "while", F_WHILE, },
};
extern char *local_names[];
extern int current_number_of_locals;
extern char *string_copy();
void pre_processor_info();
%}
#ifdef LEX
%e 1500
%p 5000
%n 1000
%k 1000
%a 2500
%o 3000
#endif
dec (0|[1-9][0-9]*)
oct (0[0-7]+)
hex (0[xX][0-9a-fA-F]+)
ident ([_a-zA-Z][_a-zA-Z0-9]*)
string (\"([^"\\\n]|\\\n|\\.)*\")
%%
";" { return ';'; }
"(" { return '('; }
")" { return ')'; }
"," { return ','; }
"{" { return '{'; }
"}" { return '}'; }
"++" { return F_INC; }
"--" { return F_DEC; }
"?" { return '?'; }
":" { return ':'; }
"~" { return '~'; }
"&&" { return F_LAND; }
"&" { return '&'; }
"&=" { return F_AND_EQ; }
"||" { return F_LOR; }
"|" { return '|'; }
"|=" { return F_OR_EQ; }
"^" { return '^'; }
"^=" { return F_XOR_EQ; }
"<<" { return F_LSH; }
"<<=" { return F_LSH_EQ; }
">>" { return F_RSH; }
">>=" { return F_RSH_EQ; }
"!" { return F_NOT; }
"->" { return F_ARROW; }
"=" { return '='; }
"-" { return '-'; }
"-=" { return F_SUB_EQ; }
"+" { return '+'; }
"+=" { return F_ADD_EQ; }
"*" { return '*'; }
"*=" { return F_MULT_EQ; }
"%" { return '%'; }
"%=" { return F_MOD_EQ; }
"/" { return '/'; }
"/=" { return F_DIV_EQ; }
"<" { return '<'; }
">" { return '>'; }
">=" { return F_GE; }
"<=" { return F_LE; }
"==" { return F_EQ; }
"!=" { return F_NE; }
"::" { return F_COLON_COLON; }
^#.*$ { pre_processor_info(yytext); }
"[" { return '['; }
"]" { return ']'; }
{dec} { return dec(yytext); }
{hex} { return hex(yytext); }
{oct} { return oct(yytext); }
'.' { yylval.number = yytext[1];
return F_NUMBER; }
{ident} {
int i;
if ((i = lookup_resword(yytext)) >= 0)
return i;
return ident(yytext);
}
{string} { return string(yytext); }
[\t ] { break; }
"\n" { current_line++;
total_lines++;
store_line_number_info();
}
. { char buff[100]; sprintf(buff, "Illegal character '%c'", yytext[0]);
yyerror(buff); }
%%
extern YYSTYPE yylval;
#ifdef LEX
int yywrap() { return 1; }
#endif
/*
* debugging, gives the name of a single.
*/
int string(str)
char *str;
{
char *p;
p = (char *)string_copy(str);
yylval.string = p;
for (str++; str[1] != '\0'; str++, p++) {
if (str[0] == '\\' && str[1] == '\n')
str++, p--; /* ignore \n's at the end of a line -- R&R */
else
if (str[0] == '\\' && str[1] == 'n') {
*p = '\n';
str++;
} else if (str[0] == '\\' && str[1] == 't') {
*p = '\t';
str++;
} else if (str[0] == '\\' && str[1] == '"') { /* LA */
*p = '"'; /* LA */
str++; /* LA */
if (!str[1]) {
yyerror("Unterminated string");
break;
}
} else if (str[0] == '\\') {
*p = str[1];
str++;
} else
*p = *str;
}
*p = '\0';
return F_STRING;
}
int dec(str)
char *str;
{
int i;
i = atoi(str);
return number(i);
}
int hex(str)
char *str;
{
int i;
sscanf(str, "%x", &i);
return number(i);
}
int oct(str)
char *str;
{
int i;
sscanf(str, "%x", &i);
return number(i);
}
int number(i)
int i;
{
if (i == 0) {
yylval.number = 0;
return F_CONST0;
}
if (i == 1) {
yylval.number = 1;
return F_CONST1;
}
yylval.number = i;
return F_NUMBER;
}
void start_new_file(f)
FILE *f;
{
extern int yyprevious;
#ifdef FLEX
yy_init = 1;
#endif
#ifdef LEX
extern int yyprevious; /* KLUDGE! */
NLSTATE;
yysptr = yysbuf;
#endif
yyin = f;
}
void pre_processor_info(str)
char *str;
{
int line,i;
char file[100];
if (sscanf(str, "# %d \"%s\"", &line, file) != 2)
return;
i = strlen(file);
if (file[i-1] == '"')
file[i-1] = '\0';
free(current_file);
current_file = string_copy(file);
current_line = line - 1;
}
#if 0
#ifdef LEX
void fix_vars()
{
extern int yyprevious;
current_line = 0;
yyprevious = 10;
yylineno = 1;
yysptr = yysbuf;
}
#endif
#endif
struct instr instrs[256];
static void add_instr_name(name, n)
char *name;
int n;
{
instrs[n - F_OFFSET].name = name;
}
void init_num_args()
{
int i, n;
for(i=0; i<NELEM(predefs); i++) {
n = predefs[i].token - F_OFFSET;
if (n < 0 || n > NELEM(instrs))
fatal("Token %s has illegal value %d.\n", predefs[i].word, n);
instrs[n].min_arg = predefs[i].min_args;
instrs[n].max_arg = predefs[i].max_args;
instrs[n].name = predefs[i].word;
instrs[n].type[0] = predefs[i].arg_type1;
instrs[n].type[1] = predefs[i].arg_type2;
instrs[n].ret_type = predefs[i].ret_type;
}
add_instr_name("<", F_LT);
add_instr_name(">", F_GT);
add_instr_name("<=", F_LE);
add_instr_name(">=", F_GE);
add_instr_name("==", F_EQ);
add_instr_name("+=", F_ADD_EQ);
add_instr_name("!", F_NOT);
add_instr_name("index", F_INDEX_INSTR);
add_instr_name("push_indexed_lvalue", F_PUSH_INDEXED_LVALUE);
add_instr_name("identifier", F_IDENTIFIER);
add_instr_name("local", F_LOCAL_NAME);
add_instr_name("indirect", F_INDIRECT);
add_instr_name("number", F_NUMBER);
add_instr_name("push_local_variable_lvalue", F_PUSH_LOCAL_VARIABLE_LVALUE);
add_instr_name("const1", F_CONST1);
add_instr_name("subtract", F_SUBTRACT);
add_instr_name("assign", F_ASSIGN);
add_instr_name("pop", F_POP_VALUE);
add_instr_name("const0", F_CONST0);
add_instr_name("jump_when_zero", F_JUMP_WHEN_ZERO);
add_instr_name("jump_when_non_zero", F_JUMP_WHEN_NON_ZERO);
add_instr_name("||", F_LOR);
add_instr_name("&&", F_LAND);
add_instr_name("-=", F_SUB_EQ);
add_instr_name("jump", F_JUMP);
add_instr_name("return", F_RETURN);
add_instr_name("sscanf", F_SSCANF);
add_instr_name("string", F_STRING);
add_instr_name("call", F_CALL_FUNCTION_BY_ADDRESS);
add_instr_name("aggregate", F_AGGREGATE);
add_instr_name("push_identifier_lvalue", F_PUSH_IDENTIFIER_LVALUE);
add_instr_name("+", F_ADD);
add_instr_name("!=", F_NE);
add_instr_name("dup", F_DUP);
add_instr_name("catch", F_CATCH);
add_instr_name("neg", F_NEGATE);
}
char *get_f_name(n)
int n;
{
if (instrs[n-F_OFFSET].name)
return instrs[n-F_OFFSET].name;
return "<OTHER>";
}
static int
lookupword(s, words, h)
char *s;
struct keyword *words;
int h;
{
int i, l, r;
l = 0;
for(;;) {
i = (l+h)/2;
r = strcmp(s, words[i].word);
if (r == 0)
return words[i].token;
else if (l == i)
return -1;
else if (r < 0)
h = i;
else
l = i;
}
}
static int lookup_resword(s)
char *s;
{
return lookupword(s, reswords, NELEM(reswords));
}
int lookup_predef(s)
char *s;
{
return lookupword(s, predefs, NELEM(predefs));
}
static int islocal(str)
char *str;
{
int i;
for (i=current_number_of_locals-1; i>=0; i--) {
if (strcmp(local_names[i], str) == 0)
return i;
}
return -1;
}
static int ident(str)
char *str;
{
int i;
i = islocal(str);
if (i >= 0) {
yylval.number = i;
return F_LOCAL_NAME;
}
yylval.string = string_copy(str);
return F_IDENTIFIER;
}