/* * Copyright (c) 2003 - 2007, Nils R. Weller * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * Lexical analyzer */ #include "lex.h" #include #include #include #include #include #include #include #include "token.h" #include "defs.h" #include "error.h" #include "numlimits.h" #include "misc.h" #include "debug.h" #include "type.h" #include "cc1_main.h" #include "dwarf.h" #include "n_libc.h" static void print_token_list(struct token *list); const char *cur_inc; int cur_inc_is_std; #if 0 static void check_std_inc(const char *inc) { const char *p; static char *std_headers[] = { "assert.h", "ctype.h", "float.h", "limits.h", "math.h", "stdarg.h", "stddef.h", "stdio.h" "stdlib.h", "string.h", NULL }; int i; cur_inc = NULL; cur_inc_is_std = 0; if ((p = strrchr(inc, '/')) == NULL) { return; } inc = p+1; if (strncmp(inc, "/usr/include", p - inc - 1) != 0) { return; } for (i = 0; std_headers[i] != NULL; ++i) { if (strcmp(std_headers[i], inc) == 0) { cur_inc = inc; cur_inc_is_std = 1; break; } } } #endif int get_next_char(FILE *fd) { int ch = getc(fd); #if 0 int ch = EOF; char *cur = lex_file_map + lex_chars_read; if (cur < lex_file_map_end) { ch = *cur; ++lex_chars_read; } else { --lex_chars_read; } #endif if (ch == '\n') { lex_line_ptr = lex_file_map + lex_chars_read; err_setlineptr(lex_line_ptr); } return ch; } static char * FGETS(char *buf, size_t bufsiz, FILE *in) { int ch; while ((ch = FGETC(in)) != EOF) { if (bufsiz > 1) { if ((*buf++ = ch) == '\n') { break; } } else { break; } --bufsiz; } *buf = 0; return buf; } #if 0 static int nextch; #define get_next_char(fd) \ ((nextch = getc(fd)) == '\n'? \ lex_line_ptr = lex_file_map + lex_chars_read, \ err_setlineptr(lex_line_ptr), nextch: nextch) #endif int lex(FILE *in) { int ch; int tmpi; int compound = 0; int array = 0; int parentheses = 0; int lineno = 0; int atline = 0; int ispragma = 0; int *dummyptr = n_xmalloc(sizeof *dummyptr); int err; char buf[512]; char buf2[256]; char *tmpc; char *curfile = NULL; int curfileid = 0; if (/*options.showline*/ 1) { int fd = fileno(in); struct stat s; if (fstat(fd, &s) == -1) { perror("fstat"); exit(EXIT_FAILURE); } lex_file_map = mmap(0, s.st_size, PROT_READ, MAP_SHARED, fd, 0); if (lex_file_map == MAP_FAILED) { perror("mmap"); exit(EXIT_FAILURE); } lex_file_map_end = lex_file_map + s.st_size; lex_line_ptr = lex_file_map; #ifdef MADV_SEQUENTIAL (void) madvise(lex_file_map, s.st_size, MADV_SEQUENTIAL); #endif } /* Initialize error message module */ err_setfile("unknown"); token_setfile("unknown"); err_setline(&lineno); errors = 0; warnings = 0; /* * Initialize the digit limits of integral constants so * get_num_literal() can warn about overflow. */ init_max_digits(); while ((ch = FGETC(in)) != EOF) { lex_tok_ptr = lex_file_map + lex_chars_read; switch (ch) { case '#': /* Must be processor file indicator or #pragma */ if ((ch = FGETC(in)) == EOF) { continue; } if (ch == 'p') { /* Must be pragma */ UNGETC(ch, in); /* ispragma = 1; */ do { ch = FGETC(in); } while (ch != EOF && ch != '\n'); #if 0 (void) fgets(buf, sizeof buf, in); #endif continue; } /* Must be preprocessor file name */ #if 0 if (fgets(buf, sizeof buf, in) == NULL) { #endif if (FGETS(buf, sizeof buf, in) == NULL) { lexerror("Unexpected end of file - " "expected preprocessor output."); return 1; } if (lex_file_map) { #if 0 char *p = strchr(buf, 0); size_t len = p - buf; lex_chars_read += len; if (len > 0 && p[-1] == '\n') { lex_line_ptr = lex_file_map + lex_chars_read; } if (lex_line_ptr == lex_file_map_end) { lex_line_ptr = lex_file_map; } #endif } if (sscanf(buf, " %d \"%256[^\"]\" %*d", &atline, buf2) != 2) { #ifndef __sgi lexerror("Bad preprocessor directive format."); #else continue; #endif } /* * Note that curfile is still referred to by tokens - * don't free */ curfile = strdup(buf2); if (gflag) { curfileid = dwarf_put_file(curfile); } #if 0 XXX check_std_inc(curfile); #endif if (*curfile && curfile[strlen(curfile) - 1] == 'c') { cur_inc = NULL; cur_inc_is_std = 0; } /* Processing new file */ err_setfile(curfile); token_setfile(curfile); token_setfileid(curfileid); lineno = atline; ispragma = 0; break; case ' ': case '\f': case '\t': case '\r': ispragma = 0; continue; break; case '\n': ++lineno; ispragma = 0; continue; break; case '\'': err = 0; tmpi = get_char_literal(in, &err); /* XXX cross-comp */ if (!err) { /* * Character literals are really treated * like integer constants */ /*int *tmpip = malloc(sizeof(int));*/ int *tmpip = n_xmalloc(16); /* XXX */ if (tmpip == NULL) { perror("malloc"); exit(EXIT_FAILURE); } *tmpip = tmpi; store_token(&toklist, tmpip, TY_INT, lineno, NULL); } ispragma = 0; break; case '"': { struct ty_string *tmpstr; tmpstr = get_string_literal(in); if (tmpstr != NULL) { store_token(&toklist, tmpstr, TOK_STRING_LITERAL, lineno, NULL); } ispragma = 0; break; } case '(': case ')': if (ch == '(') { ++parentheses; } else { if (parentheses == 0) { lexerror("No matching opening " "parentheses."); } --parentheses; } store_token(&toklist, dummyptr, ch == '(' ? TOK_PAREN_OPEN : TOK_PAREN_CLOSE, lineno, NULL); ispragma = 0; break; case '{': case '}': if (ch == '{') { ++compound; } else { if (compound == 0) { lexerror("No matching opening brace."); } --compound; } store_token(&toklist, dummyptr, ch == '{'? TOK_COMP_OPEN: TOK_COMP_CLOSE, lineno, NULL); ispragma = 0; break; case '[': case ']': if (ch == '[') { ++array; } else { if (array == 0) { lexerror("Not a valid subscript."); ++array; } --array; } store_token(&toklist, dummyptr, ch == '[' ? TOK_ARRAY_OPEN : TOK_ARRAY_CLOSE, lineno, NULL); ispragma = 0; break; case ';': store_token(&toklist, dummyptr, TOK_SEMICOLON, lineno, NULL); ispragma = 0; break; case '.': /* * This might be either a structure / union * indirection operator or a floating point * value like .5 (equivalent to 0.5). If the * latter is the case, call get_num_literal(), * else fall through */ if ((tmpi = FGETC(in)) == EOF) { lexerror("Unexpected end of file."); return 1; } UNGETC(tmpi, in); if (isdigit((unsigned char)tmpi)) { struct num *n = get_num_literal(ch, in); #if 0 if (standard == C89 && IS_LLONG(n->type)) { error("`long long' constants are not " "available in C89 (don't use" "-ansi or -std=c89"); } #endif if (n != NULL) { store_token(&toklist, n->value, n->type, lineno, NULL); } break; } ispragma = 0; /* FALLTHRU */ default: if (ch == '?') { int trig; /* Might be trigraph */ if ((trig = get_trigraph(in)) == -1) { /* * Not a trigraph - LOOKUP_OP() * will catch the ``?'' */ ; } else if (trig == 0) { /* * The source file contained a ``??'' * that isn't isn't part of a trigraph - * this is a syntax error, since it * cannot be the conditional operator */ lexerror("Syntax error at ``?\?''"); } else { /* Valid trigraph! */ UNGETC(trig, in); ispragma = 0; continue; } } if (LOOKUP_OP(ch)) { int *ptri = malloc(sizeof(int)); char *ascii = NULL; if (ptri == NULL) { perror("malloc"); exit(EXIT_FAILURE); } tmpi = get_operator(ch, in, &ascii); if (tmpi != -1) { *ptri = tmpi; store_token(&toklist, ptri, TOK_OPERATOR, lineno, ascii); } else { lexerror("INVALID OPERATOR!!!"); } } else if (isdigit((unsigned char)ch)) { struct num *n = get_num_literal(ch, in); if (n != NULL) { store_token(&toklist, n->value, n->type, lineno, NULL); } else { lexerror("Couldn't read numeric literal"); } } else if (isalpha((unsigned char)ch) || ch == '_') { if (ch == 'L') { int tmpch; tmpch = FGETC(in); if (tmpch != EOF) { UNGETC(tmpch, in); if (tmpch == '\'' || tmpch == '"') { /* * Long constant - treat like * ordinary one */ continue; } } } tmpc = get_identifier(ch, in); if (tmpc != NULL) { store_token(&toklist, tmpc, TOK_IDENTIFIER, lineno, NULL); } } else { lexerror("Unknown token - %c (code %d)\n", ch, ch); } ispragma = 0; } } #if 0 store_token(&toklist, NULL, 0, lineno); #endif print_token_list(toklist); return errors; } static void print_token_list(struct token *list) { (void)list; #ifdef DEBUG puts("-------------------------------------------------------------"); for (; list /*->data*/ != NULL; list = list->next) { if (list->type == TOK_OPERATOR) { int i; for (i = 0; operators[i].name != NULL; ++i) { if (*(int *)list->data == operators[i].value || *(int *)list->data == operators[i].is_ambig) { printf("%s", operators[i].name); break; } } if (operators[i].name == NULL) { (void) fprintf(stderr, "FATAL -- Unknown " "operator %d\n", *(int *)list->data); } } else if (IS_CONSTANT(list->type)) { rv_setrc_print(list->data, list->type, 0); } else if (IS_KEYWORD(list->type)) { printf(" %s ", (char *)list->data); } else if (list->type == TOK_IDENTIFIER) { printf(" %s ", (char *)list->data); } else if (list->type == TOK_STRING_LITERAL) { struct ty_string *ts = list->data; printf("\"%s\"", ts->str); } else if (list->type == TOK_PAREN_OPEN) { printf("("); } else if (list->type == TOK_PAREN_CLOSE){ printf(")"); } else if (list->type == TOK_ARRAY_OPEN) { printf("["); } else if (list->type == TOK_ARRAY_CLOSE) { printf("]"); } else if (list->type == TOK_COMP_OPEN) { printf("{\n"); } else if (list->type == TOK_COMP_CLOSE) { printf("}\n"); } else if (list->type == TOK_SEMICOLON) { printf(";\n"); } else { printf("Unknown - code %d\n", list->type); } } puts("-------------------------------------------------------------"); #endif }