pc_zpp.c 8.1 KB

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