pc_zpp.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /***** spin: pc_zpp.c *****/
  10. /* Copyright (c) 1997-2003 by Lucent Technologies, Bell Laboratories. */
  11. /* All Rights Reserved. This software is for educational purposes only. */
  12. /* No guarantee whatsoever is expressed or implied by the distribution of */
  13. /* this code. Permission is given to distribute this code provided that */
  14. /* this introductory message is not removed and no monies are exchanged. */
  15. /* Software written by Gerard J. Holzmann. For tool documentation see: */
  16. /* http://spinroot.com/ */
  17. /* Send all bug-reports and/or questions to: bugs@spinroot.com */
  18. /* pc_zpp.c is only used in the PC version of Spin */
  19. /* it is included to avoid too great a reliance on an external cpp */
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <ctype.h>
  24. #include "spin.h"
  25. #ifdef PC
  26. enum cstate { PLAIN, IN_STRING, IN_QUOTE, S_COMM, COMMENT, E_COMM };
  27. #define MAXNEST 32
  28. #define MAXDEF 128
  29. #define MAXLINE 2048
  30. #define GENEROUS 8192
  31. #define debug(x,y) if (verbose) printf(x,y)
  32. static FILE *outpp /* = stdout */;
  33. static int if_truth[MAXNEST];
  34. static int printing[MAXNEST];
  35. static int if_depth, nr_defs, verbose = 0;
  36. static enum cstate state = PLAIN;
  37. static char Out1[GENEROUS], Out2[GENEROUS];
  38. static struct Defines {
  39. int exists;
  40. char *src, *trg;
  41. } d[MAXDEF];
  42. static int process(char *, int, char *);
  43. static int zpp_do(char *);
  44. extern char *emalloc(size_t); /* main.c */
  45. static int
  46. do_define(char *p)
  47. { char *q, *r, *s;
  48. for (q = p+strlen(p)-1; q > p; q--)
  49. if (*q == '\n' || *q == '\t' || *q == ' ')
  50. *q = '\0';
  51. else
  52. break;
  53. q = p + strspn(p, " \t");
  54. if (!(r = strchr(q, '\t')))
  55. r = strchr(q, ' ');
  56. if (!r) { s = ""; goto adddef; }
  57. s = r + strspn(r, " \t");
  58. *r = '\0';
  59. if (strchr(q, '('))
  60. { debug("zpp: #define with arguments %s\n", q);
  61. return 0;
  62. }
  63. for (r = q+strlen(q)-1; r > q; r--)
  64. if (*r == ' ' || *r == '\t')
  65. *r = '\0';
  66. else
  67. break;
  68. if (nr_defs >= MAXDEF)
  69. { debug("zpp: too many #defines (max %d)\n", nr_defs);
  70. return 0;
  71. }
  72. if (strcmp(q, s) != 0)
  73. { int j;
  74. adddef: for (j = 0; j < nr_defs; j++)
  75. if (!strcmp(d[j].src, q))
  76. d[j].exists = 0;
  77. d[nr_defs].src = emalloc(strlen(q)+1);
  78. d[nr_defs].trg = emalloc(strlen(s)+1);
  79. strcpy(d[nr_defs].src, q);
  80. strcpy(d[nr_defs].trg, s);
  81. d[nr_defs++].exists = 1;
  82. }
  83. return 1;
  84. }
  85. static int
  86. isvalid(int c)
  87. {
  88. return (isalnum(c) || c == '_');
  89. }
  90. static char *
  91. apply(char *p0)
  92. { char *out, *in1, *in2, *startat;
  93. int i, j;
  94. startat = in1 = Out2; strcpy(Out2, p0);
  95. out = Out1; *out = '\0';
  96. for (i = nr_defs-1; i >= 0; i--)
  97. { if (!d[i].exists) continue;
  98. j = (int) strlen(d[i].src);
  99. more: in2 = strstr(startat, d[i].src);
  100. if (!in2) /* no more matches */
  101. { startat = in1;
  102. continue;
  103. }
  104. if ((in2 == in1 || !isvalid(*(in2-1)))
  105. && (in2+j == '\0' || !isvalid(*(in2+j))))
  106. { *in2 = '\0';
  107. if (strlen(in1)+strlen(d[i].trg)+strlen(in2+j) >= GENEROUS)
  108. {
  109. printf("spin: macro expansion overflow %s -> %s ?\n",
  110. d[i].src, d[i].trg);
  111. return in1;
  112. }
  113. strcat(out, in1);
  114. strcat(out, d[i].trg);
  115. strcat(out, in2+j);
  116. if (in1 == Out2)
  117. { startat = in1 = Out1;
  118. out = Out2;
  119. } else
  120. { startat = in1 = Out2;
  121. out = Out1;
  122. }
  123. *out = '\0';
  124. } else
  125. { startat = in2+1; /* +1 not +j.. */
  126. }
  127. goto more; /* recursive defines */
  128. }
  129. return in1;
  130. }
  131. static char *
  132. do_common(char *p)
  133. { char *q, *s;
  134. q = p + strspn(p, " \t");
  135. for (s = (q + strlen(q) - 1); s > q; s--)
  136. if (*s == ' ' || *s == '\t' || *s == '\n')
  137. *s = '\0';
  138. else
  139. break;
  140. return q;
  141. }
  142. static int
  143. do_undefine(char *p)
  144. { int i; char *q = do_common(p);
  145. for (i = 0; i < nr_defs; i++)
  146. if (!strcmp(d[i].src, q))
  147. d[i].exists = 0;
  148. return 1;
  149. }
  150. static char *
  151. check_ifdef(char *p)
  152. { int i; char *q = do_common(p);
  153. for (i = 0; i < nr_defs; i++)
  154. if (d[i].exists
  155. && !strcmp(d[i].src, q))
  156. return d[i].trg;
  157. return (char *) 0;
  158. }
  159. static int
  160. do_ifdef(char *p)
  161. {
  162. if (++if_depth >= MAXNEST)
  163. { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
  164. return 0;
  165. }
  166. if_truth[if_depth] = (check_ifdef(p) != (char *)0);
  167. printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
  168. return 1;
  169. }
  170. static int
  171. do_ifndef(char *p)
  172. {
  173. if (++if_depth >= MAXNEST)
  174. { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
  175. return 0;
  176. }
  177. if_truth[if_depth] = (check_ifdef(p) == (char *)0);
  178. printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
  179. return 1;
  180. }
  181. static int
  182. is_simple(char *q)
  183. {
  184. if (!q) return 0;
  185. if (strcmp(q, "0") == 0)
  186. if_truth[if_depth] = 0;
  187. else if (strcmp(q, "1") == 0)
  188. if_truth[if_depth] = 1;
  189. else
  190. return 0;
  191. return 1;
  192. }
  193. static int
  194. do_if(char *p)
  195. { char *q = do_common(p);
  196. if (++if_depth >= MAXNEST)
  197. { debug("zpp: too deeply nested (max %d)\n", MAXNEST);
  198. return 0;
  199. }
  200. if (!is_simple(q)
  201. && !is_simple(check_ifdef(q)))
  202. { debug("zpp: cannot handle #if %s\n", q);
  203. return 0;
  204. }
  205. printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
  206. return 1;
  207. }
  208. static int
  209. do_else(char *p)
  210. {
  211. debug("zpp: do_else %s", p);
  212. if_truth[if_depth] = 1-if_truth[if_depth];
  213. printing[if_depth] = printing[if_depth-1]&&if_truth[if_depth];
  214. return 1;
  215. }
  216. static int
  217. do_endif(char *p)
  218. {
  219. if (--if_depth < 0)
  220. { debug("zpp: unbalanced #endif %s\n", p);
  221. return 0;
  222. }
  223. return 1;
  224. }
  225. static int
  226. do_include(char *p)
  227. { char *r, *q;
  228. q = strchr(p, '<');
  229. r = strrchr(p, '>');
  230. if (!q || !r)
  231. { q = strchr (p, '\"');
  232. r = strrchr(p, '\"');
  233. if (!q || !r || q == r)
  234. { debug("zpp: malformed #include %s", p);
  235. return 0;
  236. } }
  237. *r = '\0';
  238. return zpp_do(++q);
  239. }
  240. static int
  241. in_comment(char *p)
  242. { char *q = p;
  243. for (q = p; *q != '\n' && *q != '\0'; q++)
  244. switch (state) {
  245. case PLAIN:
  246. switch (*q) {
  247. case '"': state = IN_STRING; break;
  248. case '\'': state = IN_QUOTE; break;
  249. case '/': state = S_COMM; break;
  250. case '\\': q++; break;
  251. }
  252. break;
  253. case IN_STRING:
  254. if (*q == '"') state = PLAIN;
  255. else if (*q == '\\') q++;
  256. break;
  257. case IN_QUOTE:
  258. if (*q == '\'') state = PLAIN;
  259. else if (*q == '\\') q++;
  260. break;
  261. case S_COMM:
  262. if (*q == '*')
  263. { *(q-1) = *q = ' ';
  264. state = COMMENT;
  265. } else if (*q != '/')
  266. state = PLAIN;
  267. break;
  268. case COMMENT:
  269. state = (*q == '*') ? E_COMM: COMMENT;
  270. *q = ' ';
  271. break;
  272. case E_COMM:
  273. if (*q == '/')
  274. state = PLAIN;
  275. else if (*q != '*')
  276. state = COMMENT;
  277. *q = ' ';
  278. break;
  279. }
  280. if (state == S_COMM) state = PLAIN;
  281. else if (state == E_COMM) state = COMMENT;
  282. return (state == COMMENT);
  283. }
  284. static int
  285. strip_cpp_comments(char *p)
  286. { char *q;
  287. q = strstr(p, "//");
  288. if (q)
  289. { if (q > p && *(q-1) == '\\')
  290. { return strip_cpp_comments(q+1);
  291. }
  292. *q = '\n';
  293. *(q+1) = '\0';
  294. return 1;
  295. }
  296. return 0;
  297. }
  298. static int
  299. zpp_do(char *fnm)
  300. { char buf[2048], buf2[MAXLINE], *p; int n, on;
  301. FILE *inp; int lno = 0, nw_lno = 0;
  302. if ((inp = fopen(fnm, "r")) == NULL)
  303. { fprintf(stdout, "spin: error: No file '%s'\n", fnm);
  304. exit(1); /* 4.1.2 was stderr */
  305. }
  306. printing[0] = if_truth[0] = 1;
  307. fprintf(outpp, "#line %d \"%s\"\n", lno+1, fnm);
  308. while (fgets(buf, MAXLINE, inp))
  309. { lno++; n = (int) strlen(buf);
  310. on = 0; nw_lno = 0;
  311. while (n > 2 && buf[n-2] == '\\')
  312. { buf[n-2] = '\0';
  313. feedme:
  314. if (!fgets(buf2, MAXLINE, inp))
  315. { debug("zpp: unexpected EOF ln %d\n", lno);
  316. return 0; /* switch to cpp */
  317. }
  318. lno++;
  319. if (n + (int) strlen(buf2) >= 2048)
  320. { debug("zpp: line %d too long\n", lno);
  321. return 0;
  322. }
  323. strcat(buf, buf2);
  324. n = (int) strlen(buf);
  325. }
  326. if (strip_cpp_comments(&buf[on]))
  327. n = (int) strlen(buf);
  328. if (in_comment(&buf[on]))
  329. { buf[n-1] = '\0'; /* eat newline */
  330. on = n-1; nw_lno = 1;
  331. goto feedme;
  332. }
  333. p = buf + strspn(buf, " \t");
  334. if (nw_lno && *p != '#')
  335. fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
  336. if (*p == '#')
  337. { if (!process(p+1, lno+1, fnm))
  338. return 0;
  339. } else if (printing[if_depth])
  340. fprintf(outpp, "%s", apply(buf));
  341. }
  342. fclose(inp);
  343. return 1;
  344. }
  345. int
  346. try_zpp(char *fnm, char *onm)
  347. { int r;
  348. if ((outpp = fopen(onm, MFLAGS)) == NULL)
  349. return 0;
  350. r = zpp_do(fnm);
  351. fclose(outpp);
  352. return r; /* 1 = ok; 0 = use cpp */
  353. }
  354. static struct Directives {
  355. int len;
  356. char *directive;
  357. int (*handler)(char *);
  358. int interp;
  359. } s[] = {
  360. { 6, "define", do_define, 1 },
  361. { 4, "else", do_else, 0 },
  362. { 5, "endif", do_endif, 0 },
  363. { 5, "ifdef", do_ifdef, 0 },
  364. { 6, "ifndef", do_ifndef, 0 },
  365. { 2, "if", do_if, 0 },
  366. { 7, "include", do_include, 1 },
  367. { 8, "undefine", do_undefine, 1 },
  368. };
  369. static int
  370. process(char *q, int lno, char *fnm)
  371. { char *p; int i, r;
  372. for (p = q; *p; p++)
  373. if (*p != ' ' && *p != '\t')
  374. break;
  375. if (strncmp(p, "line", 4) == 0)
  376. { p += 4;
  377. while (*p == ' ' || *p == '\t')
  378. { p++;
  379. }
  380. lno = atoi(p);
  381. return 1; /* line directive */
  382. }
  383. if (isdigit((int) *p))
  384. { lno = atoi(p);
  385. return 1;
  386. }
  387. if (strncmp(p, "error", 5) == 0)
  388. { printf("spin: %s", p);
  389. exit(1);
  390. }
  391. if (strncmp(p, "warning", 7) == 0)
  392. { printf("spin: %s", p);
  393. return 1;
  394. }
  395. for (i = 0; i < (int) (sizeof(s)/sizeof(struct Directives)); i++)
  396. if (!strncmp(s[i].directive, p, s[i].len))
  397. { if (s[i].interp
  398. && !printing[if_depth])
  399. return 1;
  400. fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
  401. r = s[i].handler(p + s[i].len);
  402. if (i == 6) /* include */
  403. fprintf(outpp, "#line %d \"%s\"\n", lno, fnm);
  404. return r;
  405. }
  406. debug("zpp: unrecognized directive: %s", p);
  407. return 0;
  408. }
  409. #endif