/* * Copyright (c) 2003 - 2006, 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. * * This module contains a keyword and an operator table and two * functions to initialize the LOOKUP_* macros exported by defs.h */ #include "defs.h" #include #include "token.h" #include "n_libc.h" char key_lookup[256]; /* * Initializes lookup table for keywords. Note that you must extend * key_chars appropriately any time a new keyword is added that is not * yet covered by those characters */ void init_keylookup(void) { static char key_chars[] = { 'c', 'd', 'e', 'f', 'i', 'v', 'r', 's', 'u', 'l', 'a', 'w', 'b', 'g', 't', '_', 0 }; unsigned int i; unsigned int j; memset(key_lookup, 0, sizeof key_lookup); for (i = 0; i < sizeof key_chars; ++i) { for (j = 0; keywords[j].name != NULL; ++j) { if (keywords[j].name[0] == key_chars[i]) { key_lookup[ (unsigned)key_chars[i] ] = j; break; } } } } /* * NOTE: These keywords are ordered by their first character to make * lookup faster. * A LOOKUP_KEY macro in defs.h returns the index of the first keyword * with a matching character in the table. init_keylookup() must be * called before that can be used */ struct keyword keywords[] = { { "!dummy!", 0, 0, 0 }, { "case", TOK_KEY_CASE, 0, C89 }, { "char", TOK_KEY_CHAR, TY_CHAR, C89 }, { "const", TOK_KEY_CONST, 0, C89 }, { "continue", TOK_KEY_CONTINUE, 0, C89 }, { "do", TOK_KEY_DO, 0, C89 }, { "double", TOK_KEY_DOUBLE, TY_DOUBLE, C89 }, { "default", TOK_KEY_DEFAULT, 0, C89 }, { "extern", TOK_KEY_EXTERN, 0, C89 }, { "enum", TOK_KEY_ENUM, 0, C89 }, { "else", TOK_KEY_ELSE, 0, C89 }, { "float", TOK_KEY_FLOAT, TY_FLOAT, C89 }, { "for", TOK_KEY_FOR, 0, C89 }, { "inline", TOK_KEY_INLINE, 0, C99 }, { "int", TOK_KEY_INT, TY_INT, C89 }, { "if", TOK_KEY_IF, 0, C89 }, { "void", TOK_KEY_VOID, TY_VOID, C89 }, { "volatile", TOK_KEY_VOLATILE, 0, C89 }, { "register", TOK_KEY_REGISTER, 0, C89 }, { "restrict", TOK_KEY_RESTRICT, 0, C99 }, { "return", TOK_KEY_RETURN, 0, C89 }, { "short", TOK_KEY_SHORT, TY_SHORT, C89 }, { "static", TOK_KEY_STATIC, 0, C89 }, { "signed", TOK_KEY_SIGNED, 0, C89 }, { "switch", TOK_KEY_SWITCH, 0, C89 }, { "struct", TOK_KEY_STRUCT, 0, C89 }, { "sizeof", TOK_KEY_SIZEOF, 0, C89 }, { "unsigned", TOK_KEY_UNSIGNED, 0, C89 }, { "union", TOK_KEY_UNION, 0, C89 }, { "long", TOK_KEY_LONG, TY_LONG, C89 }, { "auto", TOK_KEY_AUTO, 0, C89 }, { "while", TOK_KEY_WHILE, 0, C89 }, { "break", TOK_KEY_BREAK, 0, C89 }, { "goto", TOK_KEY_GOTO, 0, C89 }, { "typedef", TOK_KEY_TYPEDEF, 0, C89 }, { "typeof", TOK_KEY_TYPEOF, 0, C89 }, { "__asm__", TOK_KEY_ASM, 0, C89 }, { "__asm", TOK_KEY_ASM, 0, C89 }, { "__attribute__", TOK_KEY_ATTRIBUTE, 0, C89 }, { "__attribute", TOK_KEY_ATTRIBUTE, 0, C89 }, /* * The following are for GNU C compatibility */ { "__restrict__", TOK_KEY_RESTRICT, 0, C99 }, { "__restrict", TOK_KEY_RESTRICT, 0, C99 }, { "__extension__", TOK_KEY_EXTENSION, 0, 0 }, { "__extension", TOK_KEY_EXTENSION, 0, 0 }, { "__const", TOK_KEY_CONST, 0, C89 }, { "__signed", TOK_KEY_SIGNED, 0, C89 }, { "__signed__", TOK_KEY_SIGNED, 0, C89 }, { "__typeof__", TOK_KEY_TYPEOF, 0, C89 }, { "__typeof", TOK_KEY_TYPEOF, 0, C89 }, { "__alignof__", TOK_KEY_ALIGNOF, 0, C89 }, { "__alignof", TOK_KEY_ALIGNOF, 0, C89 }, { "__volatile__", TOK_KEY_VOLATILE, 0, C89 }, { "__volatile", TOK_KEY_VOLATILE, 0, C89 }, { "__inline", TOK_KEY_INLINE, 0, C99 }, { "__inline__", TOK_KEY_INLINE, 0, C99 }, { "_Bool", TOK_KEY_BOOL, 0, C99 }, #if 0 /* Perhaps later .... */ { "_Complex", TOK_KEY_COMPLEX, 0, C99 }, { "_Imaginary", TOK_KEY_IMAGINARY, 0, C99 }, #endif /* * This last element is used, because one otherwise would have * to check for operators[x].name != NULL when traversing the * list. If a last entry with a different first character is * present, the test is eliminated and one can do * while (operators[x].name[0] == first_char) { ... ++x; } */ { "ZORG", 0, 0, 0 }, { NULL, 0, 0, 0 } }; /* * Keyword lookup function that maps the ``name'' argument to its * respective index in the keyword table on success, else -1. * This should be relatively fast now... */ int lookup_key(const char *name) { int i; char c = *name; if ((i = LOOKUP_KEY((unsigned)c)) == 0) { return -1; } for (; keywords[i].name[0] == c; ++i) { if (strcmp(keywords[i].name, name) == 0) { return i; } } return -1; } /* * Refer to the keywords table comment - This one works the same except * that LOOKUP_OP() and init_oplookup() are used */ struct operator operators[] = { { "dummy", 0, 0, 0, 0, 0, 0 }, /* unary minus */ { "-", TOK_OP_UMINUS, TOK_OP_AMB_MINUS, OP_CLASS_PRE, 15, OP_ASSOC_RIGHT, 0 }, /* compound minus assignment */ { "-=", TOK_OP_COMINUS, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* prefix decrement */ { "--", TOK_OP_DECPRE, TOK_OP_AMB_DECR, OP_CLASS_PRE, 15, OP_ASSOC_RIGHT, 0 }, /* access s. / u. m. through pointer */ { "->", TOK_OP_STRUPMEMB, 0, OP_CLASS_POST, 16, OP_ASSOC_LEFT, 0 }, /* substract */ { "-", TOK_OP_MINUS, TOK_OP_AMB_MINUS, OP_CLASS_BIN, 12, OP_ASSOC_LEFT, 0 }, /* postfix decrement */ { "--", TOK_OP_DECPOST, TOK_OP_AMB_DECR, OP_CLASS_POST, 16, OP_ASSOC_LEFT, 0 }, /* unary plus */ { "+", TOK_OP_UPLUS, TOK_OP_AMB_PLUS, OP_CLASS_PRE, 15, OP_ASSOC_RIGHT, 0 }, /* prefix increment */ { "++", TOK_OP_INCPRE, TOK_OP_AMB_INCR, OP_CLASS_PRE, 15, OP_ASSOC_RIGHT, 0 }, /* add */ { "+", TOK_OP_PLUS, TOK_OP_AMB_PLUS, OP_CLASS_BIN, 12, OP_ASSOC_LEFT, 0 }, /* compound plus assignemnt */ { "+=", TOK_OP_COPLUS, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* postfix increment */ { "++", TOK_OP_INCPOST, TOK_OP_AMB_INCR, OP_CLASS_POST, 16, OP_ASSOC_LEFT, 0 }, /* divide */ { "/", TOK_OP_DIVIDE, 0, OP_CLASS_BIN, 13, OP_ASSOC_LEFT, 0 }, /* compound divide assignment */ { "/=", TOK_OP_CODIVIDE, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* multiply */ { "*", TOK_OP_MULTI, TOK_OP_AMB_MULTI, OP_CLASS_BIN, 13, OP_ASSOC_LEFT, 0 }, /* compound multiply assignment */ { "*=", TOK_OP_COMULTI, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* dereference pointer */ { "*", TOK_OP_DEREF, TOK_OP_AMB_MULTI, OP_CLASS_PRE, 15, OP_ASSOC_RIGHT, 0 }, /* modulo */ { "%", TOK_OP_MOD, 0, OP_CLASS_BIN, 13, OP_ASSOC_LEFT, 0 }, /* compound modulo assignment */ { "%=", TOK_OP_COMOD, 0, OP_CLASS_BIN , 2, OP_ASSOC_RIGHT, 0 }, /* bitwise and */ { "&", TOK_OP_BAND, TOK_OP_AMB_BAND, OP_CLASS_BIN, 8, OP_ASSOC_LEFT, 0 }, /* compound bitwise and assignment */ { "&=", TOK_OP_COBAND, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* logical and */ { "&&", TOK_OP_LAND, 0, OP_CLASS_BIN, 5, OP_ASSOC_LEFT, 1 }, /* address-of */ { "&", TOK_OP_ADDR, TOK_OP_AMB_BAND, OP_CLASS_BIN, 15, OP_ASSOC_RIGHT, 0 }, /* bitwise or */ { "|", TOK_OP_BOR, 0, OP_CLASS_BIN, 6, OP_ASSOC_LEFT, 0 }, /* compound bitwise or assignment */ { "|=", TOK_OP_COBOR, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* logical or */ { "||", TOK_OP_LOR, 0, OP_CLASS_BIN, 4, OP_ASSOC_LEFT, 1 }, /* bitwise xor */ { "^", TOK_OP_BXOR, 0, OP_CLASS_BIN, 7, OP_ASSOC_LEFT, 0 }, /* compound bitwise xor assignment */ { "^=", TOK_OP_COBXOR, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* bitwise negation */ { "~", TOK_OP_BNEG, 0, OP_CLASS_PRE, 15, OP_ASSOC_RIGHT, 0 }, /* smaller than */ { "<", TOK_OP_SMALL, 0, OP_CLASS_BIN, 10, OP_ASSOC_LEFT, 0 }, /* smaller than or equal */ { "<=", TOK_OP_SMALLEQ, 0, OP_CLASS_BIN, 10, OP_ASSOC_LEFT, 0 }, /* bitwise shift left */ { "<<", TOK_OP_BSHL, 0, OP_CLASS_BIN, 11, OP_ASSOC_LEFT, 0 }, /* compound bitwise shift left assignment */ { "<<=", TOK_OP_COBSHL, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* greater than */ { ">", TOK_OP_GREAT, 0, OP_CLASS_BIN, 10, OP_ASSOC_LEFT, 0 }, /* greater than or equal */ { ">=", TOK_OP_GREATEQ, 0, OP_CLASS_BIN, 10, OP_ASSOC_LEFT, 0 }, /* bitwise shift right */ { ">>", TOK_OP_BSHR, 0, OP_CLASS_BIN, 11, OP_ASSOC_LEFT, 0 }, /* compound bitwise shift right assignment */ { ">>=", TOK_OP_COBSHR, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* assignment */ { "=", TOK_OP_ASSIGN, 0, OP_CLASS_BIN, 2, OP_ASSOC_RIGHT, 0 }, /* logical equality */ { "==", TOK_OP_LEQU, 0, OP_CLASS_BIN, 9, OP_ASSOC_LEFT, 0 }, /* logical negation */ { "!", TOK_OP_LNEG, 0, OP_CLASS_PRE, 15, OP_ASSOC_RIGHT, 0 }, /* logical inequality */ { "!=", TOK_OP_LNEQU, 0, OP_CLASS_BIN, 9, OP_ASSOC_LEFT, 0 }, /* access structure / union member */ { ".", TOK_OP_STRUMEMB, 0, OP_CLASS_POST, 16, OP_ASSOC_LEFT, 0 }, /* comma operator */ { ",", TOK_OP_COMMA, 0, OP_CLASS_BIN, 1, OP_ASSOC_LEFT, 1 }, /* conditional operator 1 */ { "?", TOK_OP_COND, 0, OP_CLASS_TER, 3, OP_ASSOC_RIGHT, 1 }, /* conditional operator 2 */ { ":", TOK_OP_COND2, TOK_OP_AMB_COND2, OP_CLASS_TER, 3, OP_ASSOC_RIGHT, 0 }, { "ZORG", 0, 0, 0, 0, 0, 0 }, { NULL, 0, 0, 0, 0, 0, 0 } }; char op_lookup[256]; char op_lookup2[256]; /* * Initializes operator lookup table. Refer to init_keylookup() */ void init_oplookup(void) { static char op_chars[] = { '-', '+', '/', '*', '%', '&', '|', '^', '~', '<', '>', '=', '!', '.', ',', '?', ':', 0 }; unsigned int i; unsigned int j; memset(op_lookup, 0, sizeof op_lookup); for (i = 0; i < sizeof op_chars; ++i) { for (j = 0; operators[j].name != NULL; ++j) { if (operators[j].name[0] == op_chars[i]) { op_lookup[ (unsigned)op_chars[i] ] = j; break; } } } memset(op_lookup2, 0, sizeof op_lookup2); for (i = 0; i <= TOK_OP_MAX - TOK_OP_MIN; ++i) { for (j = 0; operators[j].name != NULL; ++j) { if ((unsigned)operators[j].value == (i + TOK_OP_MIN)) { op_lookup2[i] = j; break; } } } } /* * Maps operator in ascii specified by ``name'' to according index in * operator table. Returns index on success, else -1 */ int lookup_op(const char *name) { int i; char c = *name; if ((i = LOOKUP_OP((unsigned)c)) == 0) { return -1; } for (; operators[i].name[i] == c; ++i) { if (strcmp(operators[i].name, name) == 0) { return i; } } return -1; } /* * Maps numeric operator code to operator name in ascii and returns a * pointer to that on success, else NULL */ char * lookup_operator(int value) { int i; for (i = 0; operators[i].name != NULL; ++i) { if (value == operators[i].value || value == operators[i].is_ambig) { return operators[i].name; } } return NULL; } /* * Gets index for operator ``value'' in operator table - using the * first character of its ascii representation as starting point to * search */ int get_opind_by_value(char firstch, int value) { int i; if ((i = LOOKUP_OP((unsigned)firstch)) == 0) { return -1; } do { if (operators[i].value == value) { return i; } } while (operators[++i].name[0] == firstch); return -1; }