lexer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5. #include "../fs.h"
  6. #include "../vec.h"
  7. #include "lexer.h"
  8. enum {
  9. FLAG_NONE = 0,
  10. FLAG_SL_COMMENT,
  11. FLAG_ML_COMMENT_OPEN,
  12. };
  13. struct lexer_info;
  14. typedef struct lexer_info lexer_info_t;
  15. typedef int (*handler_fn)(lexer_info_t*);
  16. typedef struct prefix_node {
  17. int c;
  18. int flags;
  19. void* id;
  20. VEC(handler_fn) handlers;
  21. struct prefix_node* sibling;
  22. struct prefix_node* kids;
  23. } prefix_node_t;
  24. typedef struct prefix_tree {
  25. prefix_node_t root;
  26. } prefix_tree_t;
  27. typedef struct lexer_info {
  28. void (*got_token)(lexer_token_t*);
  29. lexer_token_t cached_token;
  30. char have_cached_token;
  31. char* src, *src_end;
  32. size_t src_len;
  33. char* head;
  34. char* line_start;
  35. long line_num;
  36. long col_num;
  37. int c;
  38. struct {
  39. long line_num, col_num;
  40. }* num_buffer;
  41. char* cached_buffer;
  42. char* buffer;
  43. size_t buf_alloc;
  44. size_t buf_len;
  45. char eof;
  46. char c_sol, c_eol;
  47. char t_sol, t_eol;
  48. char was_space;
  49. char in_generic_token;
  50. prefix_node_t* cur_node;
  51. } lexer_info_t;
  52. void read_char(lexer_info_t* lx) {
  53. RESTART:
  54. // check if there's anything left to read
  55. if(lx->head >= lx->src_end) {
  56. lx->c = 0;
  57. lx->eof = 1;
  58. return;
  59. }
  60. // count lines
  61. if(lx->c_sol) lx->c_sol = 0;
  62. if(lx->c_eol) {
  63. lx->line_start = lx->head;
  64. lx->line_num++;
  65. lx->c_eol = 0;
  66. lx->c_sol = 1;
  67. }
  68. int c = lx->head[0];
  69. lx->col_num = lx->head - lx->line_start;
  70. if(c == '?' &&
  71. // check for fucking trigraphs.
  72. lx->src_end >= lx->head + 2 &&
  73. lx->head[1] == '?') {
  74. #define FUCK_TRIGRAPHS(a,b) if(lx->head[2] == a) { c = b; goto FUCKING_FINALLY; }
  75. FUCK_TRIGRAPHS('/', '\\')
  76. FUCK_TRIGRAPHS('=', '#')
  77. FUCK_TRIGRAPHS('\'', '^')
  78. FUCK_TRIGRAPHS('(', '[')
  79. FUCK_TRIGRAPHS(')', ']')
  80. FUCK_TRIGRAPHS('!', '|')
  81. FUCK_TRIGRAPHS('<', '{')
  82. FUCK_TRIGRAPHS('>', '}')
  83. FUCK_TRIGRAPHS('-', '~')
  84. lx->head++;
  85. if(0) {
  86. FUCKING_FINALLY:
  87. lx->head += 3;
  88. }
  89. }
  90. else lx->head++;
  91. // checked for escaped newlines
  92. if(c == '\\') {
  93. if(lx->src_end > lx->head) {
  94. if(lx->head[0] == '\r') {
  95. if(lx->src_end > lx->head + 1 && lx->head[1] == '\n') // because Windows is like a mechanical typewriter but slower
  96. lx->head += 2;
  97. else
  98. lx->head += 1;
  99. lx->line_num++;
  100. goto RESTART;
  101. }
  102. else if(lx->head[0] == '\n') {
  103. if(lx->src_end > lx->head + 1 && lx->head[1] == '\r')
  104. lx->head += 2;
  105. else
  106. lx->head += 1;
  107. lx->line_num++;
  108. goto RESTART;
  109. }
  110. }
  111. }
  112. // check for regular newlines
  113. else if(c == '\r') {
  114. if(lx->src_end > lx->head && lx->head[0] == '\n') {
  115. lx->head++;
  116. }
  117. lx->c_eol = 1;
  118. c = '\n'; // normalize newlines
  119. }
  120. else if(c == '\n') {
  121. if(lx->src_end > lx->head && lx->head[0] == '\r') {
  122. lx->head++;
  123. }
  124. lx->c_eol = 1;
  125. }
  126. lx->c = c;
  127. // push c into the buffer
  128. if(lx->buf_alloc <= lx->buf_len) {
  129. lx->buf_alloc *= 2;
  130. lx->buffer = realloc(lx->buffer, lx->buf_alloc * sizeof(*lx->buffer));
  131. lx->cached_buffer = realloc(lx->cached_buffer, lx->buf_alloc * sizeof(*lx->cached_buffer));
  132. lx->num_buffer = realloc(lx->num_buffer, lx->buf_alloc * sizeof(*lx->num_buffer));
  133. }
  134. lx->buffer[lx->buf_len] = c;
  135. lx->num_buffer[lx->buf_len].line_num = lx->line_num;
  136. lx->num_buffer[lx->buf_len].col_num = lx->col_num;
  137. lx->buf_len++;
  138. }
  139. static void shift_buffer(lexer_info_t* lx, int offset) {
  140. if(offset == 0) {
  141. lx->buf_len = 0;
  142. return;
  143. }
  144. memmove(lx->buffer, lx->buffer + lx->buf_len - offset, offset * sizeof(*lx->buffer));
  145. memmove(lx->num_buffer, lx->num_buffer + lx->buf_len - offset, offset * sizeof(*lx->num_buffer));
  146. lx->buf_len = offset;
  147. }
  148. void prefix_node_add_string(prefix_node_t* n, char* s, void* id) {
  149. if(s[0] == 0) {
  150. n->id = id;
  151. return;
  152. }
  153. prefix_node_t* k = n->kids;
  154. while(k && k->c != s[0]) k = k->sibling;
  155. if(!k) {
  156. k = calloc(1, sizeof(*k));
  157. k->sibling = n->kids;
  158. n->kids = k;
  159. k->id = 0;
  160. k->c = s[0];
  161. }
  162. prefix_node_add_string(k, s + 1, id);
  163. }
  164. void prefix_tree_add_string(prefix_tree_t* tree, char* s, void* id) {
  165. prefix_node_add_string(&tree->root, s, id);
  166. }
  167. void prefix_node_add_handler(prefix_node_t* n, char* preamble, handler_fn handler) {
  168. if(preamble[0] == 0) {
  169. VEC_PUSH(&n->handlers, handler);
  170. return;
  171. }
  172. prefix_node_t* k = n->kids;
  173. while(k && k->c != preamble[0]) k = k->sibling;
  174. if(!k) {
  175. k = calloc(1, sizeof(*k));
  176. k->sibling = n->kids;
  177. n->kids = k;
  178. k->c = preamble[0];
  179. }
  180. prefix_node_add_handler(k, preamble + 1, handler);
  181. }
  182. void prefix_tree_add_handler(prefix_tree_t* tree, char* preamble, handler_fn handler) {
  183. prefix_node_add_handler(&tree->root, preamble, handler);
  184. }
  185. static void send_token(lexer_info_t* lx, size_t len) {
  186. lexer_token_t tok = {
  187. .start_line = lx->num_buffer[0].line_num,
  188. .start_col = lx->num_buffer[0].col_num,
  189. .end_line = lx->num_buffer[len-1].line_num,
  190. .end_col = lx->num_buffer[len-1].col_num,
  191. .text = lx->cached_buffer,
  192. .text_len = len,
  193. .is_generic = lx->in_generic_token,
  194. .is_whitespace = lx->was_space,
  195. .id = lx->cur_node->id,
  196. .sol = lx->t_sol,
  197. .eol = lx->t_eol,
  198. };
  199. if(lx->have_cached_token) {
  200. if((lx->was_space && lx->t_eol) || lx->t_sol) {
  201. lx->cached_token.eol = 1;
  202. }
  203. lx->got_token(&lx->cached_token);
  204. }
  205. lx->have_cached_token = 1;
  206. lx->cached_token = tok;
  207. memcpy(lx->cached_buffer, lx->buffer, lx->buf_len);
  208. // translate digraphs at the token level
  209. if(len == 2) {
  210. if(lx->buffer[0] == '<') {
  211. if(lx->buffer[1] == ':') { lx->cached_buffer[0] = '['; lx->cached_token.text_len = 1; }
  212. else if(lx->buffer[1] == '%') { lx->cached_buffer[0] = '{'; lx->cached_token.text_len = 1; }
  213. }
  214. else if(lx->buffer[0] == '%') {
  215. if(lx->buffer[1] == '>') { lx->cached_buffer[0] = '}'; lx->cached_token.text_len = 1; }
  216. else if(lx->buffer[1] == ':') { lx->cached_buffer[0] = '#'; lx->cached_token.text_len = 1; }
  217. }
  218. else if(lx->buffer[0] == ':') {
  219. if(lx->buffer[1] == '>') { lx->cached_buffer[0] = ']'; lx->cached_token.text_len = 1; }
  220. }
  221. }
  222. else if(len == 4) {
  223. if(lx->buffer[0] == '%' && lx->buffer[1] == ':' && lx->buffer[2] == '%' && lx->buffer[3] == ':') {
  224. lx->cached_buffer[0] = '#'; lx->cached_buffer[1] = '#'; lx->cached_token.text_len = 2;
  225. }
  226. }
  227. if(!lx->was_space) lx->t_sol = 0;
  228. lx->t_eol = 0;
  229. }
  230. int lex_pp(lexer_info_t* lx) {
  231. while(1) {
  232. read_char(lx);
  233. if(lx->eof) break;
  234. if(lx->c == '\n') {
  235. send_token(lx, lx->buf_len - 1);
  236. shift_buffer(lx, 1);
  237. lx->was_space = 1;
  238. break;
  239. }
  240. }
  241. return 0;
  242. }
  243. int lex_num(lexer_info_t* lx) {
  244. // the C preprocessor has a strange definition of numbers:
  245. // An optional . followed by a decimal number, followed by amy sequence of letters, numbers, +, - or .
  246. while(1) {
  247. read_char(lx);
  248. if(lx->eof) break;
  249. int c = lx->c;
  250. if(!(isalnum(c) || c == '.' || c == '-' || c == '+')) {
  251. // done
  252. send_token(lx, lx->buf_len - 1);
  253. shift_buffer(lx, 1);
  254. return 1;
  255. }
  256. }
  257. return 0;
  258. }
  259. int lex_dot(lexer_info_t* lx) {
  260. // dots need a degree of smart lookahead.
  261. // . = .
  262. // .. = ., .
  263. // ... = ...
  264. // .\d = number
  265. // just a . so far
  266. read_char(lx);
  267. if(lx->eof) return 0;
  268. if(lx->c != '.') {
  269. if(isdigit(lx->c)) {
  270. return lex_num(lx);
  271. }
  272. send_token(lx, lx->buf_len - 1);
  273. shift_buffer(lx, 1);
  274. return 1;
  275. }
  276. // .. now
  277. read_char(lx);
  278. if(lx->eof) return 0;
  279. if(lx->c != '.') {
  280. // send two separate dots
  281. send_token(lx, 1);
  282. shift_buffer(lx, lx->buf_len - 1);
  283. send_token(lx, 1);
  284. shift_buffer(lx, lx->buf_len - 1);
  285. return 1;
  286. }
  287. else {
  288. // send ...
  289. send_token(lx, lx->buf_len);
  290. shift_buffer(lx, 0);
  291. return 0;
  292. }
  293. }
  294. int lex_slc(lexer_info_t* lx) {
  295. while(1) {
  296. read_char(lx);
  297. if(lx->eof) break;
  298. if(lx->c == '\n') {
  299. send_token(lx, lx->buf_len - 1);
  300. shift_buffer(lx, 1);
  301. lx->was_space = 1;
  302. return 1;
  303. }
  304. }
  305. return 0;
  306. }
  307. int lex_mlc(lexer_info_t* lx) {
  308. while(1) {
  309. read_char(lx);
  310. if(lx->eof) break;
  311. if(lx->c == '/' && lx->buffer[lx->buf_len - 2] == '*') {
  312. send_token(lx, lx->buf_len);
  313. shift_buffer(lx, 0);
  314. break;
  315. }
  316. }
  317. return 0;
  318. }
  319. int lex_string(lexer_info_t* lx) {
  320. int escaped = 0;
  321. while(1) {
  322. read_char(lx);
  323. if(lx->eof) break;
  324. if(escaped) escaped = 0;
  325. else if(lx->c == '\\') escaped = 1;
  326. else if(lx->c == '"') {
  327. send_token(lx, lx->buf_len);
  328. shift_buffer(lx, 0);
  329. break;
  330. }
  331. }
  332. return 0;
  333. }
  334. int lex_charlit(lexer_info_t* lx) {
  335. int escaped = 0;
  336. while(1) {
  337. read_char(lx);
  338. if(lx->eof) break;
  339. if(escaped) escaped = 0;
  340. else if(lx->c == '\\') escaped = 1;
  341. else if(lx->c == '\'') {
  342. send_token(lx, lx->buf_len);
  343. shift_buffer(lx, 0);
  344. break;
  345. }
  346. }
  347. return 0;
  348. }
  349. int lex_file(char* path, lexer_opts_t* opts) {
  350. size_t fsz;
  351. char* contents = readWholeFile(path, &fsz);
  352. if(!contents) return -1;
  353. lexer_token_t tok;
  354. lexer_info_t* lx = calloc(1, sizeof(*lx));
  355. lx->got_token = opts->got_token;
  356. lx->src = contents;
  357. lx->head = lx->src;
  358. lx->src_len = fsz;
  359. lx->src_end = contents + fsz - 1;
  360. lx->buf_alloc = 256;
  361. lx->buffer = calloc(1, lx->buf_alloc * sizeof(*lx->buffer));
  362. lx->cached_buffer = calloc(1, lx->buf_alloc * sizeof(*lx->cached_buffer));
  363. lx->num_buffer = calloc(1, lx->buf_alloc * sizeof(*lx->num_buffer));
  364. // initialize a few things
  365. lx->line_num = 1;
  366. lx->line_start = lx->src;
  367. // create a prefix tree of symbols to walk it easier
  368. prefix_tree_t tree = {0};
  369. char** sp = opts->symbols;
  370. for(; *sp; sp++) {
  371. prefix_tree_add_string(&tree, *sp, 1);
  372. }
  373. //prefix_tree_add_handler(&tree, "#", lex_pp);
  374. prefix_tree_add_handler(&tree, ".", lex_dot);
  375. prefix_tree_add_handler(&tree, "0", lex_num);
  376. prefix_tree_add_handler(&tree, "1", lex_num);
  377. prefix_tree_add_handler(&tree, "2", lex_num);
  378. prefix_tree_add_handler(&tree, "3", lex_num);
  379. prefix_tree_add_handler(&tree, "4", lex_num);
  380. prefix_tree_add_handler(&tree, "5", lex_num);
  381. prefix_tree_add_handler(&tree, "6", lex_num);
  382. prefix_tree_add_handler(&tree, "7", lex_num);
  383. prefix_tree_add_handler(&tree, "8", lex_num);
  384. prefix_tree_add_handler(&tree, "9", lex_num);
  385. prefix_tree_add_handler(&tree, "//", lex_slc);
  386. prefix_tree_add_handler(&tree, "/*", lex_mlc);
  387. prefix_tree_add_handler(&tree, "\"", lex_string);
  388. prefix_tree_add_handler(&tree, "'", lex_charlit);
  389. lx->cur_node = &tree.root;
  390. lx->was_space = 0;
  391. lx->in_generic_token = 0;
  392. // read the file one painfully-slow logical character at a time
  393. while(1) {
  394. read_char(lx);
  395. FULL_RETRY:
  396. if(lx->c_sol) lx->t_sol = 1;
  397. if(lx->c_eol) lx->t_eol = 1;
  398. // end of file handling
  399. if(lx->eof) {
  400. if(lx->buf_len > 0) {
  401. lx->t_eol = 1;
  402. // printf("A");
  403. send_token(lx, lx->buf_len);
  404. }
  405. if(lx->have_cached_token) {
  406. lx->cached_token.eol = 1;
  407. lx->got_token(&lx->cached_token);
  408. }
  409. break;
  410. };
  411. int c = lx->c;
  412. if(isspace(c)) {
  413. // try to end the token
  414. if(!lx->was_space && lx->buf_len > 1) {
  415. // printf("B(%d)", c);
  416. send_token(lx, lx->buf_len - 1);
  417. shift_buffer(lx, 1);
  418. lx->in_generic_token = 0;
  419. }
  420. lx->was_space = 1;
  421. }
  422. else {
  423. if(lx->was_space && lx->buf_len > 1) {
  424. // printf("C");
  425. send_token(lx, lx->buf_len - 1);
  426. shift_buffer(lx, 1);
  427. lx->was_space = 0;
  428. lx->cur_node = &tree.root;
  429. }
  430. REDO:
  431. prefix_node_t* n = lx->cur_node->kids;
  432. while(n) {
  433. if(n->c == c) {
  434. lx->cur_node = n;
  435. goto FOUND;
  436. }
  437. n = n->sibling;
  438. }
  439. // NOT FOUND
  440. // see if the current node was terminal and shift
  441. if(lx->cur_node->id) {
  442. // printf("D");
  443. send_token(lx, lx->buf_len - 1);
  444. shift_buffer(lx, 1);
  445. lx->in_generic_token = 0;
  446. lx->cur_node = &tree.root;
  447. goto REDO;
  448. }
  449. else {
  450. lx->in_generic_token = 1;
  451. }
  452. lx->cur_node = &tree.root;
  453. }
  454. continue;
  455. FOUND:
  456. if(lx->in_generic_token && lx->buf_len > 0) {
  457. // printf("E(%c)", c);
  458. send_token(lx, lx->buf_len - 1);
  459. shift_buffer(lx, 1);
  460. }
  461. lx->in_generic_token = 0;
  462. // check for special handlers
  463. if(VEC_LEN(&lx->cur_node->handlers)) {
  464. VEC_EACH(&lx->cur_node->handlers, i, h) {
  465. if(!h(lx)) {
  466. lx->cur_node = &tree.root;
  467. }
  468. else {
  469. lx->cur_node = &tree.root;
  470. goto FULL_RETRY;
  471. }
  472. }
  473. }
  474. }
  475. return 0;
  476. }