| /** |
| * @file keywords.cpp |
| * Manages the table of keywords. |
| * |
| * @author Ben Gardner |
| * @license GPL v2+ |
| */ |
| #include "uncrustify_types.h" |
| #include "prototypes.h" |
| #include "char_table.h" |
| #include "args.h" |
| #include <cstring> |
| #include <cerrno> |
| #include <cstdlib> |
| #include <map> |
| #include "unc_ctype.h" |
| |
| using namespace std; |
| |
| /* Dynamic keyword map */ |
| typedef map<string, c_token_t> dkwmap; |
| static dkwmap dkwm; |
| |
| |
| /** |
| * interesting static keywords - keep sorted. |
| * Table should include the Name, Type, and Language flags. |
| */ |
| static const chunk_tag_t keywords[] = |
| { |
| { "@catch", CT_CATCH, LANG_OC | LANG_CPP | LANG_C }, |
| { "@dynamic", CT_OC_DYNAMIC, LANG_OC | LANG_CPP | LANG_C }, |
| { "@end", CT_OC_END, LANG_OC | LANG_CPP | LANG_C }, |
| { "@finally", CT_FINALLY, LANG_OC | LANG_CPP | LANG_C }, |
| { "@implementation", CT_OC_IMPL, LANG_OC | LANG_CPP | LANG_C }, |
| { "@interface", CT_OC_INTF, LANG_OC | LANG_CPP | LANG_C }, |
| { "@interface", CT_CLASS, LANG_JAVA }, |
| { "@private", CT_PRIVATE, LANG_OC | LANG_CPP | LANG_C }, |
| { "@property", CT_OC_PROPERTY, LANG_OC | LANG_CPP | LANG_C }, |
| { "@protocol", CT_OC_PROTOCOL, LANG_OC | LANG_CPP | LANG_C }, |
| { "@selector", CT_OC_SEL, LANG_OC | LANG_CPP | LANG_C }, |
| { "@synthesize", CT_OC_DYNAMIC, LANG_OC | LANG_CPP | LANG_C }, |
| { "@throw", CT_THROW, LANG_OC }, |
| { "@try", CT_TRY, LANG_OC | LANG_CPP | LANG_C }, |
| { "NS_ENUM", CT_ENUM, LANG_OC }, |
| { "NS_OPTIONS", CT_ENUM, LANG_OC }, |
| { "_Bool", CT_TYPE, LANG_CPP }, |
| { "_Complex", CT_TYPE, LANG_CPP }, |
| { "_Imaginary", CT_TYPE, LANG_CPP }, |
| { "__attribute__", CT_ATTRIBUTE, LANG_C | LANG_CPP }, |
| { "__block", CT_QUALIFIER, LANG_OC }, |
| { "__const__", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "__except", CT_CATCH, LANG_C | LANG_CPP }, |
| { "__finally", CT_FINALLY, LANG_C | LANG_CPP }, |
| { "__inline__", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "__restrict", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "__signed__", CT_TYPE, LANG_C | LANG_CPP }, |
| { "__thread", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "__traits", CT_QUALIFIER, LANG_D }, |
| { "__try", CT_TRY, LANG_C | LANG_CPP }, |
| { "__typeof__", CT_SIZEOF, LANG_C | LANG_CPP }, |
| { "__volatile__", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "abstract", CT_QUALIFIER, LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, |
| { "add", CT_GETSET, LANG_CS }, |
| { "alias", CT_QUALIFIER, LANG_D }, |
| { "align", CT_ALIGN, LANG_D }, |
| { "alignof", CT_SIZEOF, LANG_C | LANG_CPP }, |
| { "and", CT_SBOOL, LANG_C | LANG_CPP | FLAG_PP }, |
| { "and_eq", CT_SASSIGN, LANG_C | LANG_CPP }, |
| { "as", CT_AS, LANG_CS }, |
| { "asm", CT_ASM, LANG_C | LANG_CPP | LANG_D }, |
| { "assert", CT_ASSERT, LANG_JAVA }, |
| { "assert", CT_FUNCTION, LANG_D | LANG_PAWN }, // PAWN |
| { "assert", CT_PP_ASSERT, LANG_PAWN | FLAG_PP }, // PAWN |
| { "auto", CT_QUALIFIER, LANG_C | LANG_CPP | LANG_D }, |
| { "base", CT_BASE, LANG_CS | LANG_VALA }, |
| { "bit", CT_TYPE, LANG_D }, |
| { "bitand", CT_ARITH, LANG_C | LANG_CPP }, |
| { "bitor", CT_ARITH, LANG_C | LANG_CPP }, |
| { "body", CT_BODY, LANG_D }, |
| { "bool", CT_TYPE, LANG_CPP | LANG_CS | LANG_VALA }, |
| { "boolean", CT_TYPE, LANG_JAVA | LANG_ECMA }, |
| { "break", CT_BREAK, LANG_ALL }, // PAWN |
| { "byte", CT_TYPE, LANG_CS | LANG_D | LANG_JAVA | LANG_ECMA }, |
| { "callback", CT_QUALIFIER, LANG_VALA }, |
| { "case", CT_CASE, LANG_ALL }, // PAWN |
| { "cast", CT_D_CAST, LANG_D }, |
| { "catch", CT_CATCH, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_ECMA }, |
| { "cdouble", CT_TYPE, LANG_D }, |
| { "cent", CT_TYPE, LANG_D }, |
| { "cfloat", CT_TYPE, LANG_D }, |
| { "char", CT_CHAR, LANG_PAWN }, // PAWN |
| { "char", CT_TYPE, LANG_ALLC }, |
| { "checked", CT_QUALIFIER, LANG_CS }, |
| { "class", CT_CLASS, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, |
| { "compl", CT_ARITH, LANG_C | LANG_CPP }, |
| { "const", CT_QUALIFIER, LANG_ALL }, // PAWN |
| { "const_cast", CT_TYPE_CAST, LANG_CPP }, |
| { "constexpr", CT_QUALIFIER, LANG_CPP }, |
| { "construct", CT_CONSTRUCT, LANG_VALA }, |
| { "continue", CT_CONTINUE, LANG_ALL }, // PAWN |
| { "creal", CT_TYPE, LANG_D }, |
| { "dchar", CT_TYPE, LANG_D }, |
| { "debug", CT_DEBUG, LANG_D }, |
| { "debugger", CT_DEBUGGER, LANG_ECMA }, |
| { "decltype", CT_SIZEOF, LANG_CPP }, |
| { "default", CT_DEFAULT, LANG_ALL }, // PAWN |
| { "define", CT_PP_DEFINE, LANG_ALL | FLAG_PP }, // PAWN |
| { "defined", CT_DEFINED, LANG_PAWN }, // PAWN |
| { "defined", CT_PP_DEFINED, LANG_ALLC | FLAG_PP }, |
| { "delegate", CT_DELEGATE, LANG_CS | LANG_D }, |
| { "delete", CT_DELETE, LANG_CPP | LANG_D | LANG_ECMA }, |
| { "deprecated", CT_QUALIFIER, LANG_D }, |
| { "do", CT_DO, LANG_ALL }, // PAWN |
| { "double", CT_TYPE, LANG_ALLC }, |
| { "dynamic_cast", CT_TYPE_CAST, LANG_CPP }, |
| { "elif", CT_PP_ELSE, LANG_ALLC | FLAG_PP }, |
| { "else", CT_ELSE, LANG_ALL }, // PAWN |
| { "else", CT_PP_ELSE, LANG_ALL | FLAG_PP }, // PAWN |
| { "elseif", CT_PP_ELSE, LANG_PAWN | FLAG_PP }, // PAWN |
| { "emit", CT_PP_EMIT, LANG_PAWN | FLAG_PP }, // PAWN |
| { "endif", CT_PP_ENDIF, LANG_ALL | FLAG_PP }, // PAWN |
| { "endinput", CT_PP_ENDINPUT, LANG_PAWN | FLAG_PP }, // PAWN |
| { "endregion", CT_PP_ENDREGION, LANG_ALL | FLAG_PP }, |
| { "endscript", CT_PP_ENDINPUT, LANG_PAWN | FLAG_PP }, // PAWN |
| { "enum", CT_ENUM, LANG_ALL }, // PAWN |
| { "error", CT_PP_ERROR, LANG_PAWN | FLAG_PP }, // PAWN |
| { "event", CT_TYPE, LANG_CS }, |
| { "exit", CT_FUNCTION, LANG_PAWN }, // PAWN |
| { "explicit", CT_TYPE, LANG_C | LANG_CPP | LANG_CS }, |
| { "export", CT_EXPORT, LANG_C | LANG_CPP | LANG_D | LANG_ECMA }, |
| { "extends", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, |
| { "extern", CT_EXTERN, LANG_C | LANG_CPP | LANG_CS | LANG_D | LANG_VALA }, |
| { "false", CT_WORD, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA }, |
| { "file", CT_PP_FILE, LANG_PAWN | FLAG_PP }, // PAWN |
| { "final", CT_QUALIFIER, LANG_CPP | LANG_D | LANG_ECMA }, |
| { "finally", CT_FINALLY, LANG_D | LANG_CS | LANG_ECMA | LANG_JAVA }, |
| { "flags", CT_TYPE, LANG_VALA }, |
| { "float", CT_TYPE, LANG_ALLC }, |
| { "for", CT_FOR, LANG_ALL }, // PAWN |
| { "foreach", CT_FOR, LANG_CS | LANG_D | LANG_VALA }, |
| { "foreach_reverse", CT_FOR, LANG_D }, |
| { "forward", CT_FORWARD, LANG_PAWN }, // PAWN |
| { "friend", CT_FRIEND, LANG_CPP }, |
| { "function", CT_FUNCTION, LANG_D | LANG_ECMA }, |
| { "get", CT_GETSET, LANG_CS | LANG_VALA }, |
| { "goto", CT_GOTO, LANG_ALL }, // PAWN |
| { "idouble", CT_TYPE, LANG_D }, |
| { "if", CT_IF, LANG_ALL }, // PAWN |
| { "if", CT_PP_IF, LANG_ALL | FLAG_PP }, // PAWN |
| { "ifdef", CT_PP_IF, LANG_ALLC | FLAG_PP }, |
| { "ifloat", CT_TYPE, LANG_D }, |
| { "ifndef", CT_PP_IF, LANG_ALLC | FLAG_PP }, |
| { "implements", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, |
| { "implicit", CT_QUALIFIER, LANG_CS }, |
| { "import", CT_IMPORT, LANG_D | LANG_JAVA | LANG_ECMA }, // fudged to get indenting |
| { "import", CT_PP_INCLUDE, LANG_OC | FLAG_PP }, // ObjectiveC version of include |
| { "in", CT_IN, LANG_D | LANG_CS | LANG_VALA | LANG_ECMA | LANG_OC }, |
| { "include", CT_PP_INCLUDE, LANG_C | LANG_CPP | LANG_PAWN | FLAG_PP }, // PAWN |
| { "inline", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "inout", CT_QUALIFIER, LANG_D }, |
| { "instanceof", CT_SIZEOF, LANG_JAVA | LANG_ECMA }, |
| { "int", CT_TYPE, LANG_ALLC }, |
| { "interface", CT_CLASS, LANG_C | LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, |
| { "internal", CT_QUALIFIER, LANG_CS }, |
| { "invariant", CT_INVARIANT, LANG_D }, |
| { "ireal", CT_TYPE, LANG_D }, |
| { "is", CT_SCOMPARE, LANG_D | LANG_CS | LANG_VALA }, |
| { "lazy", CT_LAZY, LANG_D }, |
| { "line", CT_PP_LINE, LANG_PAWN | FLAG_PP }, // PAWN |
| { "lock", CT_LOCK, LANG_CS | LANG_VALA }, |
| { "long", CT_TYPE, LANG_ALLC }, |
| { "macro", CT_D_MACRO, LANG_D }, |
| { "mixin", CT_CLASS, LANG_D }, // may need special handling |
| { "module", CT_D_MODULE, LANG_D }, |
| { "mutable", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "namespace", CT_NAMESPACE, LANG_CPP | LANG_CS | LANG_VALA }, |
| { "native", CT_NATIVE, LANG_PAWN }, // PAWN |
| { "native", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, |
| { "new", CT_NEW, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_PAWN | LANG_VALA | LANG_ECMA }, // PAWN |
| { "not", CT_SARITH, LANG_C | LANG_CPP }, |
| { "not_eq", CT_SCOMPARE, LANG_C | LANG_CPP }, |
| { "null", CT_TYPE, LANG_CS | LANG_D | LANG_JAVA | LANG_VALA }, |
| { "object", CT_TYPE, LANG_CS }, |
| { "operator", CT_OPERATOR, LANG_CPP | LANG_CS | LANG_PAWN }, // PAWN |
| { "or", CT_SBOOL, LANG_C | LANG_CPP | FLAG_PP }, |
| { "or_eq", CT_SASSIGN, LANG_C | LANG_CPP }, |
| { "out", CT_QUALIFIER, LANG_CS | LANG_D | LANG_VALA }, |
| { "override", CT_QUALIFIER, LANG_CS | LANG_D | LANG_VALA }, |
| { "package", CT_PRIVATE, LANG_D }, |
| { "package", CT_PACKAGE, LANG_ECMA | LANG_JAVA }, |
| { "params", CT_TYPE, LANG_CS }, |
| { "pragma", CT_PP_PRAGMA, LANG_ALL | FLAG_PP }, // PAWN |
| { "private", CT_PRIVATE, LANG_ALLC }, // not C |
| { "property", CT_PP_PROPERTY, LANG_CS | FLAG_PP }, |
| { "protected", CT_PRIVATE, LANG_ALLC }, // not C |
| { "public", CT_PRIVATE, LANG_ALL }, // PAWN // not C |
| { "readonly", CT_QUALIFIER, LANG_CS }, |
| { "real", CT_TYPE, LANG_D }, |
| { "ref", CT_QUALIFIER, LANG_CS | LANG_VALA }, |
| { "region", CT_PP_REGION, LANG_ALL | FLAG_PP }, |
| { "register", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "reinterpret_cast", CT_TYPE_CAST, LANG_C | LANG_CPP }, |
| { "remove", CT_GETSET, LANG_CS }, |
| { "restrict", CT_QUALIFIER, LANG_C | LANG_CPP }, |
| { "return", CT_RETURN, LANG_ALL }, // PAWN |
| { "sbyte", CT_TYPE, LANG_CS }, |
| { "scope", CT_D_SCOPE, LANG_D }, |
| { "sealed", CT_QUALIFIER, LANG_CS }, |
| { "section", CT_PP_SECTION, LANG_PAWN | FLAG_PP }, // PAWN |
| { "set", CT_GETSET, LANG_CS | LANG_VALA }, |
| { "short", CT_TYPE, LANG_ALLC }, |
| { "signal", CT_PRIVATE, LANG_VALA }, |
| { "signals", CT_PRIVATE, LANG_CPP }, |
| { "signed", CT_TYPE, LANG_C | LANG_CPP }, |
| { "sizeof", CT_SIZEOF, LANG_C | LANG_CPP | LANG_CS | LANG_PAWN }, // PAWN |
| { "sleep", CT_SIZEOF, LANG_PAWN }, // PAWN |
| { "stackalloc", CT_NEW, LANG_CS }, |
| { "state", CT_STATE, LANG_PAWN }, // PAWN |
| { "static", CT_QUALIFIER, LANG_ALL }, // PAWN |
| { "static_cast", CT_TYPE_CAST, LANG_CPP }, |
| { "stock", CT_STOCK, LANG_PAWN }, // PAWN |
| { "strictfp", CT_QUALIFIER, LANG_JAVA }, |
| { "string", CT_TYPE, LANG_CS }, |
| { "struct", CT_STRUCT, LANG_C | LANG_CPP | LANG_CS | LANG_D | LANG_VALA }, |
| { "super", CT_SUPER, LANG_D | LANG_JAVA | LANG_ECMA }, |
| { "switch", CT_SWITCH, LANG_ALL }, // PAWN |
| { "synchronized", CT_QUALIFIER, LANG_D | LANG_JAVA | LANG_ECMA }, |
| { "tagof", CT_TAGOF, LANG_PAWN }, // PAWN |
| { "template", CT_TEMPLATE, LANG_CPP | LANG_D }, |
| { "this", CT_THIS, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA | LANG_ECMA }, |
| { "throw", CT_THROW, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_ECMA }, |
| { "throws", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, |
| { "transient", CT_QUALIFIER, LANG_JAVA | LANG_ECMA }, |
| { "true", CT_WORD, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_VALA }, |
| { "try", CT_TRY, LANG_CPP | LANG_CS | LANG_D | LANG_JAVA | LANG_ECMA }, |
| { "tryinclude", CT_PP_INCLUDE, LANG_PAWN | FLAG_PP }, // PAWN |
| { "typedef", CT_TYPEDEF, LANG_C | LANG_CPP | LANG_D | LANG_OC }, |
| { "typeid", CT_SIZEOF, LANG_C | LANG_CPP | LANG_D }, |
| { "typename", CT_TYPENAME, LANG_CPP }, |
| { "typeof", CT_SIZEOF, LANG_C | LANG_CPP | LANG_CS | LANG_D | LANG_VALA | LANG_ECMA }, |
| { "ubyte", CT_TYPE, LANG_D }, |
| { "ucent", CT_TYPE, LANG_D }, |
| { "uint", CT_TYPE, LANG_CS | LANG_D }, |
| { "ulong", CT_TYPE, LANG_CS | LANG_D }, |
| { "unchecked", CT_QUALIFIER, LANG_CS }, |
| { "undef", CT_PP_UNDEF, LANG_ALL | FLAG_PP }, // PAWN |
| { "union", CT_UNION, LANG_C | LANG_CPP | LANG_D }, |
| { "unittest", CT_UNITTEST, LANG_D }, |
| { "unsafe", CT_UNSAFE, LANG_CS }, |
| { "unsigned", CT_TYPE, LANG_C | LANG_CPP }, |
| { "ushort", CT_TYPE, LANG_CS | LANG_D }, |
| { "using", CT_USING, LANG_CPP | LANG_CS | LANG_VALA }, |
| { "var", CT_TYPE, LANG_VALA | LANG_ECMA }, |
| { "version", CT_D_VERSION, LANG_D }, |
| { "virtual", CT_QUALIFIER, LANG_CPP | LANG_CS | LANG_VALA }, |
| { "void", CT_TYPE, LANG_ALLC }, |
| { "volatile", CT_QUALIFIER, LANG_C | LANG_CPP | LANG_CS | LANG_JAVA | LANG_ECMA }, |
| { "volatile", CT_VOLATILE, LANG_D }, |
| { "wchar", CT_TYPE, LANG_D }, |
| { "wchar_t", CT_TYPE, LANG_C | LANG_CPP }, |
| { "weak", CT_QUALIFIER, LANG_VALA }, |
| { "while", CT_WHILE, LANG_ALL }, // PAWN |
| { "with", CT_D_WITH, LANG_D | LANG_ECMA }, |
| { "xor", CT_SARITH, LANG_C | LANG_CPP }, |
| { "xor_eq", CT_SASSIGN, LANG_C | LANG_CPP }, |
| }; |
| |
| |
| void init_keywords() |
| { |
| } |
| |
| /** |
| * Compares two chunk_tag_t entries using strcmp on the strings |
| * |
| * @param p1 The 'left' entry |
| * @param p2 The 'right' entry |
| */ |
| static int kw_compare(const void *p1, const void *p2) |
| { |
| const chunk_tag_t *t1 = (const chunk_tag_t *)p1; |
| const chunk_tag_t *t2 = (const chunk_tag_t *)p2; |
| |
| return(strcmp(t1->tag, t2->tag)); |
| } |
| |
| |
| bool keywords_are_sorted(void) |
| { |
| int idx; |
| bool retval = true; |
| |
| for (idx = 1; idx < (int)ARRAY_SIZE(keywords); idx++) |
| { |
| if (kw_compare(&keywords[idx - 1], &keywords[idx]) > 0) |
| { |
| LOG_FMT(LERR, "%s: bad sort order at idx %d, words '%s' and '%s'\n", |
| __func__, idx - 1, keywords[idx - 1].tag, keywords[idx].tag); |
| retval = false; |
| } |
| } |
| return(retval); |
| } |
| |
| |
| /** |
| * Adds a keyword to the list of dynamic keywords |
| * |
| * @param tag The tag (string) must be zero terminated |
| * @param type The type, usually CT_TYPE |
| */ |
| void add_keyword(const char *tag, c_token_t type) |
| { |
| string ss = tag; |
| |
| /* See if the keyword has already been added */ |
| dkwmap::iterator it = dkwm.find(ss); |
| if (it != dkwm.end()) |
| { |
| LOG_FMT(LDYNKW, "%s: changed '%s' to %d\n", __func__, tag, type); |
| (*it).second = type; |
| return; |
| } |
| |
| /* Insert the keyword */ |
| dkwm.insert(dkwmap::value_type(ss, type)); |
| LOG_FMT(LDYNKW, "%s: added '%s' as %d\n", __func__, tag, type); |
| } |
| |
| |
| /** |
| * Backs up to the first string match in keywords. |
| */ |
| static const chunk_tag_t *kw_static_first(const chunk_tag_t *tag) |
| { |
| const chunk_tag_t *prev = tag - 1; |
| |
| while ((prev >= &keywords[0]) && (strcmp(prev->tag, tag->tag) == 0)) |
| { |
| tag = prev; |
| prev--; |
| } |
| //fprintf(stderr, "first:%s -", tag->tag); |
| return(tag); |
| } |
| |
| |
| static const chunk_tag_t *kw_static_match(const chunk_tag_t *tag) |
| { |
| bool in_pp = ((cpd.in_preproc != CT_NONE) && (cpd.in_preproc != CT_PP_DEFINE)); |
| bool pp_iter; |
| const chunk_tag_t *iter; |
| |
| for (iter = kw_static_first(tag); |
| iter < &keywords[ARRAY_SIZE(keywords)]; |
| iter++) |
| { |
| //fprintf(stderr, " check:%s", iter->tag); |
| pp_iter = (iter->lang_flags & FLAG_PP) != 0; |
| if ((strcmp(iter->tag, tag->tag) == 0) && |
| ((cpd.lang_flags & iter->lang_flags) != 0) && |
| (in_pp == pp_iter)) |
| { |
| //fprintf(stderr, " match:%s", iter->tag); |
| return(iter); |
| } |
| } |
| return(NULL); |
| } |
| |
| |
| /** |
| * Search first the dynamic and then the static table for a matching keyword |
| * |
| * @param word Pointer to the text -- NOT zero terminated |
| * @param len The length of the text |
| * @return CT_WORD (no match) or the keyword token |
| */ |
| c_token_t find_keyword_type(const char *word, int len) |
| { |
| string ss(word, len); |
| chunk_tag_t key; |
| const chunk_tag_t *p_ret; |
| |
| if (len <= 0) |
| { |
| return(CT_NONE); |
| } |
| |
| /* check the dynamic word list first */ |
| dkwmap::iterator it = dkwm.find(ss); |
| if (it != dkwm.end()) |
| { |
| return((*it).second); |
| } |
| |
| key.tag = ss.c_str(); |
| |
| /* check the static word list */ |
| p_ret = (const chunk_tag_t *)bsearch(&key, keywords, ARRAY_SIZE(keywords), |
| sizeof(keywords[0]), kw_compare); |
| if (p_ret != NULL) |
| { |
| p_ret = kw_static_match(p_ret); |
| } |
| return((p_ret != NULL) ? p_ret->type : CT_WORD); |
| } |
| |
| |
| /** |
| * Loads the dynamic keywords from a file |
| * |
| * @param filename The path to the file to load |
| * @return SUCCESS or FAILURE |
| */ |
| int load_keyword_file(const char *filename) |
| { |
| FILE *pf; |
| char buf[256]; |
| char *ptr; |
| char *args[3]; |
| int argc; |
| int line_no = 0; |
| |
| pf = fopen(filename, "r"); |
| if (pf == NULL) |
| { |
| LOG_FMT(LERR, "%s: fopen(%s) failed: %s (%d)\n", |
| __func__, filename, strerror(errno), errno); |
| cpd.error_count++; |
| return(FAILURE); |
| } |
| |
| while (fgets(buf, sizeof(buf), pf) != NULL) |
| { |
| line_no++; |
| |
| /* remove comments */ |
| if ((ptr = strchr(buf, '#')) != NULL) |
| { |
| *ptr = 0; |
| } |
| |
| argc = Args::SplitLine(buf, args, ARRAY_SIZE(args) - 1); |
| args[argc] = 0; |
| |
| if (argc > 0) |
| { |
| if ((argc == 1) && CharTable::IsKw1(*args[0])) |
| { |
| add_keyword(args[0], CT_TYPE); |
| } |
| else |
| { |
| LOG_FMT(LWARN, "%s:%d Invalid line (starts with '%s')\n", |
| filename, line_no, args[0]); |
| cpd.error_count++; |
| } |
| } |
| } |
| |
| fclose(pf); |
| return(SUCCESS); |
| } |
| |
| |
| void print_keywords(FILE *pfile) |
| { |
| for (dkwmap::iterator it = dkwm.begin(); it != dkwm.end(); ++it) |
| { |
| c_token_t tt = (*it).second; |
| if (tt == CT_TYPE) |
| { |
| fprintf(pfile, "type %*.s%s\n", |
| cpd.max_option_name_len - 4, " ", (*it).first.c_str()); |
| } |
| else if (tt == CT_MACRO_OPEN) |
| { |
| fprintf(pfile, "macro-open %*.s%s\n", |
| cpd.max_option_name_len - 11, " ", (*it).first.c_str()); |
| } |
| else if (tt == CT_MACRO_CLOSE) |
| { |
| fprintf(pfile, "macro-close %*.s%s\n", |
| cpd.max_option_name_len - 12, " ", (*it).first.c_str()); |
| } |
| else if (tt == CT_MACRO_ELSE) |
| { |
| fprintf(pfile, "macro-else %*.s%s\n", |
| cpd.max_option_name_len - 11, " ", (*it).first.c_str()); |
| } |
| else |
| { |
| const char *tn = get_token_name(tt); |
| |
| fprintf(pfile, "set %s %*.s%s\n", tn, |
| int(cpd.max_option_name_len - (4 + strlen(tn))), " ", (*it).first.c_str()); |
| } |
| } |
| } |
| |
| |
| void clear_keyword_file(void) |
| { |
| dkwm.clear(); |
| } |
| |
| |
| /** |
| * Returns the pattern that the keyword needs based on the token |
| */ |
| pattern_class get_token_pattern_class(c_token_t tok) |
| { |
| switch (tok) |
| { |
| case CT_IF: |
| case CT_ELSEIF: |
| case CT_SWITCH: |
| case CT_FOR: |
| case CT_WHILE: |
| case CT_USING_STMT: |
| case CT_LOCK: |
| case CT_D_WITH: |
| case CT_D_VERSION_IF: |
| case CT_D_SCOPE_IF: |
| return(PATCLS_PBRACED); |
| |
| case CT_ELSE: |
| return(PATCLS_ELSE); |
| |
| case CT_DO: |
| case CT_TRY: |
| case CT_FINALLY: |
| case CT_BODY: |
| case CT_UNITTEST: |
| case CT_UNSAFE: |
| case CT_VOLATILE: |
| case CT_GETSET: |
| return(PATCLS_BRACED); |
| |
| case CT_CATCH: |
| case CT_D_VERSION: |
| case CT_DEBUG: |
| return(PATCLS_OPBRACED); |
| |
| case CT_NAMESPACE: |
| return(PATCLS_VBRACED); |
| |
| case CT_WHILE_OF_DO: |
| return(PATCLS_PAREN); |
| |
| case CT_INVARIANT: |
| return(PATCLS_OPPAREN); |
| |
| default: |
| return(PATCLS_NONE); |
| } |
| } |