/ctags/parsers/r.c

https://github.com/b4n/geany · C · 205 lines · 137 code · 23 blank · 45 comment · 35 complexity · e76f51539f486fb93e6caf1c65533802 MD5 · raw file

  1. /*
  2. * Copyright (c) 2003-2004, Ascher Stefan <stievie@utanet.at>
  3. *
  4. * This source code is released for free distribution under the terms of the
  5. * GNU General Public License.
  6. *
  7. * This module contains functions for generating tags for R language files.
  8. * R is a programming language for statistical computing.
  9. * R is GPL Software, get it from http://www.r-project.org/
  10. */
  11. /*
  12. * INCLUDE FILES
  13. */
  14. #include "general.h" /* must always come first */
  15. #include <string.h>
  16. #include <ctype.h> /* to define isalpha(), isalnum(), isspace() */
  17. #include "entry.h"
  18. #include "read.h"
  19. #include "vstring.h"
  20. /*#define R_REGEX*/
  21. #define SKIPSPACE(ch) while (isspace((int)*ch)) \
  22. ch++
  23. #ifndef R_REGEX
  24. typedef enum {
  25. K_FUNCTION,
  26. K_LIBRARY,
  27. K_SOURCE,
  28. KIND_COUNT
  29. } rKind;
  30. static kindOption RKinds [KIND_COUNT] = {
  31. { TRUE, 'f', "function", "functions" },
  32. { TRUE, 'l', "library", "libraries" },
  33. { TRUE, 's', "source", "sources" },
  34. };
  35. #endif
  36. #ifdef R_REGEX
  37. static void installRRegex (const langType language)
  38. {
  39. /* This is a function, looks as follows:
  40. * itent <- function(arg1, arg2) {
  41. * do_something;
  42. * }
  43. */
  44. addTagRegex (language,
  45. "^[ \t]*([.a-zA-Z0-9_]+)([ \t]*)<-([ \t]*)function", "\\1", "f,function", NULL);
  46. /* This loads someting, e.g. a library, simply: library(libname) */
  47. addTagRegex (language,
  48. "^[ \t]*(library|source|load|data)[\\(]([a-zA-Z0-9_]+)[\\)]", "\\2", "s,other", NULL);
  49. }
  50. #else
  51. static void makeRTag(const vString* const name, rKind kind)
  52. {
  53. tagEntryInfo e;
  54. initTagEntry(&e, vStringValue(name));
  55. Assert(kind < KIND_COUNT);
  56. e.kindName = RKinds[kind].name;
  57. e.kind = RKinds[kind].letter;
  58. makeTagEntry(&e);
  59. }
  60. static void createRTags(void)
  61. {
  62. vString *vLine = vStringNew();
  63. vString *name = vStringNew();
  64. int ikind;
  65. const unsigned char *line;
  66. while ((line = fileReadLine()) != NULL)
  67. {
  68. const unsigned char *cp = (const unsigned char*)line;
  69. vStringClear(name);
  70. while ((*cp != '\0') && (*cp != '#')) {
  71. /* iterate to the end of line or to a comment */
  72. ikind = -1;
  73. switch (*cp) {
  74. case 'l':
  75. case 's':
  76. if (strncasecmp((const char*)cp, "library", (size_t)7) == 0) {
  77. /* load a library: library(tools) */
  78. cp += 7;
  79. SKIPSPACE(cp);
  80. if (*cp == '(')
  81. ikind = K_LIBRARY;
  82. else
  83. cp -= 7;
  84. } else if (strncasecmp((const char*)cp, "source", (size_t)6) == 0) {
  85. /* load a source file: source("myfile.r") */
  86. cp += 6;
  87. SKIPSPACE(cp);
  88. if (*cp == '(')
  89. ikind = K_SOURCE;
  90. else
  91. cp -= 6;
  92. }
  93. if (ikind != -1) {
  94. cp++;
  95. vStringClear(name);
  96. while ((!isspace((int)*cp)) && *cp != '\0' && *cp != ')') {
  97. vStringPut(name, (int)*cp);
  98. cp++;
  99. }
  100. vStringTerminate(name);
  101. /* if the string really exists, make a tag of it */
  102. if (vStringLength(name) > 0)
  103. makeRTag(name, ikind);
  104. /* prepare for the next iteration */
  105. vStringClear(name);
  106. } else {
  107. vStringPut(name, (int)*cp);
  108. cp++;
  109. }
  110. break;
  111. case '<':
  112. cp++;
  113. if (*cp == '-') {
  114. /* assignment: ident <- someval */
  115. cp++;
  116. SKIPSPACE(cp);
  117. if (*cp == '\0') {
  118. /* not in this line, read next */
  119. /* sometimes functions are declared this way:
  120. ident <-
  121. function(...)
  122. {
  123. ...
  124. }
  125. I don't know if there is a reason to write the function keyword
  126. in a new line
  127. */
  128. if ((line = fileReadLine()) != NULL) {
  129. cp = (const unsigned char*)line;
  130. SKIPSPACE(cp);
  131. }
  132. }
  133. if (strncasecmp((const char*)cp, "function", (size_t)8) == 0) {
  134. /* it's a function: ident <- function(args) */
  135. cp += 8;
  136. vStringTerminate(name);
  137. /* if the string really exists, make a tag of it */
  138. if (vStringLength(name) > 0)
  139. makeRTag(name, K_FUNCTION);
  140. /* prepare for the next iteration */
  141. vStringClear(name);
  142. break;
  143. }
  144. }
  145. case ' ':
  146. case '\x009':
  147. /* skip whitespace */
  148. cp++;
  149. break;
  150. default:
  151. /* collect all characters that could be a part of an identifier */
  152. vStringPut(name, (int)*cp);
  153. cp++;
  154. break;
  155. }
  156. }
  157. }
  158. vStringDelete(name);
  159. vStringDelete(vLine);
  160. }
  161. #endif
  162. extern parserDefinition* RParser (void)
  163. {
  164. /* *.r: R files
  165. * *.s;*.q: S files
  166. */
  167. static const char *const extensions [] = { "r", "s", "q", NULL };
  168. parserDefinition* const def = parserNew ("R");
  169. #ifndef R_REGEX
  170. def->kinds = RKinds;
  171. def->kindCount = KIND_COUNT (RKinds);
  172. #endif
  173. def->extensions = extensions;
  174. #ifndef R_REGEX
  175. def->parser = createRTags;
  176. #else
  177. def->initialize = installRRegex;
  178. def->regex = TRUE;
  179. #endif
  180. return def;
  181. }
  182. /* vi:set tabstop=8 shiftwidth=4: */