Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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