/* $Id: keyword.c,v 1.2 2008/10/28 16:51:12 kiesling Exp $ */

/*
  This file is part of ctalk.
  Copyright © 2005-2008  Robert Kiesling, ctalk@ctalklang.org.
  Permission is granted to copy this software provided that this copyright
  notice is included in all source code modules.

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software Foundation, 
  Inc., 51 Franklin St., Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <string.h>
#include "cvar.h"

#define FALSE 0
#define TRUE !(FALSE)

#define N_CTALK_KEYWORDS 10

int is_ctalk_keyword (const char *s) {
  int i, is_keyword;
  char *ctalk_keywords[] = {
    "self",
    "super",
    "value",
    "arg",
    "require",
    "instanceMethod",
    "classMethod",
    "instanceVariable",
    "classVariable",
    "returnObjectClass",
    "noMethodInit"
  };

  for (i = 0, is_keyword = FALSE;
       (i < N_CTALK_KEYWORDS) && ! is_keyword;
       i++) {
    if (!strcmp (s, ctalk_keywords[i]))
      is_keyword = TRUE;
  }
  return is_keyword;
}

#ifdef __GNUC__
#define N_MACRO_KEYWORDS 18
#else
#define N_MACRO_KEYWORDS 14
#endif

int is_macro_keyword (const char *s) {

  int i, is_keyword;
  char *macro_keywords[] = {
    "include",
#ifdef __GNUC__
    "include_next",
    "ident",
    "sccs",
    "unassert",
#endif
    "define",
    "undef",
    "if",
    "ifdef",
    "ifndef",
    "else",
    "elif",
    "endif",
    "error",
    "warning",
    "assert",
    "line",
    "pragma",
  };

  for (i = 0, is_keyword = FALSE; 
       (i < N_MACRO_KEYWORDS) && ! is_keyword; 
       i++) {
    if (!strcmp (s, macro_keywords[i]))
      is_keyword = TRUE;
  }
  return is_keyword;
}

static char *c_keywords[] = {
  "auto",
  "break",
  "case",
  "char",
  "const",
  "continue",
  "default",
  "do",
  "double",
  "else",
  "enum",
  "extern",
  "float",
  "for",
  "goto",
  "if",
  "inline",
  "int",
  "long",
  "register",
  "restrict",
  "return",
  "short",
  "signed",
  "sizeof",
  "static",
  "struct",
  "switch",
  "typedef",
  "union",
  "unsigned",
  "void",
  "volatile",
  "while",
  "_Bool",
  "_Complex",
  "_Imaginary"
#ifdef __GNUC__
  , "__complex__"
#endif
};

#ifdef __GNUC__
# define N_C_KEYWORDS 38
# else
# define N_C_KEYWORDS 37
#endif

/* Check if a label is an ANSI C or C99 keyword, including data types.  
   A subset that checks only the data types is below.
*/

#ifdef __GNUC__
inline
#endif
int is_c_keyword (const char *s) {

  int i;

  for (i = 0; i < N_C_KEYWORDS; i++) {
    if (!strcmp (s, c_keywords[i]))
      return TRUE;
  }

  return FALSE;
}

/* 
 *    Check if a label is an ANSI C data type.  This is a subset of
 *    the ANSI C keywords, above.
*/

static char *c_data_types[] = {
  "char",
  "const",
  "double",
  "enum",
  "extern",
  "float",
  "inline",
  "int",
  "long",
  "register",
  "short",
  "signed",
  "static",
  "struct",
  "union",
  "unsigned",
  "void",
  "volatile",
  "_Bool",
  "_Complex",
  "_Imaginary"
#ifdef __GNUC__
  , "__complex__",
  "__inline__"
#endif
};

#ifdef __GNUC__
# define N_C_DATA_TYPES 23
# else
# define N_C_DATA_TYPES 21
#endif

/* 
 *    Check if a label is an ANSI C data type.  This is a subset of
 *    the ANSI C keywords, above.
*/

#ifdef __GNUC__
inline
#endif
int is_c_data_type (const char *s) {

  int i;

  for (i = 0; i < N_C_DATA_TYPES; i++)
    if (!strcmp (s, c_data_types[i]))
      return TRUE;

  return FALSE;
}

