1
0

c_preproc.g 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605
  1. # This file is part of asmc, a bootstrapping OS with minimal seed
  2. # Copyright (C) 2018-2019 Giovanni Mascellani <gio@debian.org>
  3. # https://gitlab.com/giomasce/asmc
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. # You should have received a copy of the GNU General Public License
  13. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. $fd_in
  15. $read_char
  16. $char_given_back
  17. fun is_valid_identifier 1 {
  18. $ident
  19. @ident 0 param = ;
  20. #"is_valid_identifier for " log ;
  21. #ident log ;
  22. #"\n" log ;
  23. $len
  24. @len ident strlen = ;
  25. if len 0 == { 0 ret ; }
  26. $i
  27. @i 0 = ;
  28. while i len < {
  29. if ident i + **c get_char_type 3 != { 0 ret ; }
  30. @i i 1 + = ;
  31. }
  32. $first
  33. @first ident **c = ;
  34. if first '0' >= first '9' <= && { 0 ret ; }
  35. #"is_valid_identifier: return true\n" log ;
  36. 1 ret ;
  37. }
  38. const PPCTX_ASTINT_GET_TOKEN 0
  39. const PPCTX_ASTINT_GET_TOKEN_OR_FAIL 4
  40. const PPCTX_ASTINT_GIVE_BACK_TOKEN 8
  41. const PPCTX_ASTINT_PARSE_TYPE 12
  42. const PPCTX_ASTINT_INTOKS 16
  43. const PPCTX_ASTINT_IPTR 20
  44. const SIZEOF_PPCTX_ASTINT 24
  45. fun ppctx_astint_get_token 1 {
  46. $int
  47. @int 0 param = ;
  48. $intoks
  49. $iptr
  50. @intoks int PPCTX_ASTINT_INTOKS take = ;
  51. @iptr int PPCTX_ASTINT_IPTR take = ;
  52. if iptr ** intoks vector_size < {
  53. $tok
  54. @tok intoks iptr ** vector_at = ;
  55. iptr iptr ** 1 + = ;
  56. tok ret ;
  57. } else {
  58. 0 ret ;
  59. }
  60. }
  61. fun ppctx_astint_get_token_or_fail 1 {
  62. $int
  63. @int 0 param = ;
  64. $res
  65. @res int ppctx_astint_get_token = ;
  66. res 0 != "ppctx_astint_get_token_or_fail: missing token" assert_msg ;
  67. res ret ;
  68. }
  69. fun ppctx_astint_give_back_token 1 {
  70. $int
  71. @int 0 param = ;
  72. $iptr
  73. @iptr int PPCTX_ASTINT_IPTR take = ;
  74. iptr iptr ** 1 - = ;
  75. }
  76. fun ppctx_astint_parse_type 1 {
  77. $int
  78. @int 0 param = ;
  79. 0xffffffff ret ;
  80. }
  81. fun ppctx_astint_init 2 {
  82. $intoks
  83. $iptr
  84. @intoks 1 param = ;
  85. @iptr 0 param = ;
  86. $int
  87. @int SIZEOF_PPCTX_ASTINT malloc = ;
  88. int PPCTX_ASTINT_GET_TOKEN take_addr @ppctx_astint_get_token = ;
  89. int PPCTX_ASTINT_GET_TOKEN_OR_FAIL take_addr @ppctx_astint_get_token_or_fail = ;
  90. int PPCTX_ASTINT_GIVE_BACK_TOKEN take_addr @ppctx_astint_give_back_token = ;
  91. int PPCTX_ASTINT_PARSE_TYPE take_addr @ppctx_astint_parse_type = ;
  92. int PPCTX_ASTINT_INTOKS take_addr intoks = ;
  93. int PPCTX_ASTINT_IPTR take_addr iptr = ;
  94. # When initialized, the index pointer is one token behind
  95. int PPCTX_ASTINT_IPTR take int PPCTX_ASTINT_IPTR take ** 1 + = ;
  96. int ret ;
  97. }
  98. fun ppctx_astint_destroy 1 {
  99. $int
  100. @int 0 param = ;
  101. int free ;
  102. }
  103. const SUBST_IS_FUNCTION 0 # bool
  104. const SUBST_PARAMETERS 4 # vector of char*
  105. const SUBST_REPLACEMENT 8 # vector of char*
  106. const SIZEOF_SUBST 12
  107. fun subst_init 0 {
  108. $ptr
  109. @ptr SIZEOF_SUBST malloc = ;
  110. ptr SUBST_IS_FUNCTION take_addr 0 = ;
  111. ptr SUBST_PARAMETERS take_addr 4 vector_init = ;
  112. ptr SUBST_REPLACEMENT take_addr 4 vector_init = ;
  113. ptr ret ;
  114. }
  115. fun subst_destroy 1 {
  116. $ptr
  117. @ptr 0 param = ;
  118. ptr SUBST_PARAMETERS take free_vect_of_ptrs ;
  119. ptr SUBST_REPLACEMENT take free_vect_of_ptrs ;
  120. ptr free ;
  121. }
  122. const PPCTX_DEFINES 0
  123. const PPCTX_VERBOSE 4
  124. const PPCTX_INCLUDE_PATH 8
  125. const SIZEOF_PPCTX 12
  126. fun ppctx_init 0 {
  127. $ptr
  128. @ptr SIZEOF_PPCTX malloc = ;
  129. ptr PPCTX_DEFINES take_addr map_init = ;
  130. ptr PPCTX_VERBOSE take_addr 1 = ;
  131. ptr PPCTX_INCLUDE_PATH take_addr 4 vector_init = ;
  132. ptr PPCTX_INCLUDE_PATH take "/disk1/stdlib/" strdup vector_push_back ;
  133. ptr ret ;
  134. }
  135. fun subst_destroy_closure 3 {
  136. $ctx
  137. $key
  138. $value
  139. @ctx 2 param = ;
  140. @key 1 param = ;
  141. @value 0 param = ;
  142. value subst_destroy ;
  143. }
  144. fun ppctx_destroy 1 {
  145. $ptr
  146. @ptr 0 param = ;
  147. $defs
  148. @defs ptr PPCTX_DEFINES take = ;
  149. defs @subst_destroy_closure 0 map_foreach ;
  150. defs map_destroy ;
  151. ptr PPCTX_INCLUDE_PATH take free_vect_of_ptrs ;
  152. ptr free ;
  153. }
  154. fun ppctx_define 3 {
  155. $ctx
  156. $key
  157. $value
  158. @ctx 2 param = ;
  159. @key 1 param = ;
  160. @value 0 param = ;
  161. $subst
  162. @subst subst_init = ;
  163. subst SUBST_REPLACEMENT take value strdup vector_push_back ;
  164. ctx PPCTX_DEFINES take key subst map_set ;
  165. }
  166. fun ppctx_set_base_filename 2 {
  167. $ctx
  168. $filename
  169. @ctx 1 param = ;
  170. @filename 0 param = ;
  171. @filename filename strdup = ;
  172. # Take the dirname
  173. $i
  174. @i filename strlen = ;
  175. filename **c '/' == "ppctx_set_base_filename: missing initial slash" assert_msg ;
  176. while filename i + **c '/' != {
  177. @i i 1 - = ;
  178. }
  179. filename i + 1 + 0 =c ;
  180. ctx PPCTX_INCLUDE_PATH take filename vector_push_back ;
  181. }
  182. fun ppctx_add_include_path 2 {
  183. $ctx
  184. $filename
  185. @ctx 1 param = ;
  186. @filename 0 param = ;
  187. @filename filename strdup = ;
  188. filename **c '/' == "ppctx_add_include_path: missing initial slash" assert_msg ;
  189. ctx PPCTX_INCLUDE_PATH take filename vector_push_back ;
  190. }
  191. fun give_back_char 0 {
  192. @char_given_back 1 = ;
  193. }
  194. fun get_char 0 {
  195. if char_given_back {
  196. @char_given_back 0 = ;
  197. } else {
  198. @read_char fd_in vfs_read = ;
  199. }
  200. read_char ret
  201. }
  202. fun is_c_comment 1 {
  203. $first
  204. $second
  205. @first 0 param **c = ;
  206. @second 0 param 1 + **c = ;
  207. if first '/' == second '*' == && { 1 ret ; }
  208. 0 ret ;
  209. }
  210. fun is_cpp_comment 1 {
  211. $first
  212. $second
  213. @first 0 param **c = ;
  214. @second 0 param 1 + **c = ;
  215. if first '/' == second '/' == && { 1 ret ; }
  216. 0 ret ;
  217. }
  218. fun is_line_escape 1 {
  219. $first
  220. $second
  221. @first 0 param **c = ;
  222. @second 0 param 1 + **c = ;
  223. if first '\\' == second '\n' == && { 1 ret ; }
  224. 0 ret ;
  225. }
  226. fun get_token 0 {
  227. $token_buf
  228. $token_buf_len
  229. @token_buf_len 32 = ;
  230. @token_buf token_buf_len malloc = ;
  231. $state
  232. @state 0 = ;
  233. $token_type
  234. $token_len
  235. @token_len 0 = ;
  236. $cont
  237. @cont 1 = ;
  238. while cont {
  239. $c
  240. @c '\r' = ;
  241. while c '\r' == {
  242. @c get_char = ;
  243. }
  244. @cont c 0xffffffff != = ;
  245. if cont {
  246. $save_char
  247. @save_char 0 = ;
  248. $type
  249. @type c get_char_type = ;
  250. $enter_state
  251. @enter_state state = ;
  252. # Normal code
  253. if enter_state 0 == {
  254. @save_char 1 = ;
  255. }
  256. # C++ style comment
  257. if enter_state 1 == {
  258. if c '\n' == {
  259. token_buf ' ' =c ;
  260. @token_len 1 = ;
  261. @state 0 = ;
  262. @cont 0 = ;
  263. give_back_char ;
  264. }
  265. }
  266. # C style comment
  267. if enter_state 2 == {
  268. if c '*' == {
  269. @state 3 = ;
  270. }
  271. }
  272. # C style comment after star
  273. if enter_state 3 == {
  274. if c '/' == {
  275. token_buf ' ' =c ;
  276. @token_len 1 = ;
  277. @state 0 = ;
  278. @cont 0 = ;
  279. }
  280. if c '*' != {
  281. @state 2 = ;
  282. }
  283. }
  284. # String
  285. if enter_state 4 == {
  286. @save_char 1 = ;
  287. if c '\\' == {
  288. @state 5 = ;
  289. }
  290. if c '\"' == {
  291. @state 0 = ;
  292. @cont 0 = ;
  293. }
  294. }
  295. # String after backslash
  296. if enter_state 5 == {
  297. @save_char 1 = ;
  298. @state 4 = ;
  299. }
  300. # Character
  301. if enter_state 6 == {
  302. @save_char 1 = ;
  303. if c '\\' == {
  304. @state 7 = ;
  305. }
  306. if c '\'' == {
  307. @state 0 = ;
  308. @cont 0 = ;
  309. }
  310. }
  311. # Character after backslash
  312. if enter_state 7 == {
  313. @save_char 1 = ;
  314. @state 6 = ;
  315. }
  316. token_buf token_len + c =c ;
  317. if save_char {
  318. if token_len 0 == {
  319. @token_len 1 = ;
  320. @token_type type = ;
  321. if c '\"' == {
  322. @state 4 = ;
  323. @token_type 0 = ;
  324. }
  325. if c '\'' == {
  326. @state 6 = ;
  327. @token_type 0 = ;
  328. }
  329. if c '\n' == {
  330. @cont 0 = ;
  331. }
  332. } else {
  333. if token_buf is_line_escape {
  334. @token_len 0 = ;
  335. } else {
  336. if token_type type == token_type 0 == || {
  337. @token_len token_len 1 + = ;
  338. if token_type 4 == {
  339. $done
  340. @done 0 = ;
  341. if token_buf is_c_comment {
  342. @state 2 = ;
  343. @done 1 = ;
  344. }
  345. if token_buf is_cpp_comment {
  346. @state 1 = ;
  347. @done 1 = ;
  348. }
  349. if done ! {
  350. token_buf token_len + 0 =c ;
  351. if token_buf ast_is_operator token_buf "##" strcmp 0 == || token_buf ".." strcmp 0 == || token_buf "..." strcmp 0 == || ! {
  352. @cont 0 = ;
  353. @done 1 = ;
  354. @token_len token_len 1 - = ;
  355. give_back_char ;
  356. }
  357. }
  358. }
  359. } else {
  360. give_back_char ;
  361. @cont 0 = ;
  362. }
  363. }
  364. }
  365. }
  366. if token_len 1 + token_buf_len >= {
  367. @token_buf_len token_buf_len 2 * = ;
  368. @token_buf token_buf_len token_buf realloc = ;
  369. }
  370. }
  371. }
  372. if token_type 2 == {
  373. token_buf ' ' =c ;
  374. @token_len 1 = ;
  375. }
  376. token_buf token_len + 0 =c ;
  377. token_buf ret ;
  378. }
  379. fun tokenize_file 1 {
  380. @fd_in 0 param vfs_open = ;
  381. fd_in 0 != "tokenize_file: could not open file" assert_msg ;
  382. $tok
  383. $cont
  384. @cont 1 = ;
  385. $token_vect
  386. @token_vect 4 vector_init = ;
  387. while cont {
  388. @tok get_token = ;
  389. @cont tok "" strcmp 0 != = ;
  390. if cont {
  391. token_vect tok vector_push_back ;
  392. } else {
  393. tok free ;
  394. }
  395. }
  396. fd_in vfs_close ;
  397. token_vect ret ;
  398. }
  399. fun discard_until_newline 2 {
  400. $tokens
  401. $iptr
  402. @iptr 0 param = ;
  403. @tokens 1 param = ;
  404. $cont
  405. @cont 1 = ;
  406. while cont {
  407. @cont tokens iptr ** vector_at "\n" strcmp 0 != = ;
  408. if cont {
  409. iptr iptr ** 1 + = ;
  410. iptr ** tokens vector_size < "discard_until_newline: stream end was found" assert_msg ;
  411. }
  412. }
  413. }
  414. fun discard_white_tokens 2 {
  415. $tokens
  416. $iptr
  417. @iptr 0 param = ;
  418. @tokens 1 param = ;
  419. $cont
  420. @cont 1 = ;
  421. while cont {
  422. iptr iptr ** 1 + = ;
  423. iptr ** tokens vector_size < "discard_white_token: stream end was found" assert_msg ;
  424. @cont tokens iptr ** vector_at " " strcmp 0 == = ;
  425. }
  426. }
  427. fun discard_white_newline_tokens 2 {
  428. $tokens
  429. $iptr
  430. @iptr 0 param = ;
  431. @tokens 1 param = ;
  432. $cont
  433. @cont 1 = ;
  434. while cont {
  435. iptr iptr ** 1 + = ;
  436. iptr ** tokens vector_size < "discard_white_token: stream end was found" assert_msg ;
  437. $tok
  438. @tok tokens iptr ** vector_at = ;
  439. @cont tok " " strcmp 0 == tok "\n" strcmp 0 == || = ;
  440. }
  441. }
  442. # Put a \ before all " and \
  443. fun stringify_patch_string 1 {
  444. $s
  445. @s 0 param = ;
  446. # Do a first string scan to compute the output string length
  447. $len
  448. @len 0 = ;
  449. $i
  450. @i 0 = ;
  451. while s i + **c '\0' != {
  452. $c
  453. @c s i + **c = ;
  454. if c '\"' == c '\\' == || {
  455. @len len 1 + = ;
  456. }
  457. @len len 1 + = ;
  458. @i i 1 + = ;
  459. }
  460. @len len 1 + = ;
  461. # Allocate the new string
  462. $r
  463. @r len malloc = ;
  464. $j
  465. @i 0 = ;
  466. @j 0 = ;
  467. # Do a second scan to fill the output string
  468. while s i + **c '\0' != {
  469. $c
  470. @c s i + **c = ;
  471. if c '\"' == c '\\' == || {
  472. r j + '\\' =c ;
  473. @j j 1 + = ;
  474. }
  475. r j + c =c ;
  476. @i i 1 + = ;
  477. @j j 1 + = ;
  478. }
  479. r j + '\0' =c ;
  480. @j j 1 + = ;
  481. len j == "stringify_path_string: error 1" assert_msg ;
  482. r ret ;
  483. }
  484. fun process_token_stringify 2 {
  485. $ctx
  486. $toks
  487. @ctx 1 param = ;
  488. @toks 0 param = ;
  489. $res
  490. @res "\"" strdup = ;
  491. $i
  492. @i 0 = ;
  493. $begin
  494. @begin 1 = ;
  495. $whites
  496. @whites 0 = ;
  497. while i toks vector_size < {
  498. $tok
  499. @tok toks i vector_at = ;
  500. if tok " " strcmp 0 == tok "\n" strcmp 0 == || {
  501. if begin ! {
  502. @whites 1 = ;
  503. }
  504. } else {
  505. @begin 0 = ;
  506. if whites {
  507. @res res " " append_to_str = ;
  508. }
  509. $patched
  510. @patched tok stringify_patch_string = ;
  511. @res res patched append_to_str = ;
  512. patched free ;
  513. }
  514. @i i 1 + = ;
  515. }
  516. @res res "\"" append_to_str = ;
  517. res ret ;
  518. }
  519. fun push_token 2 {
  520. $tokens
  521. $tok
  522. @tokens 1 param = ;
  523. @tok 0 param = ;
  524. $prev
  525. @prev tokens vector_pop_back = ;
  526. if prev "##" strcmp 0 == {
  527. if tok " " strcmp 0 == tok "\n" strcmp 0 == || ! {
  528. prev free ;
  529. @prev tokens vector_pop_back = ;
  530. @prev prev tok append_to_str = ;
  531. }
  532. tokens prev vector_push_back ;
  533. tok free ;
  534. } else {
  535. if tok "##" strcmp 0 == {
  536. while prev " " strcmp 0 == prev "\n" strcmp 0 == || {
  537. prev free ;
  538. @prev tokens vector_pop_back = ;
  539. }
  540. }
  541. tokens prev vector_push_back ;
  542. if tok "" strcmp 0 == {
  543. tok free ;
  544. } else {
  545. tokens tok vector_push_back ;
  546. }
  547. }
  548. }
  549. fun vector_destroy_closure 3 {
  550. $ctx
  551. $key
  552. $value
  553. @ctx 2 param = ;
  554. @key 1 param = ;
  555. @value 0 param = ;
  556. value vector_destroy ;
  557. }
  558. fun process_token_function 5 {
  559. $ctx
  560. $tokens
  561. $intoks
  562. $iptr
  563. $subst
  564. @ctx 4 param = ;
  565. @tokens 3 param = ;
  566. @intoks 2 param = ;
  567. @iptr 1 param = ;
  568. @subst 0 param = ;
  569. # First parse the inputs
  570. $args
  571. @args map_init = ;
  572. while args map_size subst SUBST_PARAMETERS take vector_size < {
  573. $depth
  574. @depth 0 = ;
  575. $cont
  576. @cont 1 = ;
  577. $arg
  578. @arg 4 vector_init = ;
  579. $tok
  580. while cont {
  581. @tok intoks iptr ** vector_at = ;
  582. iptr iptr ** 1 + = ;
  583. iptr ** intoks vector_size < "process_token_function: end of stream found" assert_msg ;
  584. if tok "," strcmp 0 == tok ")" strcmp 0 == || depth 0 == && {
  585. @cont 0 = ;
  586. } else {
  587. if tok "(" strcmp 0 == {
  588. @depth depth 1 + = ;
  589. }
  590. if tok ")" strcmp 0 == {
  591. @depth depth 1 - = ;
  592. }
  593. arg tok vector_push_back ;
  594. }
  595. }
  596. $ident
  597. @ident subst SUBST_PARAMETERS take args map_size vector_at = ;
  598. args ident arg map_set ;
  599. if args map_size subst SUBST_PARAMETERS take vector_size == {
  600. tok ")" strcmp 0 == "process_token_function: ) expected" assert_msg ;
  601. } else {
  602. tok "," strcmp 0 == "process_token_function: , expected" assert_msg ;
  603. }
  604. }
  605. if args map_size 0 != {
  606. iptr iptr ** 1 - = ;
  607. }
  608. # Output tokens
  609. $i
  610. @i 0 = ;
  611. $repl
  612. @repl subst SUBST_REPLACEMENT take = ;
  613. while i repl vector_size < {
  614. $tok
  615. @tok repl i vector_at = ;
  616. if tok "#" strcmp 0 == {
  617. @i i 1 + = ;
  618. i repl vector_size < "process_token_function: invalid # usage" assert_msg ;
  619. @tok repl i vector_at = ;
  620. args tok map_has "process_token_function: # requires a parameter" assert_msg ;
  621. $newtok
  622. @newtok ctx args tok map_at process_token_stringify = ;
  623. tokens newtok push_token ;
  624. } else {
  625. if args tok map_has {
  626. $repl2
  627. @repl2 args tok map_at = ;
  628. $j
  629. @j 0 = ;
  630. # If the substitution is empty, push an empty token to trigger ## pasting
  631. if repl2 vector_size 0 == {
  632. tokens "" strdup push_token ;
  633. }
  634. while j repl2 vector_size < {
  635. @tok repl2 j vector_at = ;
  636. tokens tok strdup push_token ;
  637. @j j 1 + = ;
  638. }
  639. } else {
  640. tokens tok strdup push_token ;
  641. }
  642. }
  643. @i i 1 + = ;
  644. }
  645. # Free temporaries
  646. args @vector_destroy_closure 0 map_foreach ;
  647. args map_destroy ;
  648. }
  649. fun process_token 4 {
  650. $ctx
  651. $tokens
  652. $intoks
  653. $iptr
  654. @iptr 0 param = ;
  655. @intoks 1 param = ;
  656. @tokens 2 param = ;
  657. @ctx 3 param = ;
  658. $tok
  659. @tok intoks iptr ** vector_at = ;
  660. # Search the token in the context defines
  661. $changed
  662. @changed 0 = ;
  663. if ctx PPCTX_DEFINES take tok map_has {
  664. # "Expanding: " log ;
  665. # tok log ;
  666. # "\n" log ;
  667. $subst
  668. @subst ctx PPCTX_DEFINES take tok map_at = ;
  669. $repl
  670. @repl subst SUBST_REPLACEMENT take = ;
  671. if subst SUBST_IS_FUNCTION take {
  672. $saved_i
  673. @saved_i iptr ** = ;
  674. intoks iptr discard_white_newline_tokens ;
  675. @tok intoks iptr ** vector_at = ;
  676. if tok "(" strcmp 0 == {
  677. @changed 1 = ;
  678. iptr iptr ** 1 + = ;
  679. iptr ** intoks vector_size < "preproc_token: end of stream found" assert_msg ;
  680. ctx tokens intoks iptr subst process_token_function ;
  681. } else {
  682. # No actual substitution, roll back changes and push unchanged token
  683. iptr saved_i = ;
  684. @tok intoks iptr ** vector_at = ;
  685. tokens tok strdup vector_push_back ;
  686. }
  687. } else {
  688. $different
  689. @different 1 = ;
  690. # Do not mark as changed if the macro expands back to itself
  691. if repl vector_size 1 == {
  692. if repl 0 vector_at tok strcmp 0 == {
  693. @different 0 = ;
  694. }
  695. }
  696. if different {
  697. @changed 1 = ;
  698. }
  699. $j
  700. @j 0 = ;
  701. while j repl vector_size < {
  702. tokens repl j vector_at strdup vector_push_back ;
  703. @j j 1 + = ;
  704. }
  705. }
  706. } else {
  707. tokens tok strdup vector_push_back ;
  708. }
  709. changed ret ;
  710. }
  711. fun load_token_list_from_diskfs 0 {
  712. $fd
  713. @fd "/disk1/tokens" vfs_open = ;
  714. $tokens
  715. @tokens 4 vector_init = ;
  716. $c
  717. @c fd vfs_read = ;
  718. $tok_size
  719. $tok_cap
  720. $tok
  721. @tok_size 0 = ;
  722. @tok_cap 4 = ;
  723. @tok tok_cap malloc = ;
  724. while c 0xffffffff != {
  725. if tok_size tok_cap == {
  726. @tok_cap tok_cap 2 * = ;
  727. @tok tok_cap tok realloc = ;
  728. }
  729. tok_size tok_cap < "load_token_list_from_diskfs: error 1" assert_msg ;
  730. if c '\n' == {
  731. tok tok_size + '\0' =c ;
  732. tokens tok vector_push_back ;
  733. @tok_size 0 = ;
  734. @tok_cap 4 = ;
  735. @tok tok_cap malloc = ;
  736. } else {
  737. tok tok_size + c =c ;
  738. @tok_size tok_size 1 + = ;
  739. }
  740. @c fd vfs_read = ;
  741. }
  742. tok free ;
  743. tok_size 0 == "load_token_list_from_diskfs: file does not finish with a newline" assert_msg ;
  744. fd vfs_close ;
  745. tokens ret ;
  746. }
  747. fun dump_token_list_to_debugfs 1 {
  748. $tokens
  749. @tokens 0 param = ;
  750. $i
  751. @i 0 = ;
  752. "tokens" debugfs_begin_file ;
  753. while i tokens vector_size < {
  754. $tok
  755. @tok tokens i vector_at = ;
  756. $j
  757. @j 0 = ;
  758. while tok j + **c 0 != {
  759. tok j + **c debugfs_write_char ;
  760. @j j 1 + = ;
  761. }
  762. '\n' debugfs_write_char ;
  763. @i i 1 + = ;
  764. }
  765. debugfs_finish_file ;
  766. }
  767. fun print_token_list 1 {
  768. $tokens
  769. @tokens 0 param = ;
  770. $i
  771. @i 0 = ;
  772. while i tokens vector_size < {
  773. $tok
  774. @tok tokens i vector_at = ;
  775. if tok **c '\n' == {
  776. "NL" log ;
  777. } else {
  778. tok log ;
  779. }
  780. "#" log ;
  781. @i i 1 + = ;
  782. }
  783. "\n" log ;
  784. }
  785. fun preproc_replace_int 3 {
  786. $ctx
  787. $intoks
  788. $outtoks
  789. @ctx 2 param = ;
  790. @intoks 1 param = ;
  791. @outtoks 0 param = ;
  792. $changed
  793. @changed 0 = ;
  794. $i
  795. @i 0 = ;
  796. while i intoks vector_size < {
  797. @changed changed ctx outtoks intoks @i process_token || = ;
  798. @i i 1 + = ;
  799. }
  800. changed ret ;
  801. }
  802. fun preproc_replace 2 {
  803. $ctx
  804. $intoks
  805. @ctx 1 param = ;
  806. @intoks 0 param = ;
  807. $changed
  808. @changed 1 = ;
  809. @intoks intoks dup_vect_of_ptrs = ;
  810. while changed {
  811. $outtoks
  812. @outtoks 4 vector_init = ;
  813. # "---\n" log ;
  814. # intoks print_token_list ;
  815. @changed ctx intoks outtoks preproc_replace_int = ;
  816. intoks free_vect_of_ptrs ;
  817. @intoks outtoks = ;
  818. }
  819. intoks ret ;
  820. }
  821. fun preproc_expand 3 {
  822. $ctx
  823. $intoks
  824. $outtoks
  825. @ctx 2 param = ;
  826. @intoks 1 param = ;
  827. @outtoks 0 param = ;
  828. $replaced
  829. @replaced ctx intoks preproc_replace = ;
  830. $i
  831. @i 0 = ;
  832. while i replaced vector_size < {
  833. outtoks replaced i vector_at vector_push_back ;
  834. @i i 1 + = ;
  835. }
  836. replaced vector_destroy ;
  837. }
  838. fun preproc_process_define 4 {
  839. $ctx
  840. $tokens
  841. $intoks
  842. $iptr
  843. @ctx 3 param = ;
  844. @tokens 2 param = ;
  845. @intoks 1 param = ;
  846. @iptr 0 param = ;
  847. intoks iptr discard_white_tokens ;
  848. $ident
  849. @ident intoks iptr ** vector_at = ;
  850. ident "\n" strcmp 0 != "preproc_process_define: newline found" assert_msg ;
  851. iptr iptr ** 1 + = ;
  852. iptr ** intoks vector_size < "preproc_process_define: end of stream found" assert_msg ;
  853. $tok
  854. @tok intoks iptr ** vector_at = ;
  855. $is_func
  856. @is_func tok "(" strcmp 0 == = ;
  857. $subst
  858. @subst subst_init = ;
  859. subst SUBST_IS_FUNCTION take_addr is_func = ;
  860. if is_func {
  861. intoks iptr discard_white_tokens ;
  862. @tok intoks iptr ** vector_at = ;
  863. if tok ")" strcmp 0 != {
  864. $cont
  865. @cont 1 = ;
  866. while cont {
  867. tok is_valid_identifier "preproc_process_define: token is not an identifier" assert_msg ;
  868. subst SUBST_PARAMETERS take tok strdup vector_push_back ;
  869. intoks iptr discard_white_tokens ;
  870. @tok intoks iptr ** vector_at = ;
  871. if tok ")" strcmp 0 == {
  872. @cont 0 = ;
  873. } else {
  874. tok "," strcmp 0 == "preproc_process_define: , or ) expected" assert_msg ;
  875. }
  876. intoks iptr discard_white_tokens ;
  877. @tok intoks iptr ** vector_at = ;
  878. }
  879. } else {
  880. intoks iptr discard_white_tokens ;
  881. @tok intoks iptr ** vector_at = ;
  882. }
  883. } else {
  884. iptr iptr ** 1 - = ;
  885. intoks iptr discard_white_tokens ;
  886. @tok intoks iptr ** vector_at = ;
  887. }
  888. while tok "\n" strcmp 0 != {
  889. subst SUBST_REPLACEMENT take tok strdup vector_push_back ;
  890. iptr iptr ** 1 + = ;
  891. iptr ** intoks vector_size < "preproc_process_define: end of stream found" assert_msg ;
  892. @tok intoks iptr ** vector_at = ;
  893. }
  894. if ctx PPCTX_DEFINES take ident map_has {
  895. $subst2
  896. @subst2 ctx PPCTX_DEFINES take ident map_at = ;
  897. # Check that the two definitions are identical
  898. subst SUBST_IS_FUNCTION take subst2 SUBST_IS_FUNCTION take == "preproc_process_define: redefining macro with a different is_function value" ident assert_msg_str ;
  899. subst SUBST_PARAMETERS take subst2 SUBST_PARAMETERS take cmp_vect_of_ptrs "preproc_process_define: redefining macro with different parameters" ident assert_msg_str ;
  900. subst SUBST_REPLACEMENT take subst2 SUBST_REPLACEMENT take cmp_vect_of_ptrs "preproc_process_define: redefining macro with different replacement" ident assert_msg_str ;
  901. subst2 subst_destroy ;
  902. ctx PPCTX_DEFINES take ident map_erase ;
  903. }
  904. ctx PPCTX_DEFINES take ident subst map_set ;
  905. }
  906. fun preproc_process_undef 4 {
  907. $ctx
  908. $tokens
  909. $intoks
  910. $iptr
  911. @ctx 3 param = ;
  912. @tokens 2 param = ;
  913. @intoks 1 param = ;
  914. @iptr 0 param = ;
  915. intoks iptr discard_white_tokens ;
  916. $tok
  917. @tok intoks iptr ** vector_at = ;
  918. # If this definition is known, erase it
  919. if ctx PPCTX_DEFINES take tok map_has {
  920. $subst
  921. @subst ctx PPCTX_DEFINES take tok map_at = ;
  922. subst subst_destroy ;
  923. ctx PPCTX_DEFINES take tok map_erase ;
  924. }
  925. intoks iptr discard_white_tokens ;
  926. }
  927. ifun _preproc_file 3
  928. fun preproc_process_include 4 {
  929. $ctx
  930. $tokens
  931. $intoks
  932. $iptr
  933. @ctx 3 param = ;
  934. @tokens 2 param = ;
  935. @intoks 1 param = ;
  936. @iptr 0 param = ;
  937. intoks iptr discard_white_tokens ;
  938. $tok
  939. @tok intoks iptr ** vector_at = ;
  940. $filename
  941. @filename "" strdup = ;
  942. if tok "<" strcmp 0 == {
  943. iptr iptr ** 1 + = ;
  944. @tok intoks iptr ** vector_at = ;
  945. while tok ">" strcmp 0 != {
  946. @filename filename tok append_to_str = ;
  947. iptr iptr ** 1 + = ;
  948. @tok intoks iptr ** vector_at = ;
  949. }
  950. } else {
  951. tok **c '\"' == "preproc_process_include: syntax error in inclusion directive" assert_msg ;
  952. filename free ;
  953. @filename tok 1 + strdup = ;
  954. filename filename strlen 1 - + '\0' =c ;
  955. }
  956. # Search for the right include path
  957. $i
  958. @i ctx PPCTX_INCLUDE_PATH take vector_size 1 - = ;
  959. $found
  960. @found 0 = ;
  961. while i 0 >= found ! && {
  962. $testfile
  963. @testfile filename strdup ctx PPCTX_INCLUDE_PATH take i vector_at prepend_to_str = ;
  964. $fd
  965. @fd testfile vfs_open = ;
  966. if fd {
  967. fd vfs_close ;
  968. filename free ;
  969. @filename testfile = ;
  970. @found 1 = ;
  971. } else {
  972. testfile free ;
  973. }
  974. @i i 1 - = ;
  975. }
  976. found "preproc_process_include: cannot find file" filename assert_msg_str ;
  977. if ctx PPCTX_VERBOSE take 1 == {
  978. '[' write ;
  979. }
  980. if ctx PPCTX_VERBOSE take 2 == {
  981. "Including file " log ;
  982. filename log ;
  983. "\n" log ;
  984. }
  985. tokens ctx filename _preproc_file ;
  986. if ctx PPCTX_VERBOSE take 1 == {
  987. ']' write ;
  988. }
  989. if ctx PPCTX_VERBOSE take 2 == {
  990. "Finished including file " log ;
  991. filename log ;
  992. "\n" log ;
  993. }
  994. filename free ;
  995. intoks iptr discard_white_tokens ;
  996. }
  997. ifun preproc_eval_ext 2
  998. fun preproc_eval 2 {
  999. $ctx
  1000. $ast
  1001. @ctx 1 param = ;
  1002. @ast 0 param = ;
  1003. $value
  1004. @value ast @preproc_eval_ext ctx ast_eval = ;
  1005. value "preproc_eval: failed" assert_msg ;
  1006. value ** ret ;
  1007. }
  1008. fun preproc_eval_ext 2 {
  1009. $ctx
  1010. $ast
  1011. @ctx 1 param = ;
  1012. @ast 0 param = ;
  1013. $defs
  1014. @defs ctx PPCTX_DEFINES take = ;
  1015. $name
  1016. @name ast AST_NAME take = ;
  1017. if ast AST_TYPE take 0 == {
  1018. # Operand
  1019. $value
  1020. @value i64_init = ;
  1021. if name is_valid_identifier {
  1022. if defs name map_has {
  1023. $subst
  1024. @subst defs name map_at = ;
  1025. $repl
  1026. @repl subst SUBST_REPLACEMENT take = ;
  1027. subst SUBST_IS_FUNCTION take ! "preproc_eval: not supported" assert_msg ;
  1028. if repl vector_size 1 == repl 0 vector_at is_valid_identifier ! && {
  1029. value repl 0 vector_at atoi i64_from_u32 ;
  1030. } else {
  1031. $ast2
  1032. $i
  1033. @i 0 1 - = ;
  1034. $int
  1035. @int repl @i ppctx_astint_init = ;
  1036. @ast2 int ";;" ast_parse1 = ;
  1037. int ppctx_astint_destroy ;
  1038. $res
  1039. @res ctx ast2 preproc_eval = ;
  1040. ast2 ast_destroy ;
  1041. value res i64_from_u32 ;
  1042. }
  1043. } else {
  1044. value 0 i64_from_u32 ;
  1045. }
  1046. } else {
  1047. value name atoi i64_from_u32 ;
  1048. }
  1049. value ret ;
  1050. } else {
  1051. # Operator: the only special operator here is "defined"
  1052. if name "defined_PRE" strcmp 0 == {
  1053. $value
  1054. @value i64_init = ;
  1055. $child
  1056. @child ast AST_RIGHT take = ;
  1057. child AST_TYPE take 0 == "preproc_eval: not an identifier" assert_msg ;
  1058. $ident
  1059. @ident child AST_NAME take = ;
  1060. value defs ident map_has i64_from_u32 ;
  1061. value ret ;
  1062. }
  1063. 0 ret ;
  1064. }
  1065. }
  1066. fun preproc_process_endif 5 {
  1067. $ctx
  1068. $tokens
  1069. $intoks
  1070. $iptr
  1071. $if_stack
  1072. @ctx 4 param = ;
  1073. @tokens 3 param = ;
  1074. @intoks 2 param = ;
  1075. @iptr 1 param = ;
  1076. @if_stack 0 param = ;
  1077. if_stack vector_size 1 > "preproc_process_endif: unmatched endif" assert_msg ;
  1078. if_stack vector_pop_back ;
  1079. intoks iptr discard_white_tokens ;
  1080. }
  1081. fun preproc_process_else 5 {
  1082. $ctx
  1083. $tokens
  1084. $intoks
  1085. $iptr
  1086. $if_stack
  1087. @ctx 4 param = ;
  1088. @tokens 3 param = ;
  1089. @intoks 2 param = ;
  1090. @iptr 1 param = ;
  1091. @if_stack 0 param = ;
  1092. $state
  1093. if_stack vector_size 1 > "preproc_process_endif: unmatched else" assert_msg ;
  1094. @state if_stack vector_pop_back = ;
  1095. @state state 1 + = ;
  1096. if state 2 > {
  1097. @state 2 = ;
  1098. }
  1099. if_stack state vector_push_back ;
  1100. intoks iptr discard_white_tokens ;
  1101. }
  1102. fun preproc_process_ifdef 5 {
  1103. $ctx
  1104. $tokens
  1105. $intoks
  1106. $iptr
  1107. $if_stack
  1108. @ctx 4 param = ;
  1109. @tokens 3 param = ;
  1110. @intoks 2 param = ;
  1111. @iptr 1 param = ;
  1112. @if_stack 0 param = ;
  1113. intoks iptr discard_white_tokens ;
  1114. $ident
  1115. @ident intoks iptr ** vector_at = ;
  1116. ident "\n" strcmp 0 != "preproc_process_ifdef: newline found" assert_msg ;
  1117. if ctx PPCTX_DEFINES take ident map_has {
  1118. if_stack 1 vector_push_back ;
  1119. } else {
  1120. if_stack 0 vector_push_back ;
  1121. }
  1122. intoks iptr discard_white_tokens ;
  1123. }
  1124. fun preproc_process_ifndef 5 {
  1125. $ctx
  1126. $tokens
  1127. $intoks
  1128. $iptr
  1129. $if_stack
  1130. @ctx 4 param = ;
  1131. @tokens 3 param = ;
  1132. @intoks 2 param = ;
  1133. @iptr 1 param = ;
  1134. @if_stack 0 param = ;
  1135. intoks iptr discard_white_tokens ;
  1136. $ident
  1137. @ident intoks iptr ** vector_at = ;
  1138. ident "\n" strcmp 0 != "preproc_process_ifndef: newline found" assert_msg ;
  1139. if ctx PPCTX_DEFINES take ident map_has {
  1140. if_stack 0 vector_push_back ;
  1141. } else {
  1142. if_stack 1 vector_push_back ;
  1143. }
  1144. intoks iptr discard_white_tokens ;
  1145. }
  1146. fun preproc_process_elif 5 {
  1147. $ctx
  1148. $tokens
  1149. $intoks
  1150. $iptr
  1151. $if_stack
  1152. @ctx 4 param = ;
  1153. @tokens 3 param = ;
  1154. @intoks 2 param = ;
  1155. @iptr 1 param = ;
  1156. @if_stack 0 param = ;
  1157. $ast
  1158. $int
  1159. @int intoks iptr ppctx_astint_init = ;
  1160. @ast int "\n" ast_parse1 = ;
  1161. int ppctx_astint_destroy ;
  1162. #ast ast_dump ;
  1163. $value
  1164. @value ctx ast preproc_eval ! ! = ;
  1165. ast ast_destroy ;
  1166. $state
  1167. if_stack vector_size 1 > "preproc_process_elif: unmatched else" assert_msg ;
  1168. @state if_stack vector_pop_back = ;
  1169. @state state 1 + = ;
  1170. if state 2 > {
  1171. @state 2 = ;
  1172. }
  1173. if state 1 == value ! && {
  1174. @state 0 = ;
  1175. }
  1176. if_stack state vector_push_back ;
  1177. }
  1178. fun preproc_process_if 5 {
  1179. $ctx
  1180. $tokens
  1181. $intoks
  1182. $iptr
  1183. $if_stack
  1184. @ctx 4 param = ;
  1185. @tokens 3 param = ;
  1186. @intoks 2 param = ;
  1187. @iptr 1 param = ;
  1188. @if_stack 0 param = ;
  1189. $ast
  1190. $int
  1191. @int intoks iptr ppctx_astint_init = ;
  1192. @ast int "\n" ast_parse1 = ;
  1193. int ppctx_astint_destroy ;
  1194. #ast ast_dump ;
  1195. $value
  1196. @value ctx ast preproc_eval ! ! = ;
  1197. ast ast_destroy ;
  1198. if_stack value vector_push_back ;
  1199. }
  1200. fun preproc_process_error 4 {
  1201. $ctx
  1202. $tokens
  1203. $intoks
  1204. $iptr
  1205. @ctx 3 param = ;
  1206. @tokens 2 param = ;
  1207. @intoks 1 param = ;
  1208. @iptr 0 param = ;
  1209. intoks iptr discard_white_tokens ;
  1210. $msg
  1211. @msg intoks iptr ** vector_at = ;
  1212. msg "\n" strcmp 0 != "preproc_process_error: newline found" assert_msg ;
  1213. "#error with " log ;
  1214. msg log ;
  1215. "\n" log ;
  1216. intoks iptr discard_white_tokens ;
  1217. 0 "preproc_process_error: dying because of error" assert_msg ;
  1218. }
  1219. fun preproc_process_warning 4 {
  1220. $ctx
  1221. $tokens
  1222. $intoks
  1223. $iptr
  1224. @ctx 3 param = ;
  1225. @tokens 2 param = ;
  1226. @intoks 1 param = ;
  1227. @iptr 0 param = ;
  1228. intoks iptr discard_white_tokens ;
  1229. $msg
  1230. @msg intoks iptr ** vector_at = ;
  1231. msg "\n" strcmp 0 != "preproc_process_warning: newline found" assert_msg ;
  1232. "#warning with " log ;
  1233. msg log ;
  1234. "\n" log ;
  1235. intoks iptr discard_white_tokens ;
  1236. }
  1237. fun is_including 1 {
  1238. $if_stack
  1239. @if_stack 0 param = ;
  1240. $i
  1241. @i 0 = ;
  1242. while i if_stack vector_size < {
  1243. if if_stack i vector_at 1 != {
  1244. 0 ret ;
  1245. }
  1246. @i i 1 + = ;
  1247. }
  1248. 1 ret ;
  1249. }
  1250. fun _preproc_file 3 {
  1251. $tokens
  1252. $ctx
  1253. $filename
  1254. @tokens 2 param = ;
  1255. @ctx 1 param = ;
  1256. @filename 0 param = ;
  1257. $intoks
  1258. @intoks filename tokenize_file = ;
  1259. # All incoming tokens are accumulated in ready_toks; before each
  1260. # preprocessor directive is processed (and at the end of the file),
  1261. # tokens in ready_tokens are expanded and flushed; this is probably
  1262. # not the correct algorithm, but it should work for sane programs.
  1263. $ready_toks
  1264. @ready_toks 4 vector_init = ;
  1265. $i
  1266. @i 0 = ;
  1267. $at_newline
  1268. @at_newline 1 = ;
  1269. # For each #if stack level, we store 0 if no if has matched yet, 1
  1270. # if we are including and 2 if we have already matched
  1271. $if_stack
  1272. @if_stack 4 vector_init = ;
  1273. if_stack 1 vector_push_back ;
  1274. $including
  1275. @including if_stack is_including = ;
  1276. while i intoks vector_size < {
  1277. $tok
  1278. @tok intoks i vector_at = ;
  1279. if tok "#" strcmp 0 == at_newline && {
  1280. ctx ready_toks tokens preproc_expand ;
  1281. ready_toks vector_clear ;
  1282. intoks @i discard_white_tokens ;
  1283. @tok intoks i vector_at = ;
  1284. # "Processing " log ;
  1285. # tok log ;
  1286. # "\n" log ;
  1287. $processed
  1288. @processed 0 = ;
  1289. if tok "include" strcmp 0 == processed ! && {
  1290. if including {
  1291. ctx tokens intoks @i preproc_process_include ;
  1292. } else {
  1293. intoks @i discard_until_newline ;
  1294. }
  1295. @processed 1 = ;
  1296. }
  1297. if tok "define" strcmp 0 == processed ! && {
  1298. if including {
  1299. ctx tokens intoks @i preproc_process_define ;
  1300. } else {
  1301. intoks @i discard_until_newline ;
  1302. }
  1303. @processed 1 = ;
  1304. }
  1305. if tok "undef" strcmp 0 == processed ! && {
  1306. if including {
  1307. ctx tokens intoks @i preproc_process_undef ;
  1308. } else {
  1309. intoks @i discard_until_newline ;
  1310. }
  1311. @processed 1 = ;
  1312. }
  1313. if tok "error" strcmp 0 == processed ! && {
  1314. if including {
  1315. ctx tokens intoks @i preproc_process_error ;
  1316. } else {
  1317. intoks @i discard_until_newline ;
  1318. }
  1319. @processed 1 = ;
  1320. }
  1321. if tok "warning" strcmp 0 == processed ! && {
  1322. if including {
  1323. ctx tokens intoks @i preproc_process_warning ;
  1324. } else {
  1325. intoks @i discard_until_newline ;
  1326. }
  1327. @processed 1 = ;
  1328. }
  1329. if tok "pragma" strcmp 0 == processed ! && {
  1330. # pragma-s are silently discarded
  1331. intoks @i discard_until_newline ;
  1332. @processed 1 = ;
  1333. }
  1334. if tok "if" strcmp 0 == processed ! && {
  1335. ctx tokens intoks @i if_stack preproc_process_if ;
  1336. @including if_stack is_including = ;
  1337. @processed 1 = ;
  1338. }
  1339. if tok "endif" strcmp 0 == processed ! && {
  1340. ctx tokens intoks @i if_stack preproc_process_endif ;
  1341. @including if_stack is_including = ;
  1342. @processed 1 = ;
  1343. }
  1344. if tok "elif" strcmp 0 == processed ! && {
  1345. ctx tokens intoks @i if_stack preproc_process_elif ;
  1346. @including if_stack is_including = ;
  1347. @processed 1 = ;
  1348. }
  1349. if tok "else" strcmp 0 == processed ! && {
  1350. ctx tokens intoks @i if_stack preproc_process_else ;
  1351. @including if_stack is_including = ;
  1352. @processed 1 = ;
  1353. }
  1354. if tok "ifdef" strcmp 0 == processed ! && {
  1355. ctx tokens intoks @i if_stack preproc_process_ifdef ;
  1356. @including if_stack is_including = ;
  1357. @processed 1 = ;
  1358. }
  1359. if tok "ifndef" strcmp 0 == processed ! && {
  1360. ctx tokens intoks @i if_stack preproc_process_ifndef ;
  1361. @including if_stack is_including = ;
  1362. @processed 1 = ;
  1363. }
  1364. if processed ! {
  1365. 0 "_preproc_file: invalid preprocessor directive" assert_msg ;
  1366. }
  1367. intoks i vector_at "\n" strcmp 0 == "_preproc_file: error 1" assert_msg ;
  1368. } else {
  1369. if including {
  1370. ready_toks tok vector_push_back ;
  1371. #ctx tokens intoks @i process_token ;
  1372. }
  1373. }
  1374. @tok intoks i vector_at = ;
  1375. @at_newline tok "\n" strcmp 0 == = ;
  1376. @i i 1 + = ;
  1377. }
  1378. ctx ready_toks tokens preproc_expand ;
  1379. ready_toks vector_clear ;
  1380. ready_toks vector_destroy ;
  1381. if_stack vector_size 1 == "_preproc_file: some #if was not closed" assert_msg ;
  1382. if_stack vector_destroy ;
  1383. intoks free_vect_of_ptrs ;
  1384. }
  1385. fun preproc_file 3 {
  1386. $tokens
  1387. $ctx
  1388. $filename
  1389. @tokens 2 param = ;
  1390. @ctx 1 param = ;
  1391. @filename 0 param = ;
  1392. tokens ctx filename _preproc_file ;
  1393. if ctx PPCTX_VERBOSE take 1 == {
  1394. '\n' write ;
  1395. }
  1396. }
  1397. fun remove_whites 1 {
  1398. $intoks
  1399. @intoks 0 param = ;
  1400. $outtoks
  1401. @outtoks 4 vector_init = ;
  1402. $i
  1403. @i 0 = ;
  1404. while i intoks vector_size < {
  1405. $tok
  1406. @tok intoks i vector_at = ;
  1407. if tok " " strcmp 0 == {
  1408. tok free ;
  1409. } else {
  1410. if tok "\n" strcmp 0 == {
  1411. tok free ;
  1412. } else {
  1413. outtoks tok vector_push_back ;
  1414. }
  1415. }
  1416. @i i 1 + = ;
  1417. }
  1418. intoks vector_destroy ;
  1419. outtoks ret ;
  1420. }
  1421. fun collapse_strings 1 {
  1422. $intoks
  1423. @intoks 0 param = ;
  1424. $outtoks
  1425. @outtoks 4 vector_init = ;
  1426. $i
  1427. @i 0 = ;
  1428. $oldtok
  1429. @oldtok 0 = ;
  1430. while i intoks vector_size < {
  1431. $tok
  1432. @tok intoks i vector_at = ;
  1433. if oldtok {
  1434. if tok **c '\"' == oldtok **c '\"' == && {
  1435. $oldtok_len
  1436. @oldtok_len oldtok strlen = ;
  1437. oldtok oldtok_len + 1 - **c '\"' "collapse_string: string token is not valid" assert_msg ;
  1438. oldtok oldtok_len + 1 - '\0' =c ;
  1439. @oldtok oldtok tok 1 + append_to_str = ;
  1440. tok free ;
  1441. } else {
  1442. outtoks oldtok vector_push_back ;
  1443. @oldtok tok = ;
  1444. }
  1445. } else {
  1446. @oldtok tok = ;
  1447. }
  1448. @i i 1 + = ;
  1449. }
  1450. if oldtok 0 != {
  1451. outtoks oldtok vector_push_back ;
  1452. }
  1453. intoks vector_destroy ;
  1454. outtoks ret ;
  1455. }