The first stages of Quake-Pascal.

At present, this parses a subset of the pascal language with a few type
extensions. There is already work on the type system.
This commit is contained in:
Bill Currie 2011-01-06 16:32:53 +09:00
parent ae4ca52661
commit fed82466cc
3 changed files with 521 additions and 4 deletions

View file

@ -37,17 +37,19 @@ YFLAGS = -v -d
if BUILD_QFCC
qfcc=qfcc
qfpc=qfpc
qfpreqcc=qfpreqcc
qfprogs=qfprogs
else
qfcc=
qfpc=
qfpreqcc=
qfprogs=
endif
bin_PROGRAMS= $(qfcc) $(qfprogs)
bin_PROGRAMS= $(qfcc) $(qfpc) $(qfprogs)
bin_SCRIPTS= $(qfpreqcc)
EXTRA_PROGRAMS= qfcc qfprogs
EXTRA_PROGRAMS= qfcc qfpc qfprogs
common_src=\
class.c constfold.c cpp.c debug.c def.c emit.c expr.c function.c grab.c \
@ -59,11 +61,16 @@ qfcc_SOURCES= qc-lex.l qc-parse.y $(common_src)
qfcc_LDADD= $(QFCC_LIBS)
qfcc_DEPENDENCIES= $(QFCC_DEPS)
qfpc_SOURCES= qp-lex.l qp-parse.y $(common_src)
qfpc_LDADD= $(QFCC_LIBS)
qfpc_DEPENDENCIES= $(QFCC_DEPS)
qfprogs_SOURCES= \
disassemble.c globals.c lines.c modules.c obj_file.c stub.c qfprogs.c strings.c
qfprogs_LDADD= $(QFCC_LIBS)
qfprogs_DEPENDENCIES= $(QFCC_DEPS)
BUILT_SOURCES=qc-parse.c qc-parse.h qc-lex.c
BUILT_SOURCES=qc-parse.c qc-parse.h qc-lex.c qp-parse.c qp-parse.h qp-lex.c
EXTRA_DIST=qc-lex.c qc-parse.c qc-parse.h qfpreqcc
EXTRA_DIST=qc-lex.c qc-parse.c qc-parse.h qfpreqcc \
qp-parse.c qp-parse.h qp-lex.c

242
tools/qfcc/source/qp-lex.l Normal file
View file

@ -0,0 +1,242 @@
%{
/*
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 "expr.h"
#include "grab.h"
#include "qfcc.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);
%}
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 \.\.
%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); }
<COMMENT>\r*\n { pr.source_line++; }
<COMMENT>. /* nothing to do, with people like you */
<COMMENT><<EOF>> { error (0, "EOF in comment"); return 0; }
^#{s}+{D}+{s}+\"(\.|[^"\n])*\".*$ { line_info (yytext + 1); }
^#line{s}+{D}+{s}+\"(\.|[^"\n])*\".*$ { line_info (yytext + 1); }
{INTEGER} {
yylval.integer_val = strtol (yytext, 0, 0);
return INT_VAL;
}
{FLOAT} {
yylval.float_val = strtof (yytext, 0);
return FLOAT_VAL;
}
{ID} return keyword_or_id (yytext);
\"(\\.|[^"\\])*\" {
yylval.string_val = make_string (yytext, 0);
return STRING_VAL;
}
'{s}*{m}{FLOAT}{s}+{m}{FLOAT}{s}+{m}{FLOAT}{s}*' {
sscanf (yytext, "' %f %f %f '",
&yylval.vector_val[0], &yylval.vector_val[1],
&yylval.vector_val[2]);
return VECTOR_VAL;
}
'{s}*{m}{FLOAT}{s}+{m}{FLOAT}{s}+{m}{FLOAT}{s}+{m}{FLOAT}{s}*' {
sscanf (yytext, "' %f %f %f %f '",
&yylval.quaternion_val[0],
&yylval.quaternion_val[1],
&yylval.quaternion_val[2],
&yylval.quaternion_val[3]);
return QUATERNION_VAL;
}
{RELOP} {
yylval.string_val = save_string (yytext);
return RELOP;
}
{ADDOP} {
yylval.integer_val = yytext[0];
return ADDOP;
}
{MULOP} {
yylval.integer_val = yytext[0];
return MULOP;
}
{ASSIGNOP} return ASSIGNOP;
{RANGE} return RANGE;
[!(){}.&|^~\[\];,#%?:] return yytext[0];
<*>\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},
{"prodedure", 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;
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.integer_val = yytext[0];
} else {
yylval.type = keyword->type;
}
return keyword->value;
}
yylval.string_val = save_string (token);
return ID;
}
#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

