lexer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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, char type) {
  186. if(type == -1) {
  187. if(lx->was_space) type = LEXER_TOKEN_TYPE_whitespace;
  188. else type = LEXER_TOKEN_TYPE_unknown;
  189. }
  190. lexer_token_t tok = {
  191. .start_line = lx->num_buffer[0].line_num,
  192. .start_col = lx->num_buffer[0].col_num,
  193. .end_line = lx->num_buffer[len-1].line_num,
  194. .end_col = lx->num_buffer[len-1].col_num,
  195. .text = lx->cached_buffer,
  196. .text_len = len,
  197. .type = type,
  198. .is_generic = lx->in_generic_token,
  199. .id = lx->cur_node->id,
  200. .sol = lx->t_sol,
  201. .eol = lx->t_eol,
  202. };
  203. if(lx->have_cached_token) {
  204. if((lx->was_space && lx->t_eol) || lx->t_sol) {
  205. lx->cached_token.eol = 1;
  206. }
  207. lx->got_token(&lx->cached_token);
  208. }
  209. lx->have_cached_token = 1;
  210. lx->cached_token = tok;
  211. memcpy(lx->cached_buffer, lx->buffer, lx->buf_len);
  212. // translate digraphs at the token level
  213. if(len == 2) {
  214. 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. else if(lx->buffer[1] == ':') { lx->cached_buffer[0] = '#'; lx->cached_token.text_len = 1; }
  221. }
  222. else if(lx->buffer[0] == ':') {
  223. if(lx->buffer[1] == '>') { lx->cached_buffer[0] = ']'; lx->cached_token.text_len = 1; }
  224. }
  225. }
  226. else if(len == 4) {
  227. if(lx->buffer[0] == '%' && lx->buffer[1] == ':' && lx->buffer[2] == '%' && lx->buffer[3] == ':') {
  228. lx->cached_buffer[0] = '#'; lx->cached_buffer[1] = '#'; lx->cached_token.text_len = 2;
  229. }
  230. }
  231. if(!lx->was_space) lx->t_sol = 0;
  232. lx->t_eol = 0;
  233. }
  234. int lex_pp(lexer_info_t* lx) {
  235. while(1) {
  236. read_char(lx);
  237. if(lx->eof) break;
  238. if(lx->c == '\n') {
  239. send_token(lx, lx->buf_len - 1, LEXER_TOKEN_TYPE_generic);
  240. shift_buffer(lx, 1);
  241. lx->was_space = 1;
  242. break;
  243. }
  244. }
  245. return 0;
  246. }
  247. int lex_num(lexer_info_t* lx) {
  248. // the C preprocessor has a strange definition of numbers:
  249. // An optional . followed by a decimal number, followed by amy sequence of letters, numbers, +, - or .
  250. while(1) {
  251. read_char(lx);
  252. if(lx->eof) break;
  253. int c = lx->c;
  254. if(!(isalnum(c) || c == '.' || c == '-' || c == '+')) {
  255. // done
  256. send_token(lx, lx->buf_len - 1, LEXER_TOKEN_TYPE_number);
  257. shift_buffer(lx, 1);
  258. return 1;
  259. }
  260. }
  261. return 0;
  262. }
  263. int lex_dot(lexer_info_t* lx) {
  264. // dots need a degree of smart lookahead.
  265. // . = .
  266. // .. = ., .
  267. // ... = ...
  268. // .\d = number
  269. // just a . so far
  270. read_char(lx);
  271. if(lx->eof) return 0;
  272. if(lx->c != '.') {
  273. if(isdigit(lx->c)) {
  274. return lex_num(lx);
  275. }
  276. send_token(lx, lx->buf_len - 1, LEXER_TOKEN_TYPE_punct);
  277. shift_buffer(lx, 1);
  278. return 1;
  279. }
  280. // .. now
  281. read_char(lx);
  282. if(lx->eof) return 0;
  283. if(lx->c != '.') {
  284. // send two separate dots
  285. send_token(lx, 1, LEXER_TOKEN_TYPE_punct);
  286. shift_buffer(lx, lx->buf_len - 1);
  287. send_token(lx, 1, LEXER_TOKEN_TYPE_punct);
  288. shift_buffer(lx, lx->buf_len - 1);
  289. return 1;
  290. }
  291. else {
  292. // send ...
  293. send_token(lx, lx->buf_len, LEXER_TOKEN_TYPE_punct);
  294. shift_buffer(lx, 0);
  295. return 0;
  296. }
  297. }
  298. int lex_slc(lexer_info_t* lx) {
  299. while(1) {
  300. read_char(lx);
  301. if(lx->eof) break;
  302. if(lx->c == '\n') {
  303. send_token(lx, lx->buf_len - 1, LEXER_TOKEN_TYPE_comment);
  304. shift_buffer(lx, 1);
  305. lx->was_space = 1;
  306. return 1;
  307. }
  308. }
  309. return 0;
  310. }
  311. int lex_mlc(lexer_info_t* lx) {
  312. while(1) {
  313. read_char(lx);
  314. if(lx->eof) break;
  315. if(lx->c == '/' && lx->buffer[lx->buf_len - 2] == '*') {
  316. send_token(lx, lx->buf_len, LEXER_TOKEN_TYPE_comment);
  317. shift_buffer(lx, 0);
  318. break;
  319. }
  320. }
  321. return 0;
  322. }
  323. int lex_string(lexer_info_t* lx) {
  324. int escaped = 0;
  325. while(1) {
  326. read_char(lx);
  327. if(lx->eof) break;
  328. if(escaped) escaped = 0;
  329. else if(lx->c == '\\') escaped = 1;
  330. else if(lx->c == '"') {
  331. send_token(lx, lx->buf_len, LEXER_TOKEN_TYPE_stringlit);
  332. shift_buffer(lx, 0);
  333. break;
  334. }
  335. }
  336. return 0;
  337. }
  338. int lex_charlit(lexer_info_t* lx) {
  339. int escaped = 0;
  340. while(1) {
  341. read_char(lx);
  342. if(lx->eof) break;
  343. if(escaped) escaped = 0;
  344. else if(lx->c == '\\') escaped = 1;
  345. else if(lx->c == '\'') {
  346. send_token(lx, lx->buf_len, LEXER_TOKEN_TYPE_charlit);
  347. shift_buffer(lx, 0);
  348. break;
  349. }
  350. }
  351. return 0;
  352. }
  353. int lex_file(char* path, lexer_opts_t* opts) {
  354. size_t fsz;
  355. char* contents = readWholeFile(path, &fsz);
  356. if(!contents) return -1;
  357. lexer_token_t tok;
  358. lexer_info_t* lx = calloc(1, sizeof(*lx));
  359. lx->got_token = opts->got_token;
  360. lx->src = contents;
  361. lx->head = lx->src;
  362. lx->src_len = fsz;
  363. lx->src_end = contents + fsz - 1;
  364. lx->buf_alloc = 256;
  365. lx->buffer = calloc(1, lx->buf_alloc * sizeof(*lx->buffer));
  366. lx->cached_buffer = calloc(1, lx->buf_alloc * sizeof(*lx->cached_buffer));
  367. lx->num_buffer = calloc(1, lx->buf_alloc * sizeof(*lx->num_buffer));
  368. // initialize a few things
  369. lx->line_num = 1;
  370. lx->line_start = lx->src;
  371. // create a prefix tree of symbols to walk it easier
  372. prefix_tree_t tree = {0};
  373. char** sp = opts->symbols;
  374. for(; *sp; sp++) {
  375. prefix_tree_add_string(&tree, *sp, 1);
  376. }
  377. //prefix_tree_add_handler(&tree, "#", lex_pp);
  378. prefix_tree_add_handler(&tree, ".", lex_dot);
  379. prefix_tree_add_handler(&tree, "0", lex_num);
  380. prefix_tree_add_handler(&tree, "1", lex_num);
  381. prefix_tree_add_handler(&tree, "2", lex_num);
  382. prefix_tree_add_handler(&tree, "3", lex_num);
  383. prefix_tree_add_handler(&tree, "4", lex_num);
  384. prefix_tree_add_handler(&tree, "5", lex_num);
  385. prefix_tree_add_handler(&tree, "6", lex_num);
  386. prefix_tree_add_handler(&tree, "7", lex_num);
  387. prefix_tree_add_handler(&tree, "8", lex_num);
  388. prefix_tree_add_handler(&tree, "9", lex_num);
  389. prefix_tree_add_handler(&tree, "//", lex_slc);
  390. prefix_tree_add_handler(&tree, "/*", lex_mlc);
  391. prefix_tree_add_handler(&tree, "\"", lex_string);
  392. prefix_tree_add_handler(&tree, "'", lex_charlit);
  393. lx->cur_node = &tree.root;
  394. lx->was_space = 0;
  395. lx->in_generic_token = 0;
  396. // read the file one painfully-slow logical character at a time
  397. while(1) {
  398. read_char(lx);
  399. FULL_RETRY:
  400. if(lx->c_sol) lx->t_sol = 1;
  401. if(lx->c_eol) lx->t_eol = 1;
  402. // end of file handling
  403. if(lx->eof) {
  404. if(lx->buf_len > 0) {
  405. lx->t_eol = 1;
  406. // printf("A");
  407. send_token(lx, lx->buf_len, -1);
  408. }
  409. if(lx->have_cached_token) {
  410. lx->cached_token.eol = 1;
  411. lx->got_token(&lx->cached_token);
  412. }
  413. break;
  414. };
  415. int c = lx->c;
  416. if(isspace(c)) {
  417. // try to end the token
  418. if(!lx->was_space && lx->buf_len > 1) {
  419. // printf("B(%d)", c);
  420. send_token(lx, lx->buf_len - 1, -1);
  421. shift_buffer(lx, 1);
  422. lx->in_generic_token = 0;
  423. }
  424. lx->was_space = 1;
  425. }
  426. else {
  427. if(lx->was_space && lx->buf_len > 1) {
  428. // printf("C");
  429. send_token(lx, lx->buf_len - 1, -1);
  430. shift_buffer(lx, 1);
  431. lx->was_space = 0;
  432. lx->cur_node = &tree.root;
  433. }
  434. REDO:
  435. prefix_node_t* n = lx->cur_node->kids;
  436. while(n) {
  437. if(n->c == c) {
  438. lx->cur_node = n;
  439. goto FOUND;
  440. }
  441. n = n->sibling;
  442. }
  443. // NOT FOUND
  444. // see if the current node was terminal and shift
  445. if(lx->cur_node->id) {
  446. // printf("D");
  447. send_token(lx, lx->buf_len - 1, -1);
  448. shift_buffer(lx, 1);
  449. lx->in_generic_token = 0;
  450. lx->cur_node = &tree.root;
  451. goto REDO;
  452. }
  453. else {
  454. lx->in_generic_token = 1;
  455. }
  456. lx->cur_node = &tree.root;
  457. }
  458. continue;
  459. FOUND:
  460. if(lx->in_generic_token && lx->buf_len > 0) {
  461. // printf("E(%c)", c);
  462. send_token(lx, lx->buf_len - 1, -1);
  463. shift_buffer(lx, 1);
  464. }
  465. lx->in_generic_token = 0;
  466. // check for special handlers
  467. if(VEC_LEN(&lx->cur_node->handlers)) {
  468. VEC_EACH(&lx->cur_node->handlers, i, h) {
  469. if(!h(lx)) {
  470. lx->cur_node = &tree.root;
  471. }
  472. else {
  473. lx->cur_node = &tree.root;
  474. goto FULL_RETRY;
  475. }
  476. }
  477. }
  478. }
  479. return 0;
  480. }