quakeforge/tools/qfcc/source/qp-lex.l

306 lines
6.5 KiB
Text

%{
/*
qp-lex.l
lexer for QuakePascal
Copyright (C) 2011 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2011/01/06
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((used)) const char rcsid[] = "$Id$";
#include "QF/hash.h"
#include "debug.h"
#include "diagnostic.h"
#include "expr.h"
#include "grab.h"
#include "qfcc.h"
#include "strpool.h"
#include "symtab.h"
#include "type.h"
#include "qp-parse.h"
#ifndef YY_PROTO
# define YY_PROTO(x) x
#else
# define YY_FLEX_REALLOC_HACK
#endif
int yyget_lineno (void);
FILE *yyget_in (void);
FILE *yyget_out (void);
int yyget_leng (void);
char *yyget_text (void);
void yyset_lineno (int line_number);
void yyset_in (FILE * in_str);
void yyset_out (FILE * out_str);
int yyget_debug (void);
void yyset_debug (int bdebug);
int yylex_destroy (void);
#define YY_NO_UNPUT
#define YY_DECL int yylex YY_PROTO(( void ))
YY_DECL;
static int keyword_or_id (const char *token);
static int convert_relop (const char *relop);
%}
s [ \t]
m [\-+]
D [0-9]
X [0-9a-fA-F]
ID [a-zA-Z_][0-9a-zA-Z_]*
FLOAT ({D}+|{D}*\.{D}+|{D}+\.{D}*)([eE]{m}?{D}+)?
INTEGER ({D}+|0[xX]{X}+)
RELOP (=|<>|[<>]=?)
ADDOP [\-+]
MULOP [*/]
ASSIGNOP :=
RANGE \.\.
ELLIPSIS \.\.\.
FRAMEID {ID}(\.{ID})*
%x GRAB_FRAME GRAB_OTHER COMMENT
%%
grab_frame = GRAB_FRAME;
grab_other = GRAB_OTHER;
"{" { BEGIN (COMMENT); }
<COMMENT>"{" { warning (0, "nested { in comment"); }
<COMMENT>"}" { BEGIN (INITIAL); }
"(*" { BEGIN (COMMENT); }
<COMMENT>"(*" { warning (0, "nested (* in comment"); }
<COMMENT>"*)" { BEGIN (INITIAL); }
<COMMENT>\r*\n { pr.source_line++; }
<COMMENT>. /* nothing to do, with people like you */
<COMMENT><<EOF>> { error (0, "EOF in comment"); return 0; }
"//".* /* nothing to do, with people like you */
^#{s}+{D}+{s}+\"(\.|[^"\n])*\".*$ { line_info (yytext + 1); }
^#line{s}+{D}+{s}+\"(\.|[^"\n])*\".*$ { line_info (yytext + 1); }
{INTEGER} {
int i = strtol (yytext, 0, 0);
yylval.expr = new_integer_expr (i);
return CONST;
}
{FLOAT} {
float f = strtof (yytext, 0);
yylval.expr = new_float_expr (f);
return CONST;
}
{ID} return keyword_or_id (yytext);
\"(\\.|[^"\\])*\" {
const char *s = make_string (yytext, 0);
yylval.expr = new_string_expr (s);
return CONST;
}
'{s}*{m}{FLOAT}{s}+{m}{FLOAT}{s}+{m}{FLOAT}{s}*' {
vec3_t v;
sscanf (yytext, "' %f %f %f '",
&v[0], &v[1], &v[2]);
yylval.expr = new_vector_expr (v);
return CONST;
}
'{s}*{m}{FLOAT}{s}+{m}{FLOAT}{s}+{m}{FLOAT}{s}+{m}{FLOAT}{s}*' {
quat_t q;
sscanf (yytext, "' %f %f %f %f'",
&q[0], &q[1], &q[2], &q[3]);
yylval.expr = new_quaternion_expr (q);
return CONST;
}
{RELOP} {
yylval.op = convert_relop (yytext);
return RELOP;
}
{ADDOP} {
yylval.op = yytext[0];
return ADDOP;
}
{MULOP} {
yylval.op = yytext[0];
return MULOP;
}
{ASSIGNOP} return ASSIGNOP;
{RANGE} return RANGE;
{ELLIPSIS} return ELLIPSIS;
[!(){}.&|^~\[\];,#%?:] return yytext[0];
"$"{s}*{FRAMEID} {
int ret = do_grab (yytext);
if (ret >= 0) {
yylval.expr = new_integer_expr (ret);
return CONST;
} else {
BEGIN (-ret);
}
}
<GRAB_FRAME>{FRAMEID} add_frame_macro (yytext);
<GRAB_OTHER>[^\r\n]* /* skip */
<*>\r*\n {
pr.source_line++;
BEGIN (INITIAL);
}
<*>{s}* /* skip whitespace */
<*>. error (0, "all your typo are belong to us");
%%
int
yywrap (void)
{
return 1;
}
typedef struct {
const char *name;
int value;
type_t *type;
} keyword_t;
static keyword_t keywords[] = {
{"real", TYPE, &type_float},
{"string", TYPE, &type_string},
{"vector", TYPE, &type_vector},
{"entity", TYPE, &type_entity},
{"quaternion", TYPE, &type_quaternion},
{"integer", TYPE, &type_integer},
{"program", PROGRAM, 0},
{"var", VAR, 0},
{"array", ARRAY, 0},
{"of", OF, 0},
{"function", FUNCTION, 0},
{"procedure", PROCEDURE, 0},
{"begin", PBEGIN, 0},
{"end", END, 0},
{"if", IF, 0},
{"then", THEN, 0},
{"else", ELSE, 0},
{"while", WHILE, 0},
{"do", DO, 0},
{"or", ADDOP, 0},
{"div", MULOP, 0},
{"mod", MULOP, 0},
{"and", MULOP, 0},
{"not", NOT, 0},
};
static const char *
keyword_get_key (void *kw, void *unused)
{
return ((keyword_t *) kw)->name;
}
static int
keyword_or_id (const char *token)
{
static hashtab_t *keyword_tab;
keyword_t *keyword;
symbol_t *sym;
if (!keyword_tab) {
size_t i;
keyword_tab = Hash_NewTable (1021, keyword_get_key, 0, 0);
for (i = 0; i < sizeof (keywords) / sizeof (keywords[0]); i++)
Hash_Add (keyword_tab, &keywords[i]);
}
keyword = Hash_Find (keyword_tab, token);
if (keyword) {
if (keyword->value == ADDOP || keyword->value == MULOP) {
yylval.op = token[0];
} else {
yylval.type = keyword->type;
}
return keyword->value;
}
sym = symtab_lookup (current_symtab, token);
if (!sym)
sym = new_symbol (token);
if (sym->sy_type == sy_type) {
yylval.type = sym->type;
return TYPE_NAME;
}
yylval.symbol = sym;
return ID;
}
static int
convert_relop (const char *relop)
{
switch (relop[0]) {
case '=':
return EQ;
case '<':
switch (relop[1]) {
case 0:
return LT;
case '>':
return NE;
case '=':
return LE;
}
break;
case '>':
switch (relop[1]) {
case 0:
return GT;
case '=':
return GE;
}
break;
}
error (0, "internal: bad relop %s", relop);
return EQ;
}
#ifdef YY_FLEX_REALLOC_HACK
static __attribute__ ((used)) void *(*const yy_flex_realloc_hack)(void *,yy_size_t) = yy_flex_realloc;
#else
static __attribute__ ((used)) void (*yyunput_hack)(int, char*) = yyunput;
static __attribute__ ((used)) int (*input_hack)(void) = input;
#endif