%{ /* SPIM S20 MIPS simulator. Lexical scanner. Copyright (C) 1990 by James Larus (larus@cs.wisc.edu). SPIM 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 1, or (at your option) any later version. SPIM 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 GNU CC; see the file COPYING. If not, write to James R. Larus, Computer Sciences Department, University of Wisconsin--Madison, 1210 West Dayton Street, Madison, WI 53706, USA or to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ /* $Header: /home/aa/projects/spim/public_html/cvsroot/spimsal/scanner.l,v 1.4 1999/08/21 21:12:06 brg Exp $ */ #include "spim.h" #include "inst.h" #include "mem.h" #include "y.tab.h" #ifndef YY_CHAR #define YY_CHAR char #endif /* Track which line we are reading and where it began in the buffer. */ int line_no = 1; static YY_CHAR *line_start = NULL; extern unsigned int last_inst_addr; static double scan_float; /* Where FP values are kept */ int y_str_length; /* Length of Y_STR */ /* Local functions: */ static int check_keyword (char *, int); static YY_CHAR *copy_str (YY_CHAR *, int); %} %% [ \t] {if (line_start == NULL) line_start = yytext;} \n {line_no += 1; return (Y_NL);} (-0[0-7]*)|(0[0-7]*) { sscanf (yytext, "%o", &(yylval.ival)); /* yylval.ival = atoi ((char *) yytext); */ if (line_start == NULL) line_start = yytext; return (Y_INT);} (-[1-9][0-9]*)|([1-9][0-9]*) {/*int x; sscanf (yytext, "%d", &(yylval.ival));*/ yylval.ival = atoi ((char *) yytext); if (line_start == NULL) line_start = yytext; return (Y_INT);} ((0x)|(-0x))[0-9A-Fa-f]+ {if (*yytext == '-') { sscanf(yytext+3, "%lx", &(yylval.ival)); yylval.ival = -yylval.ival; } else { sscanf(yytext+2, "%lx", &(yylval.ival)); } if (line_start == NULL) line_start = yytext; return (Y_INT);} (\+|\-)?[0-9]+\.[0-9]*(e)?(\+|\-)?[0-9]* { scan_float = atof ((char *) yytext); yylval.dptr = &scan_float; if (line_start == NULL) line_start = yytext; return (Y_FP);} [a-zA-Z_\.][a-zA-Z0-9_\.]* {int token = check_keyword ((char *) yytext, !bare_machine); if (line_start == NULL) line_start = yytext; if (token != 0) { yylval.ival = token; line_start = yytext; return (token); } yylval.cptr = strcpy (malloc (strlen ((char *) yytext)+1), (char *) yytext); return (Y_ID);} \$[a-zA-Z0-9_\.$]+ {int reg_no = register_name_to_number ((char *) yytext + 1); if (line_start == NULL) line_start = yytext; if (reg_no != -1 && *(yytext + 1) == 'f' && *(yytext + 2) != 'p') { yylval.ival = reg_no; return (Y_FP_REG); } else if (reg_no < 0 || reg_no > 31) { yylval.cptr = strcpy (malloc(strlen(yytext)+1), (char *) yytext); return (Y_ID); } else { yylval.ival =reg_no; return (Y_REG); }} "#".* {if (line_start == NULL) line_start = yytext;} [:()+-] {if (line_start == NULL) line_start = yytext; return (*yytext);} "[" {if (line_start == NULL) line_start = yytext; return (*yytext);} "]" {if (line_start == NULL) line_start = yytext; return (*yytext);} "," {if (line_start == NULL) line_start = yytext;} "?" {if (line_start == NULL) line_start = yytext; yylval.cptr = strcpy (malloc (strlen (yytext)+1), (char *) yytext); /* For top level */ return (Y_ID);} \"(([^"])|(\\\"))*\" {if (line_start == NULL) line_start = yytext; yylval.cptr = (char *)copy_str (yytext + 1, 1); return (Y_STR);} \'(([^'])|(\\\'))*\' {if (line_start == NULL) line_start = yytext; yylval.cptr = (char *)copy_str (yytext + 1, 1); return (Y_STR);} . {if (line_start == NULL) line_start = yytext; yyerror ("Unknown character");} %% void initialize_scanner (FILE *in_file) { #ifdef FLEX_SCANNER /* FLEX wants a little more help with multiple input buffers. */ static YY_BUFFER_STATE bufstate = ((YY_BUFFER_STATE) 0); if (bufstate) yy_delete_buffer(bufstate); bufstate = yy_create_buffer(in_file, YY_BUF_SIZE); yy_switch_to_buffer(bufstate); yy_init = 1; #endif yyin = in_file; line_no = 1; line_start = NULL; } void scanner_start_line (void) { if (last_inst_addr && line_start) { int len; instruction *insn; READ_MEM_INST(insn, last_inst_addr); if (insn) { len = strlen(line_start); if (NULL == (COMMENT(insn) = (char *)malloc(len+1))) { fprintf(stderr, "Out of memory.\n"); exit(-1); } bcopy(line_start, COMMENT(insn), len+1); if ((COMMENT(insn))[len-1] == '\n') (COMMENT(insn))[len-1] = '\0'; last_inst_addr = 0; SET_MEM_INST(last_inst_addr, insn); } } line_start = NULL; } #ifdef FLEX_SCANNER /* We don't use -ll */ int yywrap () {return 1;} #endif /* Return a freshly-allocated copy of STRING with the last CHOP characters removed. */ static YY_CHAR *copy_str (YY_CHAR *str, int chop) { register int new_len = strlen (str) - chop; register YY_CHAR *new_str = (YY_CHAR *) malloc (new_len + 1), *n; for (n = new_str; *str != '\0' && new_len > 0; new_len -= 1) if (*str == '\\') switch (*(str + 1)) { case 'n': { *n ++ = '\n'; str += 2; new_len -= 1; continue; } case 't': { *n ++ = '\t'; str += 2; new_len -= 1; continue; } case '0': { *n ++ = '\0'; str += 2; new_len -= 1; continue; } case '"': { *n ++ = '"'; str += 2; new_len -= 1; continue; } case 'X': { YY_CHAR c1 = *(str + 2), c2 = *(str + 3); int b = 0; if ('0' <= c1 && c1 <= '9') b = c1 - '0'; else if ('A' <= c1 && c1 <= 'F') b = c1 - 'A' + 10; else yyerror ("Bad character in \\X construct in string"); b <<= 4; if ('0' <= c2 && c2 <= '9') b += c2 - '0'; else if ('A' <= c2 && c2 <= 'F') b += c2 - 'A' + 10; else yyerror ("Bad character in \\X construct in string"); *n ++ = (YY_CHAR) b; str += 4; new_len -= 3; continue; } default: { *n ++ = *str ++; continue; } } else *n ++ = *str ++; *n = '\0'; y_str_length = n - new_str; return (new_str); } /* On a parse error, write out the current line and print a caret (^) below the point at which the error occured. Also, reset the input stream to the begining of the next line. */ void print_erroneous_line (void) { int prefix_length = yytext - line_start; int i, c; #define BSIZE 1024 YY_CHAR buffer[BSIZE], *bp = buffer; if (line_start == NULL) return; error (" "); c = *(line_start + prefix_length); *(line_start + prefix_length) = '\0'; sprintf(mess_buff, "%s", line_start); error (mess_buff); *(line_start + prefix_length) = c; sprintf(mess_buff, "%s", yytext); error (mess_buff); /* Flush the rest of the line. */ if (*yytext != '\n') { while ((c = input ()) != '\n' && c != EOF) { *bp ++ = c; } *bp = '\0'; sprintf(mess_buff, "%s\n", buffer); error (mess_buff); #ifdef FLEX_SCANNER if (c == '\n') unput('\n'); #endif line_start = NULL; } error (" "); while (prefix_length >= 50) { error(" "); prefix_length -= 50; } for (i = 0; i < prefix_length; i ++) buffer[i] = ' '; buffer[i] = '\0'; sprintf(mess_buff, "%s^\n", buffer); error (mess_buff); } static inst_info keyword_tbl [] = { #undef OP #define OP(NAME, OPCODE, TYPE, R_OPCODE) {NAME, OPCODE, TYPE}, #include "op.h" }; static int check_keyword (char *id, int allow_pseudo_ops) { inst_info *entry = map_string_to_inst_info (keyword_tbl, sizeof(keyword_tbl) / sizeof (inst_info), id); if (entry == NULL) return (0); else if (!allow_pseudo_ops && entry->value2 == PSEUDO_OP) return (0); else return (entry->value1); } static inst_info register_tbl [] = { {"a0", 4, 0}, {"a1", 5, 0}, {"a2", 6, 0}, {"a3", 7, 0}, {"at", 1, 0}, {"fp", 30, 0}, {"gp", 28, 0}, {"k0", 26, 0}, {"k1", 27, 0}, {"kt0", 26, 0}, {"kt1", 27, 0}, {"ra", 31, 0}, {"s0", 16, 0}, {"s1", 17, 0}, {"s2", 18, 0}, {"s3", 19, 0}, {"s4", 20, 0}, {"s5", 21, 0}, {"s6", 22, 0}, {"s7", 23, 0}, {"s8", 30, 0}, {"sp", 29, 0}, {"t0", 8, 0}, {"t1", 9, 0}, {"t2", 10, 0}, {"t3", 11, 0}, {"t4", 12, 0}, {"t5", 13, 0}, {"t6", 14, 0}, {"t7", 15, 0}, {"t8", 24, 0}, {"t9", 25, 0}, {"v0", 2, 0}, {"v1", 3, 0}, {"zero", 0, 0} }; int register_name_to_number (const char *name) { register int c1 = *name, c2 = *(name + 1); if ('0' <= c1 && c1 <= '9' && (c2 == '\0' || (('0' <= c2 && c2 <= '9') && *(name + 2) == '\0'))) return (atoi (name)); else if (c1 == 'f' && c2 >= '0' && c2 <= '9') return atoi (name + 1); else { inst_info *entry = map_string_to_inst_info (register_tbl, sizeof (register_tbl) / sizeof (inst_info), name); if (entry == NULL) return (-1); else return (entry->value1); } }