#include <stdlib.h>

#ifdef USE_NLLIBC
#include <nllibc.h>
#endif

#include "type.h"

static struct word {
  c_type_t type;
  char *word;
} words[] = {
  { C_TYPE_NONE,         "NONE" },

  { C_TYPE_WORD,         "WORD" },
  { C_TYPE_WORDS,        "WORDS" },

  { C_TYPE_NUMBER,       "NUMBER" },
  { C_TYPE_STRING,       "STRING" },
  { C_TYPE_MODEL,        "MODEL" },
  { C_TYPE_SYMBOL,       "SYMBOL" },
  { C_TYPE_ARRAY,        "ARRAY" },
  { C_TYPE_VALUE,        "VALUE" },
  { C_TYPE_VARIABLE,     "VARIABLE" },
  { C_TYPE_FUNCTION,     "FUNCTION" },
  { C_TYPE_LABEL,        "LABEL" },
  { C_TYPE_LONGLONG,     "LONGLONG" },
  { C_TYPE_LONGDOUBLE,   "LONGDOUBLE" },
  { C_TYPE_BLOCK,        "BLOCK" },
  { C_TYPE_STACK,        "STACK" },
  { C_TYPE_NOP,          "NOP" },

  { C_TYPE_ADDRESS,      "ADDRESS" },
  { C_TYPE_POINTER,      "POINTER" },
  { C_TYPE_PLUS,         "PLUS" },
  { C_TYPE_MINUS,        "MINUS" },
  { C_TYPE_CAST,         "CAST" },
  { C_TYPE_ARG,          "ARG" },

  { C_TYPE_COMMENT_IN,   "/*" },
  { C_TYPE_COMMENT_OUT,  "*/" },
  { C_TYPE_SQUOAT,       "\'" },
  { C_TYPE_DQUOAT,       "\"" },

  { C_TYPE_IF,           "if" },
  { C_TYPE_ELSE,         "else" },
  { C_TYPE_FOR,          "for" },
  { C_TYPE_WHILE,        "while" },
  { C_TYPE_DO,           "do" },
  { C_TYPE_SWITCH,       "switch" },
  { C_TYPE_CASE,         "case" },
  { C_TYPE_DEFAULT,      "default" },
  { C_TYPE_GOTO,         "goto" },
  { C_TYPE_BREAK,        "break" },
  { C_TYPE_CONTINUE,     "continue" },
  { C_TYPE_RETURN,       "return" },

  { C_TYPE_EXTERN,       "extern" },
  { C_TYPE_STATIC,       "static" },

  { C_TYPE_SIGNED,       "signed" },
  { C_TYPE_UNSIGNED,     "unsigned" },
  { C_TYPE_SHORT,        "short" },
  { C_TYPE_LONG,         "long" },
  { C_TYPE_CHAR,         "char" },
  { C_TYPE_INT,          "int" },
  { C_TYPE_FLOAT,        "float" },
  { C_TYPE_DOUBLE,       "double" },
  { C_TYPE_VOID,         "void" },
  { C_TYPE_STRUCT,       "struct" },
  { C_TYPE_UNION,        "union" },
  { C_TYPE_ENUM,         "enum" },
  { C_TYPE_TYPEDEF,      "typedef" },
  { C_TYPE_CONST,        "const" },
  { C_TYPE_RESTRICT,     "restrict" },
  { C_TYPE_REGISTER,     "register" },
  { C_TYPE_INLINE,       "inline" },
  { C_TYPE_VOLATILE,     "volatile" },

  { C_TYPE_SIZEOF,       "sizeof" },
  { C_TYPE_RSHIFTEQ,     ">>=" },
  { C_TYPE_LSHIFTEQ,     "<<=" },
  { C_TYPE_VARARG,       "..." },

  { C_TYPE_ARROW,        "->" },
  { C_TYPE_INC,          "++x" },
  { C_TYPE_DEC,          "--x" },
  { C_TYPE_INCA,         "x++" },
  { C_TYPE_DECA,         "x--" },
  { C_TYPE_ADDEQ,        "+=" },
  { C_TYPE_SUBEQ,        "-=" },
  { C_TYPE_MULEQ,        "*=" },
  { C_TYPE_DIVEQ,        "/=" },
  { C_TYPE_MODEQ,        "%=" },
  { C_TYPE_ANDEQ,        "&=" },
  { C_TYPE_XOREQ,        "^=" },
  { C_TYPE_OREQ,         "|=" },
  { C_TYPE_RSHIFT,       ">>" },
  { C_TYPE_LSHIFT,       "<<" },
  { C_TYPE_GTEQ,         ">=" },
  { C_TYPE_LTEQ,         "<=" },
  { C_TYPE_EQEQ,         "==" },
  { C_TYPE_NEQ,          "!=" },
  { C_TYPE_ANDAND,       "&&" },
  { C_TYPE_OROR,         "||" },

  { C_TYPE_ADD,          "+" },
  { C_TYPE_SUB,          "-" },
  { C_TYPE_MUL,          "*" },
  { C_TYPE_DIV,          "/" },
  { C_TYPE_MOD,          "%" },
  { C_TYPE_AND,          "&" },
  { C_TYPE_XOR,          "^" },
  { C_TYPE_OR,           "|" },
  { C_TYPE_INV,          "~" },
  { C_TYPE_GT,           ">" },
  { C_TYPE_LT,           "<" },
  { C_TYPE_EQ,           "=" },
  { C_TYPE_NOT,          "!" },
  { C_TYPE_DOT,          "." },
  { C_TYPE_COMMA,        "," },
  { C_TYPE_QUESTION,     "?" },

  { C_TYPE_COLON,        ":" },
  { C_TYPE_SEMICOLON,    ";" },
  { C_TYPE_BRACKET_IN,   "(" },
  { C_TYPE_BRACKET_OUT,  ")" },
  { C_TYPE_MBRACKET_IN,  "{" },
  { C_TYPE_MBRACKET_OUT, "}" },
  { C_TYPE_BBRACKET_IN,  "[" },
  { C_TYPE_BBRACKET_OUT, "]" },

  { C_TYPE_EXT_EXTENSION,   "__extension__" },
  { C_TYPE_EXT_ATTRIBUTE,   "__attribute__" },
  { C_TYPE_EXT_CONST,       "__const" },
  { C_TYPE_EXT_RESTRICT,    "__restrict" },
  { C_TYPE_EXT_INLINE,      "__inline" },
  { C_TYPE_EXT_ASM,         "__asm" },
  { C_TYPE_EXT_DEAD2,       "__dead2" },
  { C_TYPE_EXT_PURE2,       "__pure2" },
  { C_TYPE_EXT_UNUSED,      "__unused" },
  { C_TYPE_EXT_USED,        "__used" },
  { C_TYPE_EXT_PACKED,      "__packed" },
  { C_TYPE_EXT_ALIGNED,     "__aligned" },
  { C_TYPE_EXT_ALIGNOF,     "__alignof" },
  { C_TYPE_EXT_SECTION,     "__section" },
  { C_TYPE_EXT_WEAK_SYMBOL, "__weak_symbol" },

  { C_TYPE_C11_ALIGNAS,       "_Alignas" },
  { C_TYPE_C11_ALIGNOF,       "_Alignof" },
  { C_TYPE_C11_ATOMIC,        "_Atomic" },
  { C_TYPE_C11_NORETURN,      "_Noreturn" },
  { C_TYPE_C11_STATIC_ASSERT, "_Static_assert" },
  { C_TYPE_C11_THREAD_LOCAL,  "_Thread_local" },

  { C_TYPE_CLANG_NONNULL,  "_Nonnull" },
  { C_TYPE_CLANG_NULLABLE, "_Nullable" },

  { C_TYPE_BUILTIN_EXPECT,         "__builtin_expect" },
  { C_TYPE_BUILTIN_PREFETCH,       "__builtin_prefetch" },
  { C_TYPE_BUILTIN_CONSTANT_P,     "__builtin_constant_p" },
  { C_TYPE_BUILTIN_FRAME_ADDRESS,  "__builtin_frame_address" },
  { C_TYPE_BUILTIN_RETURN_ADDRESS, "__builtin_return_address" },

  { C_TYPE_NLCC_TYPE_TYPE,         "__nlcc_type_type" },
  { C_TYPE_NLCC_TYPE_SYMBOL,       "__nlcc_type_symbol" },
  { C_TYPE_NLCC_ATTR_FUNCNOINIT,   "__nlcc_attr_funcnoinit" },

  { C_TYPE_SHARP,        "#" },

  { C_TYPE_NONE,          NULL }
};

/*****************************************************************
 * library
 */

char *type_get_word(c_type_t type)
{
  int i;
  for (i = 0; words[i].word; i++) {
    if (words[i].type == type)
      return words[i].word;
  }
  return NULL;
}