View file

@ -0,0 +1,268 @@
%{
/*
qc-parse.y
parser for quakec
Copyright (C) 2001 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2001/06/12
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 "class.h"
#include "expr.h"
#include "function.h"
#include "type.h"
#define YYDEBUG 1
#define YYERROR_VERBOSE 1
#undef YYERROR_VERBOSE
extern char *yytext;
static void
yyerror (const char *s)
{
#ifdef YYERROR_VERBOSE
error (0, "%s %s\n", yytext, s);
#else
error (0, "%s before %s", s, yytext);
#endif
}
static void
parse_error (void)
{
error (0, "parse error before %s", yytext);
}
#define PARSE_ERROR do { parse_error (); YYERROR; } while (0)
int yylex (void);
%}
%union {
int op;
struct def_s *def;
struct hashtab_s *def_list;
struct type_s *type;
struct typedef_s *typename;
struct expr_s *expr;
int integer_val;
unsigned uinteger_val;
float float_val;
const char *string_val;
float vector_val[3];
float quaternion_val[4];
struct function_s *function;
struct switch_block_s *switch_block;
struct param_s *param;
struct method_s *method;
struct class_s *class;
struct category_s *category;
struct class_type_s *class_type;
struct protocol_s *protocol;
struct protocollist_s *protocol_list;
struct keywordarg_s *keywordarg;
struct methodlist_s *methodlist;
struct struct_s *strct;
}
%nonassoc IFX
%nonassoc ELSE
%left <string_val> RELOP
%left <integer_val> ADDOP
%left <integer_val> MULOP
%right UNARY
%token <type> TYPE
%token <string_val> ID
%token <integer_val> INT_VAL
%token <string_val> STRING_VAL
%token <quaternion_val> QUATERNION_VAL
%token <vector_val> VECTOR_VAL
%token <float_val> FLOAT_VAL
%token PROGRAM VAR ARRAY OF FUNCTION PROCEDURE PBEGIN END IF THEN ELSE
%token WHILE DO RANGE ASSIGNOP NOT
%type <type> standard_type type
%type <expr> const num
%{
function_t *current_func;
class_type_t *current_class;
expr_t *local_expr;
scope_t *current_scope;
%}
%%
program
: program_header
declarations
subprogram_declarations
compound_statement
'.'
;
program_header
: PROGRAM ID '(' identifier_list ')' ';'
;
identifier_list
: ID
| identifier_list ',' ID
;
declarations
: declarations VAR identifier_list ':' type ';'
| /* empty */
;
type
: standard_type { $$ = $1; }
| ARRAY '[' num RANGE num ']' OF standard_type
{
int top = $5->e.integer_val;
int bot = $3->e.integer_val;
$$ = array_type ($8, top - bot + 1);
}
;
standard_type
: TYPE { $$ = $1; }
;
subprogram_declarations
: subprogram_declarations subprogram_declaration
| /* emtpy */
;
subprogram_declaration
: subprogram_head ';' declarations compound_statement ';'
| subprogram_head '=' '#' const ';'
;
subprogram_head
: FUNCTION ID arguments ':' standard_type
| PROCEDURE ID arguments
;
arguments
: '(' parameter_list ')'
| /* emtpy */
;
parameter_list
: identifier_list ':' type
| parameter_list ';' identifier_list ':' type
;
compound_statement
: PBEGIN optional_statements END
;
optional_statements
: statement_list
| /* emtpy */
;
statement_list
: statement
| statement_list ';' statement
;
statement
: variable ASSIGNOP expression
| procedure_statement
| compound_statement
| IF expression THEN statement ELSE statement
| IF expression THEN statement %prec IFX
| WHILE expression DO statement
;
variable
: ID
| ID '[' expression ']'
;
procedure_statement
: ID
| ID '(' expression_list ')'
;
expression_list
: expression
| expression_list ',' expression
;
unary_expr
: primary
| sign unary_expr %prec UNARY
| NOT expression %prec UNARY
;
primary
: variable
| const
| ID '(' expression_list ')'
| '(' expression ')'
;
expression
: unary_expr
| expression RELOP expression
| expression ADDOP expression
| expression MULOP expression
;
sign
: ADDOP
{
if ($1 == 'o')
PARSE_ERROR;
}
;
const
: num
| STRING_VAL { $$ = new_string_expr ($1); }
;
num
: INT_VAL { $$ = new_integer_expr ($1); }
| FLOAT_VAL { $$ = new_float_expr ($1); }
| VECTOR_VAL { $$ = new_vector_expr ($1); }
| QUATERNION_VAL { $$ = new_quaternion_expr ($1); }
;
%%