static struct _type_attr_struct {
  char *name;
  int attr;
} type_attrs[] = {
  { "char",          CVAR_TYPE_CHAR},
  { "const",         CVAR_TYPE_CONST},
  { "double",        CVAR_TYPE_DOUBLE},
  { "enum",          CVAR_TYPE_ENUM},
  { "extern",        CVAR_TYPE_EXTERN},
  { "float",         CVAR_TYPE_FLOAT},
  { "inline",        CVAR_TYPE_INLINE},
  { "int",           CVAR_TYPE_INT},
  { "long",          CVAR_TYPE_LONG},
  { "register",      CVAR_TYPE_REGISTER},
  { "short",         CVAR_TYPE_SHORT},
  { "signed",        CVAR_TYPE_SIGNED},
  { "static",        CVAR_TYPE_STATIC},
  { "struct",        CVAR_TYPE_STRUCT},
  { "union",         CVAR_TYPE_UNION},
  { "unsigned",      CVAR_TYPE_UNSIGNED},
  { "void",          CVAR_TYPE_VOID},
  { "volatile",      CVAR_TYPE_VOLATILE},
  { "_Bool",         CVAR_TYPE_BOOL},
  { "_Complex",      CVAR_TYPE_COMPLEX},
  { "_Imaginary",     CVAR_TYPE_IMAGINARY}
#ifdef __GNUC__
  , { "__complex__", CVAR_TYPE_GNU_COMPLEX},
  { "__inline__",    CVAR_TYPE_GNU_INLINE}
#endif
};

int is_c_data_type_attr (const char *s) {
  int i;

  for (i = 0; i < N_C_DATA_TYPES; i++)
    if (!strcmp (s, type_attrs[i].name))
      return type_attrs[i].attr;

  return FALSE;
}

static char *c_storage_classes[] = {
  "const",
  "extern",
  "inline",
  "register",
  "static",
  "volatile",
};

#define N_C_STORAGE_CLASSES 6

/* 
 *    Check if a label is an ANSI C storage class keyword.  
 *    This is a subset of the ANSI C keywords, above.
 */

#ifdef __GNUC__
inline
#endif
int is_c_storage_class (const char *s) {

  int i, returnval = FALSE;

  for (i = 0; i < N_C_STORAGE_CLASSES; i++)
    if (!strcmp (s, c_storage_classes[i]))
      returnval = TRUE;

  return returnval;
}

#ifdef __GNUC__

static char *gnu_c_extensions[] = {
  "__extension__",                 /* GNU C. */
  "__const",
  "__restrict",
  "__attribute__",
  "__mode__",
  "__inline",
  "__inline__"
}; 

#define N_GNU_EXTENSIONS 7

#else

#define N_GNU_EXTENSIONS 0

#endif

#ifdef __GNUC__
inline
#endif
int is_gnu_extension_keyword (const char *s) {

  int i, returnval = FALSE;

  for (i = 0; i < N_GNU_EXTENSIONS; i++)
    if (!strcmp (s, gnu_c_extensions[i]))
      returnval = TRUE;

  return returnval;
}

static char *c_ctrl_keywords[] = {
  "break",
  "case",
  "do",
  "else",
  "for",
  "goto",
  "if",
  "switch",
  "while"
};

#define N_CTRL_KEYWORDS 9

/*
 *  Check if a label is a control structure keyword.
 */

#ifdef __GNUC__
inline
#endif
int is_ctrl_keyword (const char *s) {

  int i;

  for (i = 0; i < N_CTRL_KEYWORDS; i++) {
    if (!strcmp (s, c_ctrl_keywords[i]))
      return TRUE;
  }

  return FALSE;
}

#ifdef __GNUC__

static char *gnuc_builtin_types[] = {
  "_pthread_descr_struct",
  "__builtin_va_list",
  "__dirstream"
#ifdef DJGPP
  ,"signal",
  "__dj_DIR"
#endif
};


#ifdef DJGPP
#define N_GNUC_BUILTIN_TYPES 5
#else
#define N_GNUC_BUILTIN_TYPES 3
#endif
#endif

#ifdef __GNUC__
inline
#endif
int is_gnuc_builtin_type (const char *s) {

#ifdef __GNUC__
  int i;

  for (i = 0; i < N_GNUC_BUILTIN_TYPES; i++) {
    if (!strcmp (s, gnuc_builtin_types[i]))
      return TRUE;
  }
#endif

  return FALSE;
}

