pc_zpp.c 8.5 KB

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