Merge qfpc into qfcc.

Since gnu bison and flex are required anyway, no harm in using their api
prefix options. Now, qfcc can compile both QC/Ruamoko and Pascal files
(Pascal is (currently?) NOT supported in progs.src mode), selecting the
language based on the extension: .r, .qc and .c select QC/Ruamoko, .pas and
.p select Pascal, while anything else is treated as an object file (as
before).
This commit is contained in:
Bill Currie 2012-10-26 16:01:41 +09:00
parent 6e04fd5ff6
commit f14d8060e0
12 changed files with 272 additions and 156 deletions

View file

@ -120,9 +120,12 @@ extern struct symtab_s *current_symtab;
const char *strip_path (const char *filename);
void clear_frame_macros (void);
extern FILE *yyin;
int yyparse (void);
extern int yydebug;
extern FILE *qc_yyin;
extern FILE *qp_yyin;
int qc_yyparse (void);
int qp_yyparse (void);
extern int qc_yydebug;
extern int qp_yydebug;
#ifdef _WIN32
char *fix_backslash (char *path);

View file

@ -0,0 +1,44 @@
/*
shared.h
Functions and data shared between languages.
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2012/10/26
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
*/
#ifndef __shared_h
#define __shared_h
extern struct function_s *current_func;
extern struct class_type_s *current_class;
extern struct expr_s *local_expr;
extern enum vis_e current_visibility;
extern enum storage_class_e current_storage;
extern struct symtab_s *current_symtab;
struct symbol_s *check_redefined (struct symbol_s *sym);
extern struct symbol_s *check_undefined (struct symbol_s *sym);
#endif//__shared_h

View file

@ -41,11 +41,11 @@ enum storage_class_e;
*/
//@{
typedef enum {
typedef enum vis_e {
vis_public,
vis_protected,
vis_private,
} vis_e;
} vis_t;
typedef enum {
sy_var, ///< symbol refers to a variable
@ -59,7 +59,7 @@ typedef enum {
typedef struct symbol_s {
struct symbol_s *next; ///< chain of symbols in symbol table
struct symtab_s *table; ///< symbol table that owns this symbol
vis_e visibility; ///< symbol visiblity. defaults to public
vis_t visibility; ///< symbol visiblity. defaults to public
const char *name; ///< symbol name
sy_type_e sy_type; ///< symbol type (st_type)
struct type_s *type; ///< type of object to which symbol refers

View file

@ -35,24 +35,20 @@ QFCC_INCS=@QFCC_INCS@
INCLUDES= -I$(top_srcdir)/include $(QFCC_INCS)
YFLAGS = -v -d
bin_PROGRAMS= qfcc qfpc qfprogs
bin_PROGRAMS= qfcc qfprogs
bin_SCRIPTS= qfpreqcc
common_src=\
class.c codespace.c constfold.c cpp.c debug.c def.c defspace.c \
diagnostic.c dot_expr.c dot_flow.c emit.c expr.c function.c grab.c \
idstuff.c linker.c method.c obj_file.c obj_type.c opcodes.c options.c \
qfcc.c reloc.c statements.c strpool.c struct.c switch.c symtab.c type.c \
value.c
qfcc.c reloc.c shared.c statements.c strpool.c struct.c switch.c symtab.c \
type.c value.c
qfcc_SOURCES= qc-lex.l qc-parse.y $(common_src)
qfcc_SOURCES= qc-lex.l qc-parse.y qp-lex.l qp-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 dump_globals.c dump_lines.c dump_modules.c obj_file.c \
stub.c qfprogs.c dump_strings.c
@ -61,5 +57,14 @@ qfprogs_DEPENDENCIES= $(QFCC_DEPS)
BUILT_SOURCES=qc-parse.c qc-parse.h qc-lex.c qp-parse.c qp-parse.h qp-lex.c
qc-parse.c: qc-parse.y
$(YACC) $(YFLAGS) -Dapi.prefix=qc_yy $< -o $@
qc-lex.c: qc-lex.l
$(LEX) $(LFLAGS) $(AM_LFLAGS) -Pqc_yy -o$@ $<
qp-parse.c: qp-parse.y
$(YACC) $(YFLAGS) -Dapi.prefix=qp_yy $< -o $@
qp-lex.c: qp-lex.l
$(LEX) $(LFLAGS) $(AM_LFLAGS) -Pqp_yy -o$@ $<
EXTRA_DIST=qc-lex.c qc-parse.c qc-parse.h qfpreqcc \
qp-parse.c qp-parse.h qp-lex.c

View file

@ -763,7 +763,7 @@ class_find_ivar (class_t *class, int vis, const char *name)
ivar = symtab_lookup (class->ivars, name);
if (ivar) {
if (ivar->visibility > (vis_e) vis)
if (ivar->visibility > (vis_t) vis)
goto access_error;
return ivar;
}

View file

@ -642,7 +642,9 @@ DecodeArgs (int argc, char **argv)
linker_add_path (QFCC_LIB_PATH);
}
if (options.verbosity >= 3)
yydebug = 1;
if (options.verbosity >= 3) {
qc_yydebug = 1;
qp_yydebug = 1;
}
return optind;
}

View file

@ -84,7 +84,7 @@ YY_DECL;
static int keyword_or_id (char *token);
extern YYSTYPE yylval;
extern QC_YYSTYPE qc_yylval;
%}
@ -123,15 +123,15 @@ STRING \"(\\.|[^"\\])*\"
const char *c = yytext + yyleng - 1;
int i = strtol (yytext, 0, 0);
if (*c == 'u' || *c == 'U')
yylval.expr = new_integer_expr (i);//FIXME
qc_yylval.expr = new_integer_expr (i);//FIXME
else
yylval.expr = new_integer_expr (i);
qc_yylval.expr = new_integer_expr (i);
return CONST;
}
{FLOAT} {
float f = strtof (yytext, 0);
yylval.expr = new_float_expr (f);
qc_yylval.expr = new_float_expr (f);
return CONST;
}
@ -148,7 +148,7 @@ STRING \"(\\.|[^"\\])*\"
{STRING} {
const char *s = make_string (yytext, 0);
yylval.expr = new_string_expr (s);
qc_yylval.expr = new_string_expr (s);
return STRING;
}
@ return '@';
@ -157,7 +157,7 @@ STRING \"(\\.|[^"\\])*\"
vec3_t v;
sscanf (yytext, "' %f %f %f '",
&v[0], &v[1], &v[2]);
yylval.expr = new_vector_expr (v);
qc_yylval.expr = new_vector_expr (v);
return CONST;
}
@ -165,7 +165,7 @@ STRING \"(\\.|[^"\\])*\"
quat_t q;
sscanf (yytext, "' %f %f %f %f'",
&q[0], &q[1], &q[2], &q[3]);
yylval.expr = new_quaternion_expr (q);
qc_yylval.expr = new_quaternion_expr (q);
return CONST;
}
@ -174,27 +174,27 @@ STRING \"(\\.|[^"\\])*\"
if (str[1])
warning (0, "multibyte char constant");
yylval.expr = new_integer_expr (*str);
qc_yylval.expr = new_integer_expr (*str);
return CONST;
}
[+\-*/&|^%]= {
yylval.op = yytext[0];
qc_yylval.op = yytext[0];
return ASX;
}
"<<=" {
yylval.op = SHL;
qc_yylval.op = SHL;
return ASX;
}
">>=" {
yylval.op = SHR;
qc_yylval.op = SHR;
return ASX;
}
[!(){}.*/&|^~+\-=\[\];,#%?:] {
yylval.pointer = 0; // ensure pointer values are null
qc_yylval.pointer = 0; // ensure pointer vals are null
return yytext[0];
}
@ -213,19 +213,19 @@ STRING \"(\\.|[^"\\])*\"
">" return GT;
"++" {
yylval.op = '+';
qc_yylval.op = '+';
return INCOP;
}
"--" {
yylval.op = '-';
qc_yylval.op = '-';
return INCOP;
}
"$"{s}*{FRAMEID} {
int ret = do_grab (yytext);
if (ret >= 0) {
yylval.expr = new_integer_expr (ret);
qc_yylval.expr = new_integer_expr (ret);
return CONST;
} else {
BEGIN (-ret);
@ -352,10 +352,10 @@ keyword_or_id (char *token)
class_init ();
if (keyword->value) {
if (keyword->value == STRUCT) {
yylval.op = token[0];
qc_yylval.op = token[0];
} else {
yylval.type = 0;
yylval.type = keyword->type;
qc_yylval.type = 0;
qc_yylval.type = keyword->type;
}
return keyword->value;
}
@ -366,7 +366,7 @@ keyword_or_id (char *token)
sym = symtab_lookup (current_symtab, token);
if (!sym)
sym = new_symbol (token);
yylval.symbol = sym;
qc_yylval.symbol = sym;
if (sym->sy_type == sy_type)
return TYPE_NAME;
if (sym->sy_type == sy_class)

View file

@ -54,6 +54,7 @@
#include "options.h"
#include "qfcc.h"
#include "reloc.h"
#include "shared.h"
#include "strpool.h"
#include "struct.h"
#include "switch.h"
@ -65,22 +66,22 @@
#define YYERROR_VERBOSE 1
#undef YYERROR_VERBOSE
extern char *yytext;
extern char *qc_yytext;
static void
yyerror (const char *s)
{
#ifdef YYERROR_VERBOSE
error (0, "%s %s\n", yytext, s);
error (0, "%s %s\n", qc_yytext, s);
#else
error (0, "%s before %s", s, yytext);
error (0, "%s before %s", s, qc_yytext);
#endif
}
static void
parse_error (void)
{
error (0, "parse error before %s", yytext);
error (0, "parse error before %s", qc_yytext);
}
#define PARSE_ERROR do { parse_error (); YYERROR; } while (0)
@ -205,47 +206,10 @@ int yylex (void);
%{
function_t *current_func;
class_type_t *current_class;
expr_t *local_expr;
vis_e current_visibility;
storage_class_t current_storage = st_global;
symtab_t *current_symtab;
static switch_block_t *switch_block;
static expr_t *break_label;
static expr_t *continue_label;
/* When defining a new symbol, already existing symbols must be in a
different scope. However, when they are in a different scope, we want a
truly new symbol.
*/
static symbol_t *
check_redefined (symbol_t *sym)
{
if (sym->table == current_symtab)
error (0, "%s redefined", sym->name);
if (sym->table) // truly new symbols are not in any symbol table
sym = new_symbol (sym->name);
return sym;
}
/* Check for undefined symbols. If the symbol is undefined, default its type
to float or int, depending on compiler mode.
*/
static symbol_t *
check_undefined (symbol_t *sym)
{
if (!sym->table) { // truly new symbols are not in any symbol table
error (0, "%s undefined", sym->name);
if (options.code.progsversion == PROG_ID_VERSION)
sym->type = &type_float;
else
sym->type = &type_integer;
}
return sym;
}
static specifier_t
make_spec (type_t *type, storage_class_t storage, int is_typedef,
int is_overload)
@ -1734,28 +1698,28 @@ keywordselector
selector
: NAME { $$ = $1; }
| CLASS_NAME { $$ = $1; }
| TYPE { $$ = new_symbol (yytext); }
| TYPE { $$ = new_symbol (qc_yytext); }
| TYPE_NAME { $$ = $1; }
| reserved_word
;
reserved_word
: LOCAL { $$ = new_symbol (yytext); }
| RETURN { $$ = new_symbol (yytext); }
| WHILE { $$ = new_symbol (yytext); }
| DO { $$ = new_symbol (yytext); }
| IF { $$ = new_symbol (yytext); }
| ELSE { $$ = new_symbol (yytext); }
| FOR { $$ = new_symbol (yytext); }
| BREAK { $$ = new_symbol (yytext); }
| CONTINUE { $$ = new_symbol (yytext); }
| SWITCH { $$ = new_symbol (yytext); }
| CASE { $$ = new_symbol (yytext); }
| DEFAULT { $$ = new_symbol (yytext); }
| NIL { $$ = new_symbol (yytext); }
| STRUCT { $$ = new_symbol (yytext); }
| ENUM { $$ = new_symbol (yytext); }
| TYPEDEF { $$ = new_symbol (yytext); }
: LOCAL { $$ = new_symbol (qc_yytext); }
| RETURN { $$ = new_symbol (qc_yytext); }
| WHILE { $$ = new_symbol (qc_yytext); }
| DO { $$ = new_symbol (qc_yytext); }
| IF { $$ = new_symbol (qc_yytext); }
| ELSE { $$ = new_symbol (qc_yytext); }
| FOR { $$ = new_symbol (qc_yytext); }
| BREAK { $$ = new_symbol (qc_yytext); }
| CONTINUE { $$ = new_symbol (qc_yytext); }
| SWITCH { $$ = new_symbol (qc_yytext); }
| CASE { $$ = new_symbol (qc_yytext); }
| DEFAULT { $$ = new_symbol (qc_yytext); }
| NIL { $$ = new_symbol (qc_yytext); }
| STRUCT { $$ = new_symbol (qc_yytext); }
| ENUM { $$ = new_symbol (qc_yytext); }
| TYPEDEF { $$ = new_symbol (qc_yytext); }
;
keyworddecl

View file

@ -60,6 +60,7 @@
#include <QF/dstring.h>
#include <QF/hash.h>
#include <QF/qendian.h>
#include <QF/quakefs.h>
#include <QF/script.h>
#include <QF/sys.h>
#include <QF/va.h>
@ -95,6 +96,17 @@ const char *progs_src;
pr_info_t pr;
typedef enum {
lang_object,
lang_ruamoko,
lang_pascal,
} lang_t;
typedef struct ext_lang_s {
const char *ext;
lang_t lang;
} ext_lang_t;
#ifdef _WIN32
char *
fix_backslash (char *path)
@ -307,12 +319,27 @@ setup_sym_file (const char *output_file)
}
static int
compile_to_obj (const char *file, const char *obj)
compile_to_obj (const char *file, const char *obj, lang_t lang)
{
int err;
FILE **yyin;
int (*yyparse) (void);
yyin = preprocess_file (file, 0);
if (!yyin)
switch (lang) {
case lang_ruamoko:
yyin = &qc_yyin;
yyparse = qc_yyparse;
break;
case lang_pascal:
yyin = &qp_yyin;
yyparse = qp_yyparse;
break;
default:
internal_error (0, "unknown language enum");
}
*yyin = preprocess_file (file, 0);
if (!*yyin)
return !options.preprocess_only;
InitData ();
@ -324,7 +351,7 @@ compile_to_obj (const char *file, const char *obj)
begin_compilation ();
pr.source_file = ReuseString (strip_path (file));
err = yyparse () || pr.error_count;
fclose (yyin);
fclose (*yyin);
if (cpp_name && !options.save_temps) {
if (unlink (tempname->str)) {
perror ("unlink");
@ -397,14 +424,35 @@ finish_link (void)
return 0;
}
static lang_t
file_language (const char *file, const char *ext)
{
static ext_lang_t ext_lang[] = {
{".r", lang_ruamoko},
{".c", lang_ruamoko},
{".qc", lang_ruamoko},
{".pas", lang_pascal},
{".p", lang_pascal},
{0, lang_object}, // unrecognized extension = object file
};
ext_lang_t *el;
if (strncmp (file, "-l", 2) == 0)
return lang_object;
for (el = ext_lang; el->ext; el++)
if (strcmp (ext, el->ext) == 0)
break;
return el->lang;
}
static int
separate_compile (void)
{
const char **file;
const char **file, *ext;
const char **temp_files;
lang_t lang;
dstring_t *output_file = dstring_newstr ();
dstring_t *extension = dstring_newstr ();
char *f;
int err = 0;
int i;
@ -420,32 +468,21 @@ separate_compile (void)
temp_files = calloc (i + 1, sizeof (const char*));
for (file = source_files, i = 0; *file; file++) {
dstring_clearstr (extension);
dstring_clearstr (output_file);
ext = QFS_FileExtension (*file);
dstring_copysubstr (output_file, *file, ext - *file);
dstring_copystr (extension, ext);
dstring_appendstr (output_file, *file);
f = output_file->str + strlen (output_file->str);
while (f >= output_file->str && *f != '.' && *f != '/')
f--;
if (f >= output_file->str && *f == '.') {
output_file->size -= strlen (f);
dstring_appendstr (extension, f);
*f = 0;
}
if (options.compile && options.output_file) {
dstring_clearstr (output_file);
dstring_appendstr (output_file, options.output_file);
} else {
dstring_appendstr (output_file, ".qfo");
}
if (strncmp (*file, "-l", 2)
&& (!strcmp (extension->str, ".r")
|| !strcmp (extension->str, ".qc")
|| !strcmp (extension->str, ".c"))) {
if ((lang = file_language (*file, extension->str)) != lang_object) {
if (options.verbosity >= 2)
printf ("%s %s\n", *file, output_file->str);
temp_files[i++] = save_string (output_file->str);
err = compile_to_obj (*file, output_file->str) || err;
err = compile_to_obj (*file, output_file->str, lang) || err;
free ((char *)*file);
*file = strdup (output_file->str);
@ -530,16 +567,18 @@ static int
compile_file (const char *filename)
{
int err;
FILE **yyin = &qc_yyin;
int (*yyparse) (void) = qc_yyparse;
yyin = preprocess_file (filename, 0);
if (!yyin)
*yyin = preprocess_file (filename, 0);
if (!*yyin)
return !options.preprocess_only;
pr.source_file = ReuseString (strip_path (filename));
pr.source_line = 1;
clear_frame_macros ();
err = yyparse () || pr.error_count;
fclose (yyin);
fclose (*yyin);
if (cpp_name && (!options.save_temps)) {
if (unlink (tempname->str)) {
perror ("unlink");

View file

@ -109,13 +109,13 @@ FRAMEID {ID}(\.{ID})*
{INTEGER} {
int i = strtol (yytext, 0, 0);
yylval.expr = new_integer_expr (i);
qp_yylval.expr = new_integer_expr (i);
return CONST;
}
{FLOAT} {
float f = strtof (yytext, 0);
yylval.expr = new_float_expr (f);
qp_yylval.expr = new_float_expr (f);
return CONST;
}
@ -123,7 +123,7 @@ FRAMEID {ID}(\.{ID})*
\"(\\.|[^"\\])*\" {
const char *s = make_string (yytext, 0);
yylval.expr = new_string_expr (s);
qp_yylval.expr = new_string_expr (s);
return CONST;
}
@ -131,7 +131,7 @@ FRAMEID {ID}(\.{ID})*
vec3_t v;
sscanf (yytext, "' %f %f %f '",
&v[0], &v[1], &v[2]);
yylval.expr = new_vector_expr (v);
qp_yylval.expr = new_vector_expr (v);
return CONST;
}
@ -139,20 +139,20 @@ FRAMEID {ID}(\.{ID})*
quat_t q;
sscanf (yytext, "' %f %f %f %f'",
&q[0], &q[1], &q[2], &q[3]);
yylval.expr = new_quaternion_expr (q);
qp_yylval.expr = new_quaternion_expr (q);
return CONST;
}
{RELOP} {
yylval.op = convert_relop (yytext);
qp_yylval.op = convert_relop (yytext);
return RELOP;
}
{ADDOP} {
yylval.op = yytext[0];
qp_yylval.op = yytext[0];
return ADDOP;
}
{MULOP} {
yylval.op = yytext[0];
qp_yylval.op = yytext[0];
return MULOP;
}
@ -166,7 +166,7 @@ FRAMEID {ID}(\.{ID})*
"$"{s}*{FRAMEID} {
int ret = do_grab (yytext);
if (ret >= 0) {
yylval.expr = new_integer_expr (ret);
qp_yylval.expr = new_integer_expr (ret);
return CONST;
} else {
BEGIN (-ret);
@ -251,9 +251,9 @@ keyword_or_id (const char *token)
keyword = Hash_Find (keyword_tab, token);
if (keyword) {
if (keyword->value == ADDOP || keyword->value == MULOP) {
yylval.op = token[0];
qp_yylval.op = token[0];
} else {
yylval.type = keyword->type;
qp_yylval.type = keyword->type;
}
return keyword->value;
}
@ -261,10 +261,10 @@ keyword_or_id (const char *token)
if (!sym)
sym = new_symbol (token);
if (sym->sy_type == sy_type) {
yylval.type = sym->type;
qp_yylval.type = sym->type;
return TYPE_NAME;
}
yylval.symbol = sym;
qp_yylval.symbol = sym;
return ID;
}

View file

@ -47,6 +47,7 @@
#include "function.h"
#include "qfcc.h"
#include "reloc.h"
#include "shared.h"
#include "symtab.h"
#include "type.h"
@ -54,22 +55,22 @@
#define YYERROR_VERBOSE 1
#undef YYERROR_VERBOSE
extern char *yytext;
extern char *qp_yytext;
static void
yyerror (const char *s)
{
#ifdef YYERROR_VERBOSE
error (0, "%s %s\n", yytext, s);
error (0, "%s %s\n", qp_yytext, s);
#else
error (0, "%s before %s", s, yytext);
error (0, "%s before %s", s, qp_yytext);
#endif
}
static void
parse_error (void)
{
error (0, "parse error before %s", yytext);
error (0, "parse error before %s", qp_yytext);
}
#define PARSE_ERROR do { parse_error (); YYERROR; } while (0)
@ -136,26 +137,6 @@ int yylex (void);
%type <op> sign
%{
symtab_t *current_symtab;
storage_class_t current_storage = st_global;
function_t *current_func;
struct class_type_s *current_class;
expr_t *local_expr;
param_t *current_params;
/* When defining a new symbol, already existing symbols must be in a
different scope. However, when they are in a different scope, we want a
truly new symbol.
*/
static symbol_t *
check_redefined (symbol_t *sym)
{
if (sym->table == current_symtab)
error (0, "%s redefined", sym->name);
if (sym->table) // truly new symbols are not in any symbol table
sym = new_symbol (sym->name);
return sym;
}
%}
%%

View file

@ -0,0 +1,78 @@
/*
qc-parse.y
parser for quakec
Copyright (C) 2012 Bill Currie <bill@taniwha.org>
Author: Bill Currie <bill@taniwha.org>
Date: 2012/10/26
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
#include "class.h"
#include "diagnostic.h"
#include "expr.h"
#include "function.h"
#include "options.h"
#include "shared.h"
#include "symtab.h"
#include "type.h"
function_t *current_func;
class_type_t *current_class;
expr_t *local_expr;
vis_t current_visibility;
storage_class_t current_storage = st_global;
symtab_t *current_symtab;
/* When defining a new symbol, already existing symbols must be in a
different scope. However, when they are in a different scope, we want a
truly new symbol.
*/
symbol_t *
check_redefined (symbol_t *sym)
{
if (sym->table == current_symtab)
error (0, "%s redefined", sym->name);
if (sym->table) // truly new symbols are not in any symbol table
sym = new_symbol (sym->name);
return sym;
}
/* Check for undefined symbols. If the symbol is undefined, default its type
to float or int, depending on compiler mode.
*/
symbol_t *
check_undefined (symbol_t *sym)
{
if (!sym->table) { // truly new symbols are not in any symbol table
error (0, "%s undefined", sym->name);
if (options.code.progsversion == PROG_ID_VERSION)
sym->type = &type_float;
else
sym->type = &type_integer;
}
return sym;
}