FileTokens.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "tokenizer/FileTokens.h"
  6. #include "utils/SnuviUtils.h"
  7. static Error* error;
  8. typedef char String[64];
  9. #define STRING_LENGTH ((int)sizeof(String))
  10. typedef struct {
  11. String name;
  12. } Define;
  13. #define DEFINES 256
  14. static Define defines[DEFINES];
  15. static int defineIndex = 0;
  16. static int ftGetLine(const FileTokens* ft, int index) {
  17. int fileLayer = 0;
  18. int lines = 1;
  19. for(int i = index; i >= 0; i--) {
  20. FileToken* t = ft->tokens + i;
  21. if(t->type == FT_PATH) {
  22. if(fileLayer == 0) {
  23. return lines;
  24. }
  25. fileLayer--;
  26. } else if(t->type == FT_END_PATH) {
  27. fileLayer++;
  28. } else if(t->type == FT_NEWLINE) {
  29. lines += fileLayer == 0;
  30. }
  31. }
  32. return 0;
  33. }
  34. static const char* ftGetPath(const FileTokens* ft, int index) {
  35. int fileLayer = 0;
  36. for(int i = index; i >= 0; i--) {
  37. FileToken* t = ft->tokens + i;
  38. if(t->type == FT_PATH) {
  39. if(fileLayer == 0) {
  40. return t->literal;
  41. }
  42. fileLayer--;
  43. } else if(t->type == FT_END_PATH) {
  44. fileLayer++;
  45. }
  46. }
  47. return "unknown path";
  48. }
  49. static void ftError(const FileTokens* ft, int index, const char* format, ...) {
  50. va_list args;
  51. va_start(args, format);
  52. eInitErrorV(error, "", ftGetLine(ft, index), format, args);
  53. int fileLayer = 0;
  54. for(int i = index; i >= 0; i--) {
  55. FileToken* t = ft->tokens + i;
  56. if(t->type == FT_PATH) {
  57. if(fileLayer == 0) {
  58. eAddPath(error, t->literal);
  59. } else {
  60. fileLayer--;
  61. }
  62. } else if(t->type == FT_END_PATH) {
  63. fileLayer++;
  64. }
  65. }
  66. va_end(args);
  67. }
  68. static void ftSystemError(const char* msg, const FileTokens* parent,
  69. const FileTokens* ft, int index) {
  70. ftError(parent, index, "%s '%s': %s", msg, ftGetPath(ft, 0),
  71. strerror(errno));
  72. }
  73. static void ftToSpace(FileToken* t) {
  74. free(t->literal);
  75. if(t->type != FT_NEWLINE) {
  76. t->type = FT_SPACE;
  77. }
  78. t->literal = NULL;
  79. t->single = 0;
  80. }
  81. static FileToken* ftAddToken(FileTokens* ft, FileTokenType type) {
  82. if(ft->length >= ft->capacity) {
  83. ft->capacity = (ft->capacity * 5) / 4 + 8;
  84. ft->tokens = realloc(ft->tokens, ft->capacity * sizeof(FileToken));
  85. }
  86. FileToken* t = ft->tokens + ft->length++;
  87. t->type = type;
  88. t->literal = NULL;
  89. t->single = 0;
  90. return t;
  91. }
  92. static void ftAddPath(FileTokens* ft, const char* path) {
  93. ftAddToken(ft, FT_PATH)->literal = strdup(path);
  94. }
  95. static void ftAddEndPath(FileTokens* ft) {
  96. ftAddToken(ft, FT_END_PATH);
  97. }
  98. static void ftAddNewline(FileTokens* ft) {
  99. ftAddToken(ft, FT_NEWLINE);
  100. }
  101. static void ftAddLiteral(FileTokens* ft, const char* path, int length) {
  102. ftAddToken(ft, FT_LITERAL)->literal = strndup(path, length);
  103. }
  104. static void ftAddSingle(FileTokens* ft, int single) {
  105. ftAddToken(ft, FT_SINGLE)->single = single;
  106. }
  107. static void ftAddSpace(FileTokens* ft) {
  108. ftAddToken(ft, FT_SPACE);
  109. }
  110. void ftPrint(FileTokens* ft) {
  111. for(int i = 0; i < ft->length; i++) {
  112. switch(ft->tokens[i].type) {
  113. case FT_PATH:
  114. printf("\033[0;34mPath: %s\n", ft->tokens[i].literal);
  115. break;
  116. case FT_END_PATH: puts("\033[0;34mEnd Path"); break;
  117. case FT_NEWLINE: putchar('\n'); break;
  118. case FT_LITERAL:
  119. printf("\033[0;33m%s", ft->tokens[i].literal);
  120. break;
  121. case FT_SINGLE:
  122. printf("\033[0;31m%c", (char)ft->tokens[i].single);
  123. break;
  124. case FT_SPACE: putchar(' '); break;
  125. }
  126. }
  127. printf("\033[0m");
  128. }
  129. static bool ftHasError() {
  130. return eHasError(error);
  131. }
  132. static bool ftStringCompare(const char* a, const char* b) {
  133. return strcmp(a, b) == 0;
  134. }
  135. static void ftInitFileTokens(FileTokens* ft, const char* path) {
  136. ft->tokens = NULL;
  137. ft->capacity = 0;
  138. ft->length = 0;
  139. ftAddPath(ft, path);
  140. }
  141. static void ftTokenize(FileTokens* ft, unsigned char* data) {
  142. int index = 0;
  143. int oldIndex = 0;
  144. bool inString = false;
  145. while(true) {
  146. unsigned char c = data[index];
  147. if(isAllowedInName(c) || (inString && c != '"' && c != '\0')) {
  148. index++;
  149. continue;
  150. }
  151. if(oldIndex < index) {
  152. ftAddLiteral(ft, (const char*)(data + oldIndex), index - oldIndex);
  153. }
  154. if(c == '"') {
  155. inString = !inString;
  156. }
  157. if(c == '\0') {
  158. break;
  159. } else if(c == '\n') {
  160. ftAddNewline(ft);
  161. } else if(c == ' ') {
  162. ftAddSpace(ft);
  163. } else if(c == '/' && data[index + 1] == '/') {
  164. while(data[index] != '\0' && data[index] != '\n') {
  165. index++;
  166. }
  167. ftAddNewline(ft);
  168. } else if(c == '/' && data[index + 1] == '*') {
  169. int startIndex = ft->length - 1;
  170. index += 2;
  171. while(true) {
  172. if(data[index] == '\0') {
  173. ftError(ft, startIndex, "test");
  174. return;
  175. } else if(data[index] == '\n') {
  176. ftAddNewline(ft);
  177. } else if(data[index] == '*' && data[index + 1] == '/') {
  178. index++;
  179. break;
  180. }
  181. index++;
  182. }
  183. } else {
  184. ftAddSingle(ft, c);
  185. }
  186. index++;
  187. oldIndex = index;
  188. }
  189. }
  190. static void ftReadFull(FILE* file, FileTokens* parent, FileTokens* ft,
  191. int index) {
  192. if(fseek(file, 0, SEEK_END)) {
  193. ftSystemError("cannot seek end of file", parent, ft, index);
  194. return;
  195. }
  196. long length = ftell(file);
  197. if(length < 0) {
  198. ftSystemError("cannot tell end of file", parent, ft, index);
  199. return;
  200. }
  201. rewind(file);
  202. unsigned char* data = malloc(length + 1);
  203. int readValues = fread(data, 1, length, file);
  204. if(readValues != length) {
  205. ftSystemError("cannot read file", parent, ft, index);
  206. free(data);
  207. return;
  208. }
  209. data[length] = '\0';
  210. ftTokenize(ft, data);
  211. ftAddEndPath(ft);
  212. free(data);
  213. }
  214. static void ftReadFullFile(FileTokens* parent, FileTokens* ft, int index) {
  215. FILE* file = fopen(ftGetPath(ft, 0), "r");
  216. if(file == NULL) {
  217. ftSystemError("cannot open file", parent, ft, index);
  218. return;
  219. }
  220. ftReadFull(file, parent, ft, index);
  221. if(fclose(file) < 0) {
  222. ftSystemError("cannot close file", parent, ft, index);
  223. }
  224. }
  225. static void ftReplace(int from, int to, FileTokens* ft,
  226. FileTokens* replacement) {
  227. int newCapacity = ft->capacity + replacement->capacity;
  228. FileToken* newTokens = malloc(newCapacity * sizeof(FileToken));
  229. // these will be overwritten
  230. for(int i = from; i < to; i++) {
  231. free(ft->tokens[i].literal);
  232. ft->tokens[i].literal = NULL;
  233. }
  234. memcpy(newTokens, ft->tokens, from * sizeof(FileToken));
  235. memcpy(newTokens + from, replacement->tokens,
  236. replacement->length * sizeof(FileToken));
  237. memcpy(newTokens + from + replacement->length, ft->tokens + to,
  238. (ft->length - to) * sizeof(FileToken));
  239. free(ft->tokens);
  240. ft->tokens = newTokens;
  241. ft->capacity = newCapacity;
  242. ft->length = from + replacement->length + ft->length - to;
  243. // ownership moved
  244. for(int i = 0; i < replacement->length; i++) {
  245. replacement->tokens[i].literal = NULL;
  246. }
  247. }
  248. static void ftSkipSpaces(int* index, FileTokens* ft) {
  249. while(*index < ft->length) {
  250. FileToken* t = ft->tokens + *index;
  251. if(t->type != FT_SPACE) {
  252. return;
  253. }
  254. (*index)++;
  255. }
  256. }
  257. const char* INCLUDE_ERROR = "include path must be a string";
  258. static bool ftIncludeDoubleQuote(int* index, FileTokens* ft) {
  259. if(*index >= ft->length || ft->tokens[*index].type != FT_SINGLE ||
  260. ft->tokens[*index].single != '"') {
  261. ftError(ft, *index - 1, INCLUDE_ERROR);
  262. return true;
  263. }
  264. (*index)++;
  265. return false;
  266. }
  267. static void ftHandleInclude(int* index, int start, FileTokens* ft) {
  268. ftSkipSpaces(index, ft);
  269. if(ftIncludeDoubleQuote(index, ft)) {
  270. return;
  271. }
  272. if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
  273. ftError(ft, *index - 1, INCLUDE_ERROR);
  274. return;
  275. }
  276. const char* path = ft->tokens[(*index)++].literal;
  277. if(ftIncludeDoubleQuote(index, ft)) {
  278. return;
  279. }
  280. const char* parentPath = ftGetPath(ft, *index - 1);
  281. int afterLastSlash = 0;
  282. for(int i = 0; parentPath[i] != '\0'; i++) {
  283. afterLastSlash = parentPath[i] == '/' ? i + 1 : afterLastSlash;
  284. }
  285. int pathLength = strlen(path) + 1;
  286. char* fullPath = malloc(afterLastSlash + pathLength);
  287. memcpy(fullPath, parentPath, afterLastSlash);
  288. memcpy(fullPath + afterLastSlash, path, pathLength);
  289. FileTokens include;
  290. ftInitFileTokens(&include, fullPath);
  291. free(fullPath);
  292. ftReadFullFile(ft, &include, *index - 1);
  293. if(!ftHasError()) {
  294. ftReplace(start, *index, ft, &include);
  295. *index = start;
  296. }
  297. ftDelete(&include);
  298. }
  299. static bool ftIsDefined(const char* s) {
  300. for(int i = 0; i < defineIndex; i++) {
  301. if(ftStringCompare(defines[i].name, s)) {
  302. return true;
  303. }
  304. }
  305. return false;
  306. }
  307. static int ftFindEndIf(int from, FileTokens* ft) {
  308. int layer = 0;
  309. for(int i = from; i < ft->length - 1; i++) {
  310. if(ft->tokens[i].type != FT_SINGLE || ft->tokens[i].single != '#') {
  311. continue;
  312. } else if(ft->tokens[i + 1].type != FT_LITERAL) {
  313. continue;
  314. }
  315. if(ftStringCompare(ft->tokens[i + 1].literal, "ifndef")) {
  316. layer++;
  317. } else if(ftStringCompare(ft->tokens[i + 1].literal, "endif")) {
  318. if(layer == 0) {
  319. return i;
  320. }
  321. layer--;
  322. }
  323. }
  324. return -1;
  325. }
  326. static void ftHandleIfNotDefined(int* index, int start, FileTokens* ft) {
  327. ftSkipSpaces(index, ft);
  328. if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
  329. ftError(ft, start, "ifndef expects a literal");
  330. return;
  331. }
  332. const char* check = ft->tokens[(*index)++].literal;
  333. int endIf = ftFindEndIf(*index, ft);
  334. if(endIf == -1) {
  335. ftError(ft, start, "cannot find #endif");
  336. return;
  337. }
  338. if(ftIsDefined(check)) {
  339. for(int i = start; i < endIf + 2; i++) {
  340. ftToSpace(ft->tokens + i);
  341. }
  342. } else {
  343. ftToSpace(ft->tokens + start); // #
  344. ftToSpace(ft->tokens + start + 1); // ifndef
  345. ftToSpace(ft->tokens + (*index - 1)); // DEFINITION
  346. ftToSpace(ft->tokens + endIf); // #
  347. ftToSpace(ft->tokens + endIf + 1); // endif
  348. }
  349. }
  350. static void ftHandleDefine(int* index, int start, FileTokens* ft) {
  351. if(defineIndex >= DEFINES) {
  352. ftError(ft, *index - 1, "too much defines");
  353. return;
  354. }
  355. ftSkipSpaces(index, ft);
  356. if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
  357. ftError(ft, *index - 1, "define expects a literal");
  358. return;
  359. }
  360. const char* define = ft->tokens[(*index)++].literal;
  361. if(ftIsDefined(define)) {
  362. return;
  363. }
  364. strncpy(defines[defineIndex].name, define, STRING_LENGTH);
  365. defineIndex++;
  366. ftToSpace(ft->tokens + start); // #
  367. ftToSpace(ft->tokens + start + 1); // define
  368. ftToSpace(ft->tokens + (*index - 1)); // DEFINITION
  369. }
  370. static void ftParseInstruction(int* index, FileTokens* ft) {
  371. int start = *index;
  372. (*index)++;
  373. if(*index >= ft->length || ft->tokens[*index].type != FT_LITERAL) {
  374. ftError(ft, *index - 1, "expected literal after #");
  375. return;
  376. }
  377. const char* name = ft->tokens[(*index)++].literal;
  378. if(ftStringCompare(name, "include")) {
  379. ftHandleInclude(index, start, ft);
  380. } else if(ftStringCompare(name, "ifndef")) {
  381. ftHandleIfNotDefined(index, start, ft);
  382. } else if(ftStringCompare(name, "define")) {
  383. ftHandleDefine(index, start, ft);
  384. } else if(ftStringCompare(name, "endif")) {
  385. ftError(ft, *index - 1, "endif without if");
  386. } else {
  387. ftError(ft, *index - 1, "unknown preprocessor literal '%s'", name);
  388. }
  389. }
  390. static void ftSearchInstruction(FileTokens* ft) {
  391. for(int i = 0; i < ft->length && !ftHasError(); i++) {
  392. if(ft->tokens[i].type == FT_SINGLE && ft->tokens[i].single == '#') {
  393. ftParseInstruction(&i, ft);
  394. }
  395. }
  396. }
  397. void ftInit(const char* path, FileTokens* ft, Error* e) {
  398. defineIndex = 0;
  399. error = e;
  400. eInitSuccess(error);
  401. ftInitFileTokens(ft, path);
  402. ftReadFullFile(ft, ft, 0);
  403. if(!ftHasError()) {
  404. ftSearchInstruction(ft);
  405. }
  406. }
  407. void ftDelete(FileTokens* ft) {
  408. for(int i = 0; i < ft->length; i++) {
  409. free(ft->tokens[i].literal);
  410. }
  411. free(ft->tokens);
  412. ft->tokens = NULL;
  413. ft->capacity = 0;
  414. ft->length = 0;
  415. }