diff --git a/Tmain/list-params.d/run.sh b/Tmain/list-params.d/run.sh index 9b0db88da4..3ccb98bbdb 100644 --- a/Tmain/list-params.d/run.sh +++ b/Tmain/list-params.d/run.sh @@ -27,3 +27,7 @@ echo echo '# CPP MACHINABLE NOHEADER' ${C} --with-list-header=no --machinable --list-params=CPreProcessor echo + +echo '# CPP MACHINABLE NOHEADER + PARAM DEFINE WITH CMDLINE' +${C} --_paramdef-CPreProcessor='pragma,handle program' --with-list-header=no --machinable --list-params=CPreProcessor +echo diff --git a/Tmain/list-params.d/stdout-expected.txt b/Tmain/list-params.d/stdout-expected.txt index aac535bb01..1defe6a13c 100644 --- a/Tmain/list-params.d/stdout-expected.txt +++ b/Tmain/list-params.d/stdout-expected.txt @@ -59,3 +59,10 @@ define define replacement for an identifier (name(params,...)=definition) if0 examine code within "#if 0" branch (true or [false]) ignore a token to be specially handled +# CPP MACHINABLE NOHEADER + PARAM DEFINE WITH CMDLINE +_expand expand macros if their definitions are in the current C/C++/CUDA input file (true or [false]) +define define replacement for an identifier (name(params,...)=definition) +if0 examine code within "#if 0" branch (true or [false]) +ignore a token to be specially handled +pragma handle program + diff --git a/Units/paramdef.r/no-set.d/args.ctags b/Units/paramdef.r/no-set.d/args.ctags new file mode 100644 index 0000000000..988b97da76 --- /dev/null +++ b/Units/paramdef.r/no-set.d/args.ctags @@ -0,0 +1,11 @@ +--langdef=Foo +--map-Foo=.foo +--kinddef-Foo=v,xval,externally defined values +--_paramdef-Foo=VAR,desc +--regex-Foo=/(x)//{{ + /VAR _param { + /xval _tag _commit pop + } { + \1 /xval _tag _commit pop + } ifelse +}} diff --git a/Units/paramdef.r/no-set.d/expected.tags b/Units/paramdef.r/no-set.d/expected.tags new file mode 100644 index 0000000000..307fc70004 --- /dev/null +++ b/Units/paramdef.r/no-set.d/expected.tags @@ -0,0 +1 @@ +x input.foo /^x$/;" v diff --git a/Units/paramdef.r/no-set.d/input.foo b/Units/paramdef.r/no-set.d/input.foo new file mode 100644 index 0000000000..587be6b4c3 --- /dev/null +++ b/Units/paramdef.r/no-set.d/input.foo @@ -0,0 +1 @@ +x diff --git a/Units/paramdef.r/simple.d/args.ctags b/Units/paramdef.r/simple.d/args.ctags new file mode 100644 index 0000000000..36fd84f369 --- /dev/null +++ b/Units/paramdef.r/simple.d/args.ctags @@ -0,0 +1,10 @@ +--langdef=Foo +--map-Foo=.foo +--kinddef-Foo=v,xval,externally defined values +--_paramdef-Foo=VAR,desc +--regex-Foo=/(x)//{{ + /VAR _param { + /xval _tag _commit pop + } if +}} +--param-Foo.VAR=y diff --git a/Units/paramdef.r/simple.d/expected.tags b/Units/paramdef.r/simple.d/expected.tags new file mode 100644 index 0000000000..a6b4fb30fe --- /dev/null +++ b/Units/paramdef.r/simple.d/expected.tags @@ -0,0 +1 @@ +y input.foo /^x$/;" v diff --git a/Units/paramdef.r/simple.d/input.foo b/Units/paramdef.r/simple.d/input.foo new file mode 100644 index 0000000000..587be6b4c3 --- /dev/null +++ b/Units/paramdef.r/simple.d/input.foo @@ -0,0 +1 @@ +x diff --git a/docs/optscript.rst b/docs/optscript.rst index ed7aa32c3d..671a8d4fcc 100644 --- a/docs/optscript.rst +++ b/docs/optscript.rst @@ -232,6 +232,8 @@ Related options --list-fields + --_paramdef-=, + You can run optscript code fragments when pattern specified with options matches successfully. The options are ``--regex-``, ``--mline-regex-``, and ``--_mtable-regex-`` as you @@ -269,12 +271,18 @@ represents the field has an operator for reading (``:fieldname``). ``w`` represents the field has an operator for writing (``fieldname:``). +``--_paramdef-=,`` defines a language specific +parameter named ````. ``--param-.=`` assigns +a value ```` to the parameter. You can access the value from +Optscript code with ``_param`` operator. Don't use ``{`` character +in the description. The character is reserved for future extension. + Operators ............................ **.** -> ``-`` **.** ``corkIndex:int`` - Push the cork index for the tag + Push the cork index for the tag. **\\n** -> ``-`` **\\n** ``matchedString:string`` @@ -324,7 +332,45 @@ Data types Recipes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -TBW +Parameters +........................................... +With ``--_paramdef-=,`` option, you can +define a parser-specific parameter to your optlib parser. + +In the following example, we define a parser, ``Foo`` with a +parser-specific parameter ``VAR``. If the parser sees "x" in the +current input stream, a code fragment attached to the pattern "/(x)/" +runs. The code fragment does (1) check whether a value for ``VAR`` is +given, (2) emit a tag with the value given to parameter ``VAR`` as +name and with ``xval`` kind, and (3) remove the cork index from the +operand stack. + +foo.ctags: +.. code-block:: + + --langdef=Foo + --map-Foo=.foo + --kinddef-Foo=v,xval,externally defined values + --_paramdef-Foo=VAR,desc + --regex-Foo=/(x)//{{ + /VAR _param { % if VAR is defined .... + /xval _tag _commit pop + } if + % if VAR is not defined, we do nothing. + }} + +input.foo: +.. code-block:: + + x + +When running the parser, we can give a value ("hereiam" in the following example) +for the parameter ``VAR`` from the command line: + +.. code-block:: console + + $ ./ctags --options=args.ctags --param-Foo.VAR=hereiam -o - input.foo + hereiam input.foo /^x$/;" v Difference between Optscript and PostScript ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/main/lregex.c b/main/lregex.c index 6c8a999865..b47a891634 100644 --- a/main/lregex.c +++ b/main/lregex.c @@ -231,6 +231,7 @@ struct lregexControlBlock { struct guestRequest *guest_req; EsObject *local_dict; + hashTable*param_dict; ptrArray *hook[SCRIPT_HOOK_MAX]; ptrArray *hook_code[SCRIPT_HOOK_MAX]; @@ -341,6 +342,8 @@ extern struct lregexControlBlock* allocLregexControlBlock (parserDefinition *par lcb->tstack = ptrArrayNew(NULL); lcb->guest_req = guestRequestNew (); lcb->local_dict = es_nil; + lcb->param_dict = hashTableNew (3, hashCstrhash, hashCstreq, + eFree, eFree); for (int i = 0; i< SCRIPT_HOOK_MAX; i++) { @@ -373,6 +376,9 @@ extern void freeLregexControlBlock (struct lregexControlBlock* lcb) es_object_unref (lcb->local_dict); lcb->local_dict = es_nil; + hashTableDelete (lcb->param_dict); + lcb->param_dict = NULL; + for (int i = 0; i < SCRIPT_HOOK_MAX; i++) { ptrArrayDelete (lcb->hook[i]); @@ -3157,6 +3163,13 @@ extern void addOptscriptToHook (struct lregexControlBlock *lcb, enum scriptHook ptrArrayAdd (lcb->hook[hook], eStrdup (code)); } +extern void propagateParamToOptscript (struct lregexControlBlock *lcb, const char *param, const char *value) +{ + Assert (param); + Assert (value); + hashTablePutItem (lcb->param_dict, eStrdup (param), eStrdup (value)); +} + /* Return true if available. */ extern bool checkRegex (void) { @@ -4000,6 +4013,32 @@ static EsObject *lrop_makepromise (OptVM *vm, EsObject *name) return es_false; } +static EsObject *lrop_param (OptVM *vm, EsObject *name) +{ + struct lregexControlBlock *lcb = opt_vm_get_app_data (vm); + EsObject *key = opt_vm_ostack_top (vm); + if (es_object_get_type (key) != OPT_TYPE_NAME) + return OPT_ERR_TYPECHECK; + EsObject *key_sym = es_pointer_get (key); + const char *keyc = es_symbol_get (key_sym); + const char *valuec = hashTableGetItem (lcb->param_dict, keyc); + + if (valuec) + { + opt_vm_ostack_pop (vm); + EsObject *value = opt_string_new_from_cstr (valuec); + opt_vm_ostack_push (vm, value); + es_object_unref (value); + opt_vm_ostack_push (vm, es_true); + } + else + { + opt_vm_ostack_pop (vm); + opt_vm_ostack_push (vm, es_false); + } + return false; +} + static struct optscriptOperatorRegistration lropOperators [] = { { .name = "_matchstr", @@ -4165,6 +4204,13 @@ static struct optscriptOperatorRegistration lropOperators [] = { .help_str = "lang:string start:matchloc end:matchloc _MAKEPROMISE promise:int true%" "lang:string start:matchloc end:matchloc _MAKEPROMISE false", }, + { + .name = "_param", + .fn = lrop_param, + .arity = 1, + .help_str = "param:name _PARAM value:string true%" + "param:name _PARAM false", + }, }; extern void initRegexOptscript (void) diff --git a/main/lregex_p.h b/main/lregex_p.h index 663f71ba29..d271d092af 100644 --- a/main/lregex_p.h +++ b/main/lregex_p.h @@ -111,6 +111,7 @@ extern void initRegexOptscript (void); extern void listRegexOpscriptOperators (FILE *fp); extern void addOptscriptToHook (struct lregexControlBlock *lcb, enum scriptHook hook, const char *code); +extern void propagateParamToOptscript (struct lregexControlBlock *lcb, const char *param, const char *value); extern void printMultitableStatistics (struct lregexControlBlock *lcb); diff --git a/main/mini-geany.c b/main/mini-geany.c index d073106d15..0f05719953 100644 --- a/main/mini-geany.c +++ b/main/mini-geany.c @@ -184,6 +184,10 @@ static unsigned int ctagsGetLangCount(void) void addIgnoreSymbol(const char *value) { langType lang = getNamedLanguage ("CPreProcessor", 0); + /* + * In the future, we will rename applyParameter to + * applyLanguageParam. + */ applyParameter (lang, "ignore", value); } diff --git a/main/options.c b/main/options.c index b00a707773..3f6f3d1d64 100644 --- a/main/options.c +++ b/main/options.c @@ -381,6 +381,8 @@ static optionDescription LongOptionDescription [] = { {1,1," Copy patterns of a regex table to another regex table."}, {1,1," --_mtable-regex-=///[]"}, {1,1," Define multitable regular expression for locating tags in specific language."}, + {1,1," --_paramdef-=,"}, + {1,1," Define new param for ."}, {1,1," --_prelude-={{ optscript-code }}"}, {1,1," Specify code run before parsing with parser."}, {1,1," --_pretend-="}, @@ -1709,7 +1711,7 @@ static void processIf0Option (const char *const option, langType lang = getNamedLanguage ("CPreProcessor", 0); const char *arg = if0? "true": "false"; - applyParameter (lang, "if0", arg); + applyLanguageParam (lang, "if0", arg); } static void processLanguageForceOption ( @@ -2018,31 +2020,6 @@ extern bool processMapOption ( return true; } -extern bool processParamOption ( - const char *const option, const char *const value) -{ - langType language; - const char* name; - const char* sep; - - language = getLanguageComponentInOption (option, "param-"); - if (language == LANG_IGNORE) - return false; - - sep = option + strlen ("param-") + strlen (getLanguageName (language)); - /* `:' is only for keeping self compatibility */ - if (! (*sep == '.' || *sep == ':' )) - error (FATAL, "no separator(.) is given for %s=%s", option, value); - name = sep + 1; - - if (value == NULL || value [0] == '\0') - error (FATAL, "no value is given for %s", option); - - applyParameter (language, name, value); - - return true; -} - static void processLicenseOption ( const char *const option CTAGS_ATTR_UNUSED, const char *const parameter CTAGS_ATTR_UNUSED) @@ -2129,18 +2106,18 @@ static void processListParametersOption (const char *const option, const char *const parameter) { if (parameter [0] == '\0' || strcasecmp (parameter, RSV_LANG_ALL) == 0) - printLanguageParameters (LANG_AUTO, - localOption.withListHeader, localOption.machinable, - stdout); + printLanguageParams (LANG_AUTO, + localOption.withListHeader, localOption.machinable, + stdout); else { langType language = getNamedLanguage (parameter, 0); if (language == LANG_IGNORE) error (FATAL, "Unknown language \"%s\" in \"%s\" option", parameter, option); else - printLanguageParameters (language, - localOption.withListHeader, localOption.machinable, - stdout); + printLanguageParams (language, + localOption.withListHeader, localOption.machinable, + stdout); } exit (0); } @@ -2595,7 +2572,7 @@ static void readIgnoreList (const char *const list) while (token != NULL) { - applyParameter (lang, "ignore", token); + applyLanguageParam (lang, "ignore", token); token = strtok (NULL, IGNORE_SEPARATORS); } eFree (newList); @@ -2615,7 +2592,7 @@ static void addIgnoreListFromFile (const char *const fileName) for(i=0;i +typedef struct sParamObject { + paramDefinition *def; + freeParamDefFunc free; +} paramObject; + +struct paramControlBlock { + paramObject *param; + unsigned int count; + langType owner; +}; + +extern struct paramControlBlock* allocParamControlBlock (parserDefinition *parser) +{ + struct paramControlBlock *pcb; + + pcb = xMalloc (1, struct paramControlBlock); + pcb->param = xMalloc (parser->paramCount, paramObject); + pcb->count = parser->paramCount; + pcb->owner = parser->id; + + for (unsigned int i = 0; i < parser->paramCount; ++i) + { + paramObject *param = pcb->param + i; + param->def = parser->paramTable + i; + param->free = NULL; + } + + return pcb; +} + +extern void freeParamControlBlock (struct paramControlBlock* pcb) +{ + for (unsigned int i = 0; i< pcb->count; ++i) + { + if (pcb->param [i].free) + pcb->param [i].free (pcb->param [i].def); + } + if (pcb->param) + eFree (pcb->param); + eFree (pcb); +} + +extern int defineParam (struct paramControlBlock* pcb, paramDefinition *def, + freeParamDefFunc freeParamDef) +{ + unsigned int id = pcb->count++; + pcb->param = xRealloc (pcb->param, pcb->count, paramObject); + pcb->param [id].def = def; + pcb->param [id].free = freeParamDef; + + verbose ("Add param[%d] \"%s,%s\" to %s\n", id, + def->name, def->desc, + getLanguageName (pcb->owner)); + + return id; +} + +extern bool applyParam (struct paramControlBlock* pcb, const char *name, const char *args) +{ + for (unsigned int i = 0; i < pcb->count; i++) + { + paramDefinition *pdef = pcb->param[i].def; + if (strcmp(pdef->name, name) == 0) + { + if (pdef->handleParam == NULL) + return true; + return pdef->handleParam (pcb->owner, name, args); + } + } + const char *lang = getLanguageName (pcb->owner); + error (FATAL, "no such parameter in %s: %s", lang, name); + return false; +} extern struct colprintTable * paramColprintTableNew (void) { return colprintTableNew ("L:LANGUAGE", "L:NAME","L:DESCRIPTION", NULL); } -extern void paramColprintAddParameter (struct colprintTable *table, - langType language, - const parameterHandlerTable *const paramHandler) +extern void paramColprintAddParams (struct colprintTable *table, + struct paramControlBlock* pcb) { - struct colprintLine *line = colprintTableGetNewLine(table); + const char *lang = getLanguageName (pcb->owner); + for (unsigned int i = 0; i < pcb->count; i++) + { + paramDefinition *pdef = pcb->param [i].def; + struct colprintLine *line = colprintTableGetNewLine(table); - colprintLineAppendColumnCString (line, getLanguageName (language)); - colprintLineAppendColumnCString (line, paramHandler->name); - colprintLineAppendColumnCString (line, paramHandler->desc); + colprintLineAppendColumnCString (line, lang); + colprintLineAppendColumnCString (line, pdef->name); + colprintLineAppendColumnCString (line, pdef->desc); + } } static int paramColprintCompareLines (struct colprintLine *a , struct colprintLine *b) diff --git a/main/param.h b/main/param.h index bbba6be3fe..9b759646c0 100644 --- a/main/param.h +++ b/main/param.h @@ -23,10 +23,10 @@ /* * DATA DECLARATIONS */ -struct sParameterHandlerTable { +struct sParamDefinition { const char *name; const char *desc; - void (* handleParameter) (langType lang, const char *name, const char *arg); + bool (* handleParam) (langType lang, const char *name, const char *arg); }; /* diff --git a/main/param_p.h b/main/param_p.h index 0205a7d165..a322448d37 100644 --- a/main/param_p.h +++ b/main/param_p.h @@ -21,16 +21,29 @@ #include "colprint_p.h" +/* +* DATA DECLARATIONS +*/ +struct paramControlBlock; +typedef void (* freeParamDefFunc) (paramDefinition *); + + /* * FUNCTION PROTOTYPES */ -extern void applyParameter (const langType language, const char *name, const char *args); + +extern bool applyParameter (const langType language, const char *name, const char *args); extern struct colprintTable * paramColprintTableNew (void); -extern void paramColprintAddParameter (struct colprintTable *table, - langType language, - const parameterHandlerTable *const paramHandler); +extern void paramColprintAddParams (struct colprintTable *table, + struct paramControlBlock* pcb); extern void paramColprintTablePrint (struct colprintTable *table, bool noparser, bool withListHeader, bool machinable, FILE *fp); +extern struct paramControlBlock* allocParamControlBlock (parserDefinition *parser); +extern void freeParamControlBlock (struct paramControlBlock* pcb); +extern int defineParam (struct paramControlBlock* pcb, paramDefinition *def, + freeParamDefFunc freeParamDef); +extern bool applyParam (struct paramControlBlock* pcb, const char *name, const char *args); + #endif /* CTAGS_MAIN_PARAM_PRIVATE_H */ diff --git a/main/parse.c b/main/parse.c index ed56df243d..e5f6410134 100644 --- a/main/parse.c +++ b/main/parse.c @@ -95,6 +95,7 @@ typedef struct sParserObject { struct slaveControlBlock *slaveControlBlock; struct kindControlBlock *kindControlBlock; struct lregexControlBlock *lregexControlBlock; + struct paramControlBlock *paramControlBlock; langType pretendingAsLanguage; /* OLDLANG in --_pretend-= is set here if this parser is NEWLANG. @@ -1983,6 +1984,7 @@ static void initializeParsingCommon (parserDefinition *def, bool is_builtin) parser->kindControlBlock = allocKindControlBlock (def); parser->slaveControlBlock = allocSlaveControlBlock (def); parser->lregexControlBlock = allocLregexControlBlock (def); + parser->paramControlBlock = allocParamControlBlock (def); } extern void initializeParsing (void) @@ -2052,6 +2054,8 @@ extern void freeParserResources (void) freeSlaveControlBlock (parser->slaveControlBlock); parser->slaveControlBlock = NULL; + freeParamControlBlock (parser->paramControlBlock); + freeList (&parser->currentPatterns); freeList (&parser->currentExtensions); freeList (&parser->currentAliases); @@ -3355,23 +3359,112 @@ extern void printLanguageKinds (const langType language, bool allKindFields, } } -static void printParameters (struct colprintTable *table, langType language) +extern bool processParamOption ( + const char *const option, const char *const value) { - const parserDefinition* lang; + langType language; + const char* name; + const char* sep; + + language = getLanguageComponentInOption (option, "param-"); + if (language == LANG_IGNORE) + return false; + + sep = option + strlen ("param-") + strlen (getLanguageName (language)); + /* `:' is only for keeping self compatibility */ + if (! (*sep == '.' || *sep == ':' )) + error (FATAL, "no separator(.) is given for %s=%s", option, value); + name = sep + 1; + + if (value == NULL || value [0] == '\0') + error (FATAL, "no value is given for %s", option); + + if (applyLanguageParam (language, name, value)) + propagateParamToOptscript (LanguageTable [language].lregexControlBlock, + name, value); + return true; +} + +static void freePdef (paramDefinition *pdef) +{ + eFree ((void *)pdef->name); + eFree ((void *)pdef->desc); + eFree (pdef); +} + +static bool processLangDefineParam (const langType language, + const char *const option, + const char *const parameter) +{ + parserObject *parser; + + paramDefinition *pdef; + const char * p = parameter; + const char *name_end; + const char *desc; + const char *flags; + Assert (0 <= language && language < (int) LanguageCount); + Assert (p); - initializeParser (language); - lang = LanguageTable [language].def; - if (lang->parameterHandlerTable != NULL) + if (p[0] == '\0') + error (FATAL, "no parameter definition specified in \"--%s\" option", option); + + name_end = strchr (p, ','); + if (!name_end) + error (FATAL, "no parameter description specified in \"--%s\" option", option); + else if (name_end == p) + error (FATAL, "the parameter name in \"--%s\" option is empty", option); + + for (; p < name_end; p++) { - for (unsigned int i = 0; i < lang->parameterHandlerCount; ++i) - paramColprintAddParameter(table, language, lang->parameterHandlerTable + i); + if (!isalnum (*p) && *p != '_') + error (FATAL, "unacceptable char as part of extra name in \"--%s\" option", + option); } + p++; + if (p [0] == '\0' || p [0] == LONG_FLAGS_OPEN) + error (FATAL, "parameter description in \"--%s\" option is empty", option); + + desc = extractDescriptionAndFlags (p, &flags); + + pdef = xCalloc (1, paramDefinition); + pdef->name = eStrndup (parameter, name_end - parameter); + pdef->desc = desc; + +#if 0 + if (flags) + flagsEval (flags, NULL, 0, pdef); +#endif + + parser = LanguageTable + language; + defineParam (parser->paramControlBlock, pdef, freePdef); + return true; } -extern void printLanguageParameters (const langType language, - bool withListHeader, bool machinable, FILE *fp) +extern bool processParamdefOption (const char *const option, const char *const value) +{ + langType language; + + language = getLanguageComponentInOption (option, "_paramdef-"); + if (language == LANG_IGNORE) + return false; + + return processLangDefineParam (language, option, value); +} + +static void printParams (struct colprintTable *table, langType language) +{ + Assert (0 <= language && language < (int) LanguageCount); + + initializeParser (language); + paramColprintAddParams (table, + LanguageTable [language].paramControlBlock); +} + +extern void printLanguageParams (const langType language, + bool withListHeader, bool machinable, FILE *fp) { struct colprintTable *table = paramColprintTableNew(); @@ -3384,11 +3477,11 @@ extern void printLanguageParameters (const langType language, if (lang->invisible) continue; - printParameters (table, i); + printParams (table, i); } } else - printParameters (table, language); + printParams (table, language); paramColprintTablePrint (table, (language != LANG_AUTO), withListHeader, machinable, fp); @@ -4987,31 +5080,12 @@ extern vString *anonGenerateNew (const char *prefix, int kind) } -extern void applyParameter (const langType language, const char *name, const char *args) +extern bool applyLanguageParam (const langType language, const char *name, const char *args) { - parserDefinition* parser; - - Assert (0 <= language && language < (int) LanguageCount); initializeParserOne (language); - parser = LanguageTable [language].def; - - if (parser->parameterHandlerTable) - { - unsigned int i; - - for (i = 0; i < parser->parameterHandlerCount; i++) - { - if (strcmp (parser->parameterHandlerTable [i].name, name) == 0) - { - parser->parameterHandlerTable [i].handleParameter (language, name, args); - return; - } - } - } - - error (FATAL, "no such parameter in %s: %s", parser->name, name); + return applyParam (LanguageTable [language].paramControlBlock, name, args); } extern subparser *getNextSubparser(subparser *last, diff --git a/main/parse.h b/main/parse.h index 6871a241bb..ec06cf13f0 100644 --- a/main/parse.h +++ b/main/parse.h @@ -129,8 +129,8 @@ struct sParserDefinition { parserDependency * dependencies; unsigned int dependencyCount; - parameterHandlerTable *parameterHandlerTable; - unsigned int parameterHandlerCount; + paramDefinition *paramTable; + unsigned int paramCount; xpathFileSpec *xpathFileSpecs; unsigned int xpathFileSpecCount; diff --git a/main/parse_p.h b/main/parse_p.h index 9bd2ea69a2..9fb9c10cb8 100644 --- a/main/parse_p.h +++ b/main/parse_p.h @@ -118,8 +118,8 @@ extern void printLanguageRoles (const langType language, const char* letters, extern void printLanguageAliases (const langType language, bool withListHeader, bool machinable, FILE *fp); extern void printLanguageList (void); -extern void printLanguageParameters (const langType language, - bool withListHeader, bool machinable, FILE *fp); +extern void printLanguageParams (const langType language, + bool withListHeader, bool machinable, FILE *fp); extern void printLanguageSubparsers (const langType language, bool withListHeader, bool machinable, FILE *fp); extern void printLangdefFlags (bool withListHeader, bool machinable, FILE *fp); @@ -182,4 +182,7 @@ extern bool makeParserVersionPseudoTags (const langType language, extern void printLanguageMultitableStatistics (langType language); extern void printParserStatisticsIfUsed (langType lang); +/* For keeping the API compatibility with Geany, we use a macro here. */ +#define applyLanguageParam applyParameter + #endif /* CTAGS_MAIN_PARSE_PRIVATE_H */ diff --git a/main/types.h b/main/types.h index b36bf7711a..e22138529e 100644 --- a/main/types.h +++ b/main/types.h @@ -45,7 +45,7 @@ typedef struct sFieldDefinition fieldDefinition; struct sXtagDefinition; typedef struct sXtagDefinition xtagDefinition; -struct sParameterHandlerTable; -typedef struct sParameterHandlerTable parameterHandlerTable; +struct sParamDefinition; +typedef struct sParamDefinition paramDefinition; #endif /* CTAGS_MAIN_TYPES_H */ diff --git a/misc/optlib2c b/misc/optlib2c index 8f4bbdf801..4fb5038270 100755 --- a/misc/optlib2c +++ b/misc/optlib2c @@ -298,6 +298,21 @@ my $options = scopesep($_[0], $2, $3, $4); return 1; } ], + [ qr/^--_paramdef-(.*)=([^,]+),([^\{]+)/, sub { + die "Don't use --_paramdef-=+ option before defining the language" + if (! defined $_[0]->{'langdef'}); + die "Adding a parameter is allowed only to the language specified with --langdef: $1" + unless ($_[0]->{'langdef'} eq $1); + + my $name = $2; + my $desc = $3; + + die "unacceptable character is used for parameter name: $name" + unless ($name =~ /^[_a-zA-Z0-9]+$/); + + push @{$_[0]->{'paramdefs'}}, { name => $name, desc => $desc }; + return 1; + } ], [ qr/^-.*/, sub { die "Unhandled option: \"$&\""; } ], @@ -940,6 +955,29 @@ EOF EOF } +sub emit_params { + my $opts = shift; + + return if (! @{$opts->{'paramdefs'}}); + + print <{'Clangdef'}ParamTable [] = { +EOF + for (@{$opts->{'paramdefs'}}) { + my $desc = escape_as_cstr $_->{'desc'}; + print <{'paramdefs'}}) { + print <paramTable = $opts->{'Clangdef'}ParamTable; + def->paramCount = ARRAY_SIZE($opts->{'Clangdef'}ParamTable); +EOF + } + if (@{$opts->{'regexs'}}) { print <tagRegexTable = $opts->{'Clangdef'}TagRegexTable; @@ -1091,6 +1136,7 @@ EOF emit_kinddefs $opts; emit_fields $opts; emit_xtags $opts; + emit_params $opts; emit_regexs $opts; emit_dependencies $opts; emit_selector $opts; @@ -1156,6 +1202,8 @@ sub main { ], fielddefs => [ # { name => "", desc => "", enabled => 1|0 }, ], + paramdefs => [ # { name => "", desc => "" }, + ], base => undef, tableNames => [ # "" ], diff --git a/parsers/asm.c b/parsers/asm.c index 8f7daf1a2a..72146263cd 100644 --- a/parsers/asm.c +++ b/parsers/asm.c @@ -743,7 +743,7 @@ static void initialize (const langType language) } #define defineCommentCharSetter(PREPOS, POS) \ - static void asmSetCommentChars##PREPOS##POS (const langType language CTAGS_ATTR_UNUSED, \ + static bool asmSetCommentChars##PREPOS##POS (const langType language CTAGS_ATTR_UNUSED, \ const char *optname CTAGS_ATTR_UNUSED, const char *arg) \ { \ if (commentChars##PREPOS##POS != defaultCommentChar##PREPOS##POS) \ @@ -753,12 +753,13 @@ static void initialize (const langType language) commentChars##PREPOS##POS = eStrdup (arg); \ else \ commentChars##PREPOS##POS = defaultCommentChar##PREPOS##POS; \ + return true; \ } defineCommentCharSetter(At, BOL); defineCommentCharSetter(In, MOL); -static void asmSetExtraLinesepChars(const langType language CTAGS_ATTR_UNUSED, +static bool asmSetExtraLinesepChars(const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg) { if (extraLinesepChars != defaultExtraLinesepChars) @@ -768,35 +769,38 @@ static void asmSetExtraLinesepChars(const langType language CTAGS_ATTR_UNUSED, extraLinesepChars = eStrdup (arg); else extraLinesepChars = defaultExtraLinesepChars; + + return true; } -static void setUseCPreProcessor(const langType language CTAGS_ATTR_UNUSED, +static bool setUseCPreProcessor(const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg) { useCPreProcessor = paramParserBool (arg, useCPreProcessor, name, "parameter"); + return true; } -static parameterHandlerTable AsmParameterHandlerTable [] = { +static paramDefinition AsmParams [] = { { .name = "commentCharsAtBOL", .desc = "line comment chraracters at the begining of line ([" DEFAULT_COMMENT_CHARS_BOL "])", - .handleParameter = asmSetCommentCharsAtBOL, + .handleParam = asmSetCommentCharsAtBOL, }, { .name = "commentCharsInMOL", .desc = "line comment chraracters in the begining of line ([" DEFAULT_COMMENT_CHARS_MOL "])", - .handleParameter = asmSetCommentCharsInMOL, + .handleParam = asmSetCommentCharsInMOL, }, { .name = "extraLinesepChars", .desc = "extra characters used as a line separator ([])", - .handleParameter = asmSetExtraLinesepChars, + .handleParam = asmSetExtraLinesepChars, }, { .name = "useCPreProcessor", .desc = "run CPreProcessor parser for extracting macro definitions ([true] or false)", - .handleParameter = setUseCPreProcessor, + .handleParam = setUseCPreProcessor, }, }; @@ -828,8 +832,8 @@ extern parserDefinition* AsmParser (void) def->fieldTable = AsmFields; def->fieldCount = ARRAY_SIZE (AsmFields); - def->parameterHandlerTable = AsmParameterHandlerTable; - def->parameterHandlerCount = ARRAY_SIZE(AsmParameterHandlerTable); + def->paramTable = AsmParams; + def->paramCount = ARRAY_SIZE(AsmParams); return def; } diff --git a/parsers/cpreprocessor.c b/parsers/cpreprocessor.c index 9cd32dc944..a06144a7fd 100644 --- a/parsers/cpreprocessor.c +++ b/parsers/cpreprocessor.c @@ -2486,13 +2486,14 @@ static void finalizeCpp (const langType language, bool initialized) } } -static void CpreProExpandMacrosInInput (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg) +static bool CpreProExpandMacrosInInput (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg) { doesExpandMacros = paramParserBool (arg, doesExpandMacros, name, "parameter"); + return true; } -static void CpreProInstallIgnoreToken (const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg) +static bool CpreProInstallIgnoreToken (const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg) { if (arg == NULL || arg[0] == '\0') { @@ -2507,9 +2508,10 @@ static void CpreProInstallIgnoreToken (const langType language CTAGS_ATTR_UNUSED cmdlineMacroTable = makeMacroTable (); saveIgnoreToken(arg); } + return true; } -static void CpreProInstallMacroToken (const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg) +static bool CpreProInstallMacroToken (const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg) { if (arg == NULL || arg[0] == '\0') { @@ -2524,30 +2526,32 @@ static void CpreProInstallMacroToken (const langType language CTAGS_ATTR_UNUSED, cmdlineMacroTable = makeMacroTable (); saveMacro(cmdlineMacroTable, arg); } + return true; } -static void CpreProSetIf0 (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg) +static bool CpreProSetIf0 (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg) { doesExaminCodeWithInIf0Branch = paramParserBool (arg, doesExaminCodeWithInIf0Branch, name, "parameter"); + return true; } -static parameterHandlerTable CpreProParameterHandlerTable [] = { +static paramDefinition CpreProParams [] = { { .name = "if0", .desc = "examine code within \"#if 0\" branch (true or [false])", - .handleParameter = CpreProSetIf0, + .handleParam = CpreProSetIf0, }, { .name = "ignore", .desc = "a token to be specially handled", - .handleParameter = CpreProInstallIgnoreToken, + .handleParam = CpreProInstallIgnoreToken, }, { .name = "define", .desc = "define replacement for an identifier (name(params,...)=definition)", - .handleParameter = CpreProInstallMacroToken, + .handleParam = CpreProInstallMacroToken, }, { .name = "_expand", .desc = "expand macros if their definitions are in the current C/C++/CUDA input file (true or [false])", - .handleParameter = CpreProExpandMacrosInInput, + .handleParam = CpreProExpandMacrosInInput, } }; @@ -2563,8 +2567,8 @@ extern parserDefinition* CPreProParser (void) def->fieldTable = CPreProFields; def->fieldCount = ARRAY_SIZE (CPreProFields); - def->parameterHandlerTable = CpreProParameterHandlerTable; - def->parameterHandlerCount = ARRAY_SIZE(CpreProParameterHandlerTable); + def->paramTable = CpreProParams; + def->paramCount = ARRAY_SIZE(CpreProParams); def->useCork = CORK_QUEUE | CORK_SYMTAB; return def; diff --git a/parsers/fypp.c b/parsers/fypp.c index 4890ee01d9..cc706a4247 100644 --- a/parsers/fypp.c +++ b/parsers/fypp.c @@ -425,7 +425,7 @@ static void finalizeFyppParser (langType language, bool initialized) } } -static void fyppSetGuestParser (const langType language CTAGS_ATTR_UNUSED, +static bool fyppSetGuestParser (const langType language CTAGS_ATTR_UNUSED, const char *optname CTAGS_ATTR_UNUSED, const char *arg) { if (!strcmp (arg, RSV_NONE)) @@ -435,7 +435,7 @@ static void fyppSetGuestParser (const langType language CTAGS_ATTR_UNUSED, vStringDelete (fyppGuestParser); fyppGuestParser = NULL; } - return; + return true; } langType lang = getNamedLanguage (arg, strlen(arg)); @@ -447,13 +447,15 @@ static void fyppSetGuestParser (const langType language CTAGS_ATTR_UNUSED, else fyppGuestParser = vStringNew(); vStringCatS (fyppGuestParser, arg); + + return true; } -static parameterHandlerTable FyppParameterHandlerTable [] = { +static paramDefinition FyppParams [] = { { .name = "guest", .desc = "parser run after Fypp parser parses the original input (\"NONE\" or a parser name [Fortran])" , - .handleParameter = fyppSetGuestParser, + .handleParam = fyppSetGuestParser, }, }; @@ -469,8 +471,8 @@ extern parserDefinition* FyppParser (void) def->finalize = finalizeFyppParser; def->method = METHOD_REGEX; - def->parameterHandlerTable = FyppParameterHandlerTable; - def->parameterHandlerCount = ARRAY_SIZE(FyppParameterHandlerTable); + def->paramTable = FyppParams; + def->paramCount = ARRAY_SIZE(FyppParams); def->useCork = CORK_QUEUE; diff --git a/parsers/itcl.c b/parsers/itcl.c index 2d08810b6f..ac88fe4116 100644 --- a/parsers/itcl.c +++ b/parsers/itcl.c @@ -299,16 +299,17 @@ static void findITclTags(void) scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS); } -static void itclForceUseParamHandler (const langType language CTAGS_ATTR_UNUSED, +static bool itclForceUseParamHandler (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg) { itclForceUse = paramParserBool (arg, itclForceUse, name, "parameter"); + return true; } -static parameterHandlerTable ItclParameterHandlerTable [] = { +static paramDefinition ItclParams [] = { { .name = "forceUse", .desc = "enable the parser even when `itcl' namespace is not specified in the input (true or [false])" , - .handleParameter = itclForceUseParamHandler, + .handleParam = itclForceUseParamHandler, }, }; @@ -335,8 +336,8 @@ extern parserDefinition* ITclParser (void) def->keywordTable = ITclKeywordTable; def->keywordCount = ARRAY_SIZE (ITclKeywordTable); - def->parameterHandlerTable = ItclParameterHandlerTable; - def->parameterHandlerCount = ARRAY_SIZE(ItclParameterHandlerTable); + def->paramTable = ItclParams; + def->paramCount = ARRAY_SIZE(ItclParams); return def; } diff --git a/parsers/tcloo.c b/parsers/tcloo.c index f0dd7e09ae..ae3338b837 100644 --- a/parsers/tcloo.c +++ b/parsers/tcloo.c @@ -163,16 +163,17 @@ static void findTclOOTags(void) scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS); } -static void tclooForceUseParamHandler (const langType language CTAGS_ATTR_UNUSED, +static bool tclooForceUseParamHandler (const langType language CTAGS_ATTR_UNUSED, const char *name, const char *arg) { tclooForceUse = paramParserBool (arg, tclooForceUse, name, "parameter"); + return true; } -static parameterHandlerTable TclOOParameterHandlerTable [] = { +static paramDefinition TclOOParams [] = { { .name = "forceUse", .desc = "enable the parser even when `oo' namespace is not specified in the input (true or [false])" , - .handleParameter = tclooForceUseParamHandler, + .handleParam = tclooForceUseParamHandler, }, }; @@ -194,8 +195,8 @@ extern parserDefinition* TclOOParser (void) def->useCork = CORK_QUEUE; def->requestAutomaticFQTag = true; - def->parameterHandlerTable = TclOOParameterHandlerTable; - def->parameterHandlerCount = ARRAY_SIZE(TclOOParameterHandlerTable); + def->paramTable = TclOOParams; + def->paramCount = ARRAY_SIZE(TclOOParams); return def; }