From fed82466cc09881675acdc99912f4c7ef20c2f2f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 6 Jan 2011 16:32:53 +0900 Subject: [PATCH] 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. --- tools/qfcc/source/Makefile.am | 15 +- tools/qfcc/source/qp-lex.l | 242 ++++++++++++++++++++++++++++++ tools/qfcc/source/qp-parse.y | 268 ++++++++++++++++++++++++++++++++++ 3 files changed, 521 insertions(+), 4 deletions(-) create mode 100644 tools/qfcc/source/qp-lex.l create mode 100644 tools/qfcc/source/qp-parse.y diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index f4520f4e9..fc4b34b0f 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -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 diff --git a/tools/qfcc/source/qp-lex.l b/tools/qfcc/source/qp-lex.l new file mode 100644 index 000000000..095204813 --- /dev/null +++ b/tools/qfcc/source/qp-lex.l @@ -0,0 +1,242 @@ +%{ +/* + qp-lex.l + + lexer for QuakePascal + + Copyright (C) 2011 Bill Currie + + Author: Bill Currie + 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); } +"{" { warning (0, "nested { in comment"); } +"}" { BEGIN (INITIAL); } +\r*\n { pr.source_line++; } +. /* nothing to do, with people like you */ +<> { 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 + diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y new file mode 100644 index 000000000..77e27873c --- /dev/null +++ b/tools/qfcc/source/qp-parse.y @@ -0,0 +1,268 @@ +%{ +/* + qc-parse.y + + parser for quakec + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + 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 RELOP +%left ADDOP +%left MULOP +%right UNARY + +%token TYPE +%token ID +%token INT_VAL +%token STRING_VAL +%token QUATERNION_VAL +%token VECTOR_VAL +%token FLOAT_VAL + +%token PROGRAM VAR ARRAY OF FUNCTION PROCEDURE PBEGIN END IF THEN ELSE +%token WHILE DO RANGE ASSIGNOP NOT + +%type standard_type type +%type 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); } + ; + +%%