/*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#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
}
syntax highlighted by Code2HTML, v. 0.9.1