diff options
author | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
---|---|---|
committer | Stan Shebs <shebs@codesourcery.com> | 1999-04-16 01:35:26 +0000 |
commit | c906108c21474dfb4ed285bcc0ac6fe02cd400cc (patch) | |
tree | a0015aa5cedc19ccbab307251353a41722a3ae13 /gdb/m2-exp.y | |
parent | cd946cff9ede3f30935803403f06f6ed30cad136 (diff) | |
download | gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.zip gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.gz gdb-c906108c21474dfb4ed285bcc0ac6fe02cd400cc.tar.bz2 |
Initial creation of sourceware repositorygdb-4_18-branchpoint
Diffstat (limited to 'gdb/m2-exp.y')
-rw-r--r-- | gdb/m2-exp.y | 1094 |
1 files changed, 1094 insertions, 0 deletions
diff --git a/gdb/m2-exp.y b/gdb/m2-exp.y new file mode 100644 index 0000000..507e5bc --- /dev/null +++ b/gdb/m2-exp.y @@ -0,0 +1,1094 @@ +/* YACC grammar for Modula-2 expressions, for GDB. + Copyright (C) 1986, 1989, 1990, 1991, 1993, 1994, 1995 + Free Software Foundation, Inc. + Generated from expread.y (now c-exp.y) and contributed by the Department + of Computer Science at the State University of New York at Buffalo, 1991. + +This file is part of GDB. + +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 the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Parse a Modula-2 expression from text in a string, + and return the result as a struct expression pointer. + That structure contains arithmetic operations in reverse polish, + with constants represented by operations that are followed by special data. + See expression.h for the details of the format. + What is important here is that it can be built up sequentially + during the process of parsing; the lower levels of the tree always + come first in the result. + + Note that malloc's and realloc's in this file are transformed to + xmalloc and xrealloc respectively by the same sed command in the + makefile that remaps any other malloc/realloc inserted by the parser + generator. Doing this with #defines and trying to control the interaction + with include files (<malloc.h> and <stdlib.h> for example) just became + too messy, particularly when such includes can be inserted at random + times by the parser generator. */ + +%{ + +#include "defs.h" +#include "gdb_string.h" +#include "expression.h" +#include "language.h" +#include "value.h" +#include "parser-defs.h" +#include "m2-lang.h" +#include "bfd.h" /* Required by objfiles.h. */ +#include "symfile.h" /* Required by objfiles.h. */ +#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */ + +/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc), + as well as gratuitiously global symbol names, so we can have multiple + yacc generated parsers in gdb. Note that these are only the variables + produced by yacc. If other parser generators (bison, byacc, etc) produce + additional global names that conflict at link time, then those parser + generators need to be fixed instead of adding those names to this list. */ + +#define yymaxdepth m2_maxdepth +#define yyparse m2_parse +#define yylex m2_lex +#define yyerror m2_error +#define yylval m2_lval +#define yychar m2_char +#define yydebug m2_debug +#define yypact m2_pact +#define yyr1 m2_r1 +#define yyr2 m2_r2 +#define yydef m2_def +#define yychk m2_chk +#define yypgo m2_pgo +#define yyact m2_act +#define yyexca m2_exca +#define yyerrflag m2_errflag +#define yynerrs m2_nerrs +#define yyps m2_ps +#define yypv m2_pv +#define yys m2_s +#define yy_yys m2_yys +#define yystate m2_state +#define yytmp m2_tmp +#define yyv m2_v +#define yy_yyv m2_yyv +#define yyval m2_val +#define yylloc m2_lloc +#define yyreds m2_reds /* With YYDEBUG defined */ +#define yytoks m2_toks /* With YYDEBUG defined */ +#define yylhs m2_yylhs +#define yylen m2_yylen +#define yydefred m2_yydefred +#define yydgoto m2_yydgoto +#define yysindex m2_yysindex +#define yyrindex m2_yyrindex +#define yygindex m2_yygindex +#define yytable m2_yytable +#define yycheck m2_yycheck + +#ifndef YYDEBUG +#define YYDEBUG 0 /* Default to no yydebug support */ +#endif + +int +yyparse PARAMS ((void)); + +static int +yylex PARAMS ((void)); + +void +yyerror PARAMS ((char *)); + +#if 0 +static char * +make_qualname PARAMS ((char *, char *)); +#endif + +static int +parse_number PARAMS ((int)); + +/* The sign of the number being parsed. */ +static int number_sign = 1; + +/* The block that the module specified by the qualifer on an identifer is + contained in, */ +#if 0 +static struct block *modblock=0; +#endif + +%} + +/* Although the yacc "value" of an expression is not used, + since the result is stored in the structure being created, + other node types do have values. */ + +%union + { + LONGEST lval; + ULONGEST ulval; + DOUBLEST dval; + struct symbol *sym; + struct type *tval; + struct stoken sval; + int voidval; + struct block *bval; + enum exp_opcode opcode; + struct internalvar *ivar; + + struct type **tvec; + int *ivec; + } + +%type <voidval> exp type_exp start set +%type <voidval> variable +%type <tval> type +%type <bval> block +%type <sym> fblock + +%token <lval> INT HEX ERROR +%token <ulval> UINT M2_TRUE M2_FALSE CHAR +%token <dval> FLOAT + +/* Both NAME and TYPENAME tokens represent symbols in the input, + and both convey their data as strings. + But a TYPENAME is a string that happens to be defined as a typedef + or builtin type name (such as int or char) + and a NAME is any other symbol. + + Contexts where this distinction is not important can use the + nonterminal "name", which matches either NAME or TYPENAME. */ + +%token <sval> STRING +%token <sval> NAME BLOCKNAME IDENT VARNAME +%token <sval> TYPENAME + +%token SIZE CAP ORD HIGH ABS MIN_FUNC MAX_FUNC FLOAT_FUNC VAL CHR ODD TRUNC +%token INC DEC INCL EXCL + +/* The GDB scope operator */ +%token COLONCOLON + +%token <voidval> INTERNAL_VAR + +/* M2 tokens */ +%left ',' +%left ABOVE_COMMA +%nonassoc ASSIGN +%left '<' '>' LEQ GEQ '=' NOTEQUAL '#' IN +%left OROR +%left LOGICAL_AND '&' +%left '@' +%left '+' '-' +%left '*' '/' DIV MOD +%right UNARY +%right '^' DOT '[' '(' +%right NOT '~' +%left COLONCOLON QID +/* This is not an actual token ; it is used for precedence. +%right QID +*/ + + +%% + +start : exp + | type_exp + ; + +type_exp: type + { write_exp_elt_opcode(OP_TYPE); + write_exp_elt_type($1); + write_exp_elt_opcode(OP_TYPE); + } + ; + +/* Expressions */ + +exp : exp '^' %prec UNARY + { write_exp_elt_opcode (UNOP_IND); } + +exp : '-' + { number_sign = -1; } + exp %prec UNARY + { number_sign = 1; + write_exp_elt_opcode (UNOP_NEG); } + ; + +exp : '+' exp %prec UNARY + { write_exp_elt_opcode(UNOP_PLUS); } + ; + +exp : not_exp exp %prec UNARY + { write_exp_elt_opcode (UNOP_LOGICAL_NOT); } + ; + +not_exp : NOT + | '~' + ; + +exp : CAP '(' exp ')' + { write_exp_elt_opcode (UNOP_CAP); } + ; + +exp : ORD '(' exp ')' + { write_exp_elt_opcode (UNOP_ORD); } + ; + +exp : ABS '(' exp ')' + { write_exp_elt_opcode (UNOP_ABS); } + ; + +exp : HIGH '(' exp ')' + { write_exp_elt_opcode (UNOP_HIGH); } + ; + +exp : MIN_FUNC '(' type ')' + { write_exp_elt_opcode (UNOP_MIN); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_MIN); } + ; + +exp : MAX_FUNC '(' type ')' + { write_exp_elt_opcode (UNOP_MAX); + write_exp_elt_type ($3); + write_exp_elt_opcode (UNOP_MIN); } + ; + +exp : FLOAT_FUNC '(' exp ')' + { write_exp_elt_opcode (UNOP_FLOAT); } + ; + +exp : VAL '(' type ',' exp ')' + { write_exp_elt_opcode (BINOP_VAL); + write_exp_elt_type ($3); + write_exp_elt_opcode (BINOP_VAL); } + ; + +exp : CHR '(' exp ')' + { write_exp_elt_opcode (UNOP_CHR); } + ; + +exp : ODD '(' exp ')' + { write_exp_elt_opcode (UNOP_ODD); } + ; + +exp : TRUNC '(' exp ')' + { write_exp_elt_opcode (UNOP_TRUNC); } + ; + +exp : SIZE exp %prec UNARY + { write_exp_elt_opcode (UNOP_SIZEOF); } + ; + + +exp : INC '(' exp ')' + { write_exp_elt_opcode(UNOP_PREINCREMENT); } + ; + +exp : INC '(' exp ',' exp ')' + { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_ADD); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } + ; + +exp : DEC '(' exp ')' + { write_exp_elt_opcode(UNOP_PREDECREMENT);} + ; + +exp : DEC '(' exp ',' exp ')' + { write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); + write_exp_elt_opcode(BINOP_SUB); + write_exp_elt_opcode(BINOP_ASSIGN_MODIFY); } + ; + +exp : exp DOT NAME + { write_exp_elt_opcode (STRUCTOP_STRUCT); + write_exp_string ($3); + write_exp_elt_opcode (STRUCTOP_STRUCT); } + ; + +exp : set + ; + +exp : exp IN set + { error("Sets are not implemented.");} + ; + +exp : INCL '(' exp ',' exp ')' + { error("Sets are not implemented.");} + ; + +exp : EXCL '(' exp ',' exp ')' + { error("Sets are not implemented.");} + +set : '{' arglist '}' + { error("Sets are not implemented.");} + | type '{' arglist '}' + { error("Sets are not implemented.");} + ; + + +/* Modula-2 array subscript notation [a,b,c...] */ +exp : exp '[' + /* This function just saves the number of arguments + that follow in the list. It is *not* specific to + function types */ + { start_arglist(); } + non_empty_arglist ']' %prec DOT + { write_exp_elt_opcode (MULTI_SUBSCRIPT); + write_exp_elt_longcst ((LONGEST) end_arglist()); + write_exp_elt_opcode (MULTI_SUBSCRIPT); } + ; + +exp : exp '(' + /* This is to save the value of arglist_len + being accumulated by an outer function call. */ + { start_arglist (); } + arglist ')' %prec DOT + { write_exp_elt_opcode (OP_FUNCALL); + write_exp_elt_longcst ((LONGEST) end_arglist ()); + write_exp_elt_opcode (OP_FUNCALL); } + ; + +arglist : + ; + +arglist : exp + { arglist_len = 1; } + ; + +arglist : arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +non_empty_arglist + : exp + { arglist_len = 1; } + ; + +non_empty_arglist + : non_empty_arglist ',' exp %prec ABOVE_COMMA + { arglist_len++; } + ; + +/* GDB construct */ +exp : '{' type '}' exp %prec UNARY + { write_exp_elt_opcode (UNOP_MEMVAL); + write_exp_elt_type ($2); + write_exp_elt_opcode (UNOP_MEMVAL); } + ; + +exp : type '(' exp ')' %prec UNARY + { write_exp_elt_opcode (UNOP_CAST); + write_exp_elt_type ($1); + write_exp_elt_opcode (UNOP_CAST); } + ; + +exp : '(' exp ')' + { } + ; + +/* Binary operators in order of decreasing precedence. Note that some + of these operators are overloaded! (ie. sets) */ + +/* GDB construct */ +exp : exp '@' exp + { write_exp_elt_opcode (BINOP_REPEAT); } + ; + +exp : exp '*' exp + { write_exp_elt_opcode (BINOP_MUL); } + ; + +exp : exp '/' exp + { write_exp_elt_opcode (BINOP_DIV); } + ; + +exp : exp DIV exp + { write_exp_elt_opcode (BINOP_INTDIV); } + ; + +exp : exp MOD exp + { write_exp_elt_opcode (BINOP_REM); } + ; + +exp : exp '+' exp + { write_exp_elt_opcode (BINOP_ADD); } + ; + +exp : exp '-' exp + { write_exp_elt_opcode (BINOP_SUB); } + ; + +exp : exp '=' exp + { write_exp_elt_opcode (BINOP_EQUAL); } + ; + +exp : exp NOTEQUAL exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + | exp '#' exp + { write_exp_elt_opcode (BINOP_NOTEQUAL); } + ; + +exp : exp LEQ exp + { write_exp_elt_opcode (BINOP_LEQ); } + ; + +exp : exp GEQ exp + { write_exp_elt_opcode (BINOP_GEQ); } + ; + +exp : exp '<' exp + { write_exp_elt_opcode (BINOP_LESS); } + ; + +exp : exp '>' exp + { write_exp_elt_opcode (BINOP_GTR); } + ; + +exp : exp LOGICAL_AND exp + { write_exp_elt_opcode (BINOP_LOGICAL_AND); } + ; + +exp : exp OROR exp + { write_exp_elt_opcode (BINOP_LOGICAL_OR); } + ; + +exp : exp ASSIGN exp + { write_exp_elt_opcode (BINOP_ASSIGN); } + ; + + +/* Constants */ + +exp : M2_TRUE + { write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); } + ; + +exp : M2_FALSE + { write_exp_elt_opcode (OP_BOOL); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_BOOL); } + ; + +exp : INT + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_int); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : UINT + { + write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_card); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); + } + ; + +exp : CHAR + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_m2_char); + write_exp_elt_longcst ((LONGEST) $1); + write_exp_elt_opcode (OP_LONG); } + ; + + +exp : FLOAT + { write_exp_elt_opcode (OP_DOUBLE); + write_exp_elt_type (builtin_type_m2_real); + write_exp_elt_dblcst ($1); + write_exp_elt_opcode (OP_DOUBLE); } + ; + +exp : variable + ; + +exp : SIZE '(' type ')' %prec UNARY + { write_exp_elt_opcode (OP_LONG); + write_exp_elt_type (builtin_type_int); + write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3)); + write_exp_elt_opcode (OP_LONG); } + ; + +exp : STRING + { write_exp_elt_opcode (OP_M2_STRING); + write_exp_string ($1); + write_exp_elt_opcode (OP_M2_STRING); } + ; + +/* This will be used for extensions later. Like adding modules. */ +block : fblock + { $$ = SYMBOL_BLOCK_VALUE($1); } + ; + +fblock : BLOCKNAME + { struct symbol *sym + = lookup_symbol (copy_name ($1), expression_context_block, + VAR_NAMESPACE, 0, NULL); + $$ = sym;} + ; + + +/* GDB scope operator */ +fblock : block COLONCOLON BLOCKNAME + { struct symbol *tem + = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, NULL); + if (!tem || SYMBOL_CLASS (tem) != LOC_BLOCK) + error ("No function \"%s\" in specified context.", + copy_name ($3)); + $$ = tem; + } + ; + +/* Useful for assigning to PROCEDURE variables */ +variable: fblock + { write_exp_elt_opcode(OP_VAR_VALUE); + write_exp_elt_block (NULL); + write_exp_elt_sym ($1); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +/* GDB internal ($foo) variable */ +variable: INTERNAL_VAR + ; + +/* GDB scope operator */ +variable: block COLONCOLON NAME + { struct symbol *sym; + sym = lookup_symbol (copy_name ($3), $1, + VAR_NAMESPACE, 0, NULL); + if (sym == 0) + error ("No symbol \"%s\" in specified context.", + copy_name ($3)); + + write_exp_elt_opcode (OP_VAR_VALUE); + /* block_found is set by lookup_symbol. */ + write_exp_elt_block (block_found); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); } + ; + +/* Base case for variables. */ +variable: NAME + { struct symbol *sym; + int is_a_field_of_this; + + sym = lookup_symbol (copy_name ($1), + expression_context_block, + VAR_NAMESPACE, + &is_a_field_of_this, + NULL); + if (sym) + { + if (symbol_read_needs_frame (sym)) + { + if (innermost_block == 0 || + contained_in (block_found, + innermost_block)) + innermost_block = block_found; + } + + write_exp_elt_opcode (OP_VAR_VALUE); + /* We want to use the selected frame, not + another more inner frame which happens to + be in the same block. */ + write_exp_elt_block (NULL); + write_exp_elt_sym (sym); + write_exp_elt_opcode (OP_VAR_VALUE); + } + else + { + struct minimal_symbol *msymbol; + register char *arg = copy_name ($1); + + msymbol = + lookup_minimal_symbol (arg, NULL, NULL); + if (msymbol != NULL) + { + write_exp_msymbol + (msymbol, + lookup_function_type (builtin_type_int), + builtin_type_int); + } + else if (!have_full_symbols () && !have_partial_symbols ()) + error ("No symbol table is loaded. Use the \"symbol-file\" command."); + else + error ("No symbol \"%s\" in current context.", + copy_name ($1)); + } + } + ; + +type + : TYPENAME + { $$ = lookup_typename (copy_name ($1), + expression_context_block, 0); } + + ; + +%% + +#if 0 /* FIXME! */ +int +overflow(a,b) + long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_int) - b) < a; +} + +int +uoverflow(a,b) + unsigned long a,b; +{ + return (MAX_OF_TYPE(builtin_type_m2_card) - b) < a; +} +#endif /* FIXME */ + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (olen) + int olen; +{ + register char *p = lexptr; + register LONGEST n = 0; + register LONGEST prevn = 0; + register int c,i,ischar=0; + register int base = input_radix; + register int len = olen; + int unsigned_p = number_sign == 1 ? 1 : 0; + + if(p[len-1] == 'H') + { + base = 16; + len--; + } + else if(p[len-1] == 'C' || p[len-1] == 'B') + { + base = 8; + ischar = p[len-1] == 'C'; + len--; + } + + /* Scan the number */ + for (c = 0; c < len; c++) + { + if (p[c] == '.' && base == 10) + { + /* It's a float since it contains a point. */ + yylval.dval = atof (p); + lexptr += len; + return FLOAT; + } + if (p[c] == '.' && base != 10) + error("Floating point numbers must be base 10."); + if (base == 10 && (p[c] < '0' || p[c] > '9')) + error("Invalid digit \'%c\' in number.",p[c]); + } + + while (len-- > 0) + { + c = *p++; + n *= base; + if( base == 8 && (c == '8' || c == '9')) + error("Invalid digit \'%c\' in octal number.",c); + if (c >= '0' && c <= '9') + i = c - '0'; + else + { + if (base == 16 && c >= 'A' && c <= 'F') + i = c - 'A' + 10; + else + return ERROR; + } + n+=i; + if(i >= base) + return ERROR; + if(!unsigned_p && number_sign == 1 && (prevn >= n)) + unsigned_p=1; /* Try something unsigned */ + /* Don't do the range check if n==i and i==0, since that special + case will give an overflow error. */ + if(RANGE_CHECK && n!=i && i) + { + if((unsigned_p && (unsigned)prevn >= (unsigned)n) || + ((!unsigned_p && number_sign==-1) && -prevn <= -n)) + range_error("Overflow on numeric constant."); + } + prevn=n; + } + + lexptr = p; + if(*p == 'B' || *p == 'C' || *p == 'H') + lexptr++; /* Advance past B,C or H */ + + if (ischar) + { + yylval.ulval = n; + return CHAR; + } + else if ( unsigned_p && number_sign == 1) + { + yylval.ulval = n; + return UINT; + } + else if((unsigned_p && (n<0))) { + range_error("Overflow on numeric constant -- number too large."); + /* But, this can return if range_check == range_warn. */ + } + yylval.lval = n; + return INT; +} + + +/* Some tokens */ + +static struct +{ + char name[2]; + int token; +} tokentab2[] = +{ + { {'<', '>'}, NOTEQUAL }, + { {':', '='}, ASSIGN }, + { {'<', '='}, LEQ }, + { {'>', '='}, GEQ }, + { {':', ':'}, COLONCOLON }, + +}; + +/* Some specific keywords */ + +struct keyword { + char keyw[10]; + int token; +}; + +static struct keyword keytab[] = +{ + {"OR" , OROR }, + {"IN", IN },/* Note space after IN */ + {"AND", LOGICAL_AND}, + {"ABS", ABS }, + {"CHR", CHR }, + {"DEC", DEC }, + {"NOT", NOT }, + {"DIV", DIV }, + {"INC", INC }, + {"MAX", MAX_FUNC }, + {"MIN", MIN_FUNC }, + {"MOD", MOD }, + {"ODD", ODD }, + {"CAP", CAP }, + {"ORD", ORD }, + {"VAL", VAL }, + {"EXCL", EXCL }, + {"HIGH", HIGH }, + {"INCL", INCL }, + {"SIZE", SIZE }, + {"FLOAT", FLOAT_FUNC }, + {"TRUNC", TRUNC }, +}; + + +/* Read one token, getting characters through lexptr. */ + +/* This is where we will check to make sure that the language and the operators used are + compatible */ + +static int +yylex () +{ + register int c; + register int namelen; + register int i; + register char *tokstart; + register char quote; + + retry: + + tokstart = lexptr; + + + /* See if it is a special token of length 2 */ + for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++) + if(STREQN(tokentab2[i].name, tokstart, 2)) + { + lexptr += 2; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + lexptr++; + goto retry; + + case '(': + paren_depth++; + lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + lexptr++; + return c; + + case ',': + if (comma_terminates && paren_depth == 0) + return 0; + lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (lexptr[1] >= '0' && lexptr[1] <= '9') + break; /* Falls into number code. */ + else + { + lexptr++; + return DOT; + } + +/* These are character tokens that appear as-is in the YACC grammar */ + case '+': + case '-': + case '*': + case '/': + case '^': + case '<': + case '>': + case '[': + case ']': + case '=': + case '{': + case '}': + case '#': + case '@': + case '~': + case '&': + lexptr++; + return c; + + case '\'' : + case '"': + quote = c; + for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + if(c != quote) + error("Unterminated string or character constant."); + yylval.sval.ptr = tokstart + 1; + yylval.sval.length = namelen - 1; + lexptr += namelen + 1; + + if(namelen == 2) /* Single character */ + { + yylval.ulval = tokstart[1]; + return CHAR; + } + else + return STRING; + } + + /* Is it a number? */ + /* Note: We have already dealt with the case of the token '.'. + See case '.' above. */ + if ((c >= '0' && c <= '9')) + { + /* It's a number. */ + int got_dot = 0, got_e = 0; + register char *p = tokstart; + int toktype; + + for (++p ;; ++p) + { + if (!got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + else if ((*p < '0' || *p > '9') && + (*p < 'A' || *p > 'F') && + (*p != 'H')) /* Modula-2 hexadecimal number */ + break; + } + toktype = parse_number (p - tokstart); + if (toktype == ERROR) + { + char *err_copy = (char *) alloca (p - tokstart + 1); + + memcpy (err_copy, tokstart, p - tokstart); + err_copy[p - tokstart] = 0; + error ("Invalid number \"%s\".", err_copy); + } + lexptr = p; + return toktype; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error ("Invalid character '%c' in expression.", c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + lexptr += namelen; + + /* Lookup special keywords */ + for(i = 0 ; i < (int) (sizeof(keytab) / sizeof(keytab[0])) ; i++) + if(namelen == strlen(keytab[i].keyw) && STREQN(tokstart,keytab[i].keyw,namelen)) + return keytab[i].token; + + yylval.sval.ptr = tokstart; + yylval.sval.length = namelen; + + if (*tokstart == '$') + { + write_dollar_variable (yylval.sval); + return INTERNAL_VAR; + } + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + + + char *tmp = copy_name (yylval.sval); + struct symbol *sym; + + if (lookup_partial_symtab (tmp)) + return BLOCKNAME; + sym = lookup_symbol (tmp, expression_context_block, + VAR_NAMESPACE, 0, NULL); + if (sym && SYMBOL_CLASS (sym) == LOC_BLOCK) + return BLOCKNAME; + if (lookup_typename (copy_name (yylval.sval), expression_context_block, 1)) + return TYPENAME; + + if(sym) + { + switch(sym->aclass) + { + case LOC_STATIC: + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_LOCAL_ARG: + case LOC_BASEREG: + case LOC_BASEREG_ARG: + case LOC_CONST: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + return NAME; + + case LOC_TYPEDEF: + return TYPENAME; + + case LOC_BLOCK: + return BLOCKNAME; + + case LOC_UNDEF: + error("internal: Undefined class in m2lex()"); + + case LOC_LABEL: + case LOC_UNRESOLVED: + error("internal: Unforseen case in m2lex()"); + } + } + else + { + /* Built-in BOOLEAN type. This is sort of a hack. */ + if(STREQN(tokstart,"TRUE",4)) + { + yylval.ulval = 1; + return M2_TRUE; + } + else if(STREQN(tokstart,"FALSE",5)) + { + yylval.ulval = 0; + return M2_FALSE; + } + } + + /* Must be another type of name... */ + return NAME; + } +} + +#if 0 /* Unused */ +static char * +make_qualname(mod,ident) + char *mod, *ident; +{ + char *new = malloc(strlen(mod)+strlen(ident)+2); + + strcpy(new,mod); + strcat(new,"."); + strcat(new,ident); + return new; +} +#endif /* 0 */ + +void +yyerror (msg) + char *msg; +{ + error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr); +} |