1
2 #include <stdio.h>
3 #if __STDC__
4 #include <stdlib.h>
5 #include <locale.h>
6 #else
7 #include <malloc.h>
8 #endif
9 #include <ctype.h>
10 #include <string.h>
11 #include <time.h>
12
13 #include "cc.h"
14
15 #define MAXINCPATH 5
16
17 int main P((int argc, char ** argv));
18 void undefine_macro P((char * name));
19 void define_macro P((char * name));
20 void print_toks_cpp P((void));
21 void print_toks_raw P((void));
22 void define_macro P((char *));
23 void undefine_macro P((char *));
24 void cmsg P((char * mtype, char * str));
25 char * token_txn P((int));
26 void pr_indent P((int));
27 void hash_line P((void));
28
29 char * include_paths[MAXINCPATH];
30
31 char last_name[512] = "";
32 int last_line = -1;
33 int debug_mode = 0;
34 int p_flag = 0;
35 int exit_code = 0;
36
37 char * outfile = 0;
38 FILE * ofd = 0;
39
40 int
main(argc,argv)41 main(argc, argv)
42 int argc;
43 char ** argv;
44 {
45 int ar, i;
46 char * p;
47 static char Usage[] = "Usage: cpp -E -0 -Dxxx -Uxxx -Ixxx infile -o outfile";
48
49 #ifdef LC_CTYPE
50 setlocale(LC_CTYPE, "");
51 #endif
52
53 alltok = 1; /* Get all tokens from the cpp. */
54
55 for(ar=1; ar<argc; ar++) if( argv[ar][0] == '-') switch(argv[ar][1])
56 {
57 case 'd': debug_mode++; break;
58 case 'T': alltok = 0; break;
59 case 'A': dialect = DI_ANSI; break;
60 case 'K': dialect = DI_KNR; break;
61
62 /* Some options for describing the code generator. */
63 case '0': define_macro("__BCC__");
64 define_macro("__AS386_16__");
65 define_macro("__8086__");
66 break;
67 case '3': define_macro("__BCC__");
68 define_macro("__AS386_32__");
69 define_macro("__i386__");
70 break;
71 case 'c': define_macro("__CALLER_SAVES__");
72 break;
73 case 'f': define_macro("__FIRST_ARG_IN_AX__");
74 break;
75 case 'O': define_macro("__OPTIMISED__");
76 break;
77
78 case 'C': /* Keep comments. */
79 cwarn("-C not implemented");
80 break;
81 case 'P': p_flag++;
82 break;
83
84 case 'I':
85 if (argv[ar][2]) p=argv[ar]+2;
86 else {
87 ar++;
88 if (ar>=argc) cfatal(Usage);
89 p = argv[ar];
90 }
91 for(i=0; i<MAXINCPATH; i++)
92 if (!include_paths[i]) {
93 include_paths[i] = p;
94 break;
95 }
96 if (i>=MAXINCPATH)
97 cfatal("Too many items in include path for CPP");
98 break;
99 case 'D':
100 if (argv[ar][2]) p=argv[ar]+2;
101 else {
102 ar++;
103 if (ar>=argc) cfatal(Usage);
104 p = argv[ar];
105 }
106 define_macro(p);
107 break;
108 case 'U':
109 if (argv[ar][2]) p=argv[ar]+2;
110 else {
111 ar++;
112 if (ar>=argc) cfatal(Usage);
113 p = argv[ar];
114 }
115 undefine_macro(p);
116 break;
117 case 'o':
118 if (argv[ar][2]) p=argv[ar]+2;
119 else {
120 ar++;
121 if (ar>=argc) cfatal(Usage);
122 p = argv[ar];
123 }
124 if (outfile) cfatal(Usage);
125 outfile = p;
126 break;
127 default:
128 fprintf(stderr, "CPP Unknown option %s\n", argv[ar]);
129 cfatal(Usage);
130 } else if (!curfile) {
131 /* Input file */
132 curfile = fopen(argv[ar], "r");
133 c_fname = argv[ar]; c_lineno = 1;
134 if (!curfile)
135 cfatal("Cannot open input file");
136 } else
137 cfatal(Usage);
138
139 if (!curfile)
140 cfatal(Usage);
141
142 /* Define date and time macros. */
143 if (dialect != DI_KNR) {
144 time_t now;
145 char * timep;
146 char buf[128];
147 time(&now);
148 timep = ctime(&now);
149
150 /* Yes, well */
151 sprintf(buf, "__TIME__=\"%.8s\"", timep + 11);
152 define_macro(buf);
153 /* US order; Seems to be mandated by standard. */
154 sprintf(buf, "__DATE__=\"%.3s %.2s %.4s\"", timep + 4, timep + 8, timep + 20);
155 define_macro(buf);
156 }
157
158 if (outfile) ofd = fopen(outfile, "w");
159 else ofd = stdout;
160 if (!ofd)
161 cfatal("Cannot open output file");
162
163 if (debug_mode)
164 print_toks_raw();
165 else
166 print_toks_cpp();
167
168 if (outfile) fclose(ofd);
169 exit(exit_code);
170 }
171
172 void
undefine_macro(name)173 undefine_macro(name)
174 char * name;
175 {
176 struct define_item * ptr;
177
178 ptr = read_entry(0, name);
179 if (ptr) {
180 set_entry(0, name, (void*)0);
181 if (!ptr->in_use) free(ptr);
182 }
183 }
184
185 void
define_macro(name)186 define_macro(name)
187 char * name;
188 {
189 char * p;
190 char * value;
191 struct define_item * ptr;
192
193 if ((p=strchr(name, '=')) != 0) {
194 *p = 0;
195 value = p+1;
196 } else
197 value = "1";
198
199 undefine_macro(name);
200
201 ptr = malloc(sizeof(struct define_item) + strlen(value));
202 ptr->name = set_entry(0, name, ptr);
203 strcpy(ptr->value, value);
204 ptr->arg_count = -1;
205 ptr->in_use = 0;
206 ptr->next = 0;
207 }
208
209 FILE *
open_include(fname,mode,checkrel)210 open_include(fname, mode, checkrel)
211 char * fname;
212 char * mode;
213 int checkrel;
214 {
215 FILE * fd = 0;
216 int i;
217 char buf[256], *p;
218
219 if( checkrel )
220 {
221 strcpy(buf, c_fname);
222 p = strrchr(buf, '/');
223 if (p) *++p = 0; else *(p=buf) = 0;
224 strcpy(p, fname);
225
226 fd=fopen(buf, mode);
227 }
228 if (!fd) {
229 for(i=0; i<MAXINCPATH; i++)
230 if (include_paths[i]) {
231 strcpy(buf, include_paths[i]);
232 if (buf[strlen(buf)-1] != '/') strcat(buf, "/");
233 strcat(buf, fname);
234 fd=fopen(buf, mode);
235 if( fd ) break;
236 }
237 }
238 if (!fd) return fd;
239 c_fname = strdup(buf);
240 c_lineno = 1;
241
242 return fd;
243 }
244
245 /*----------------------------------------------------------------------*/
246
247 static int outpos = 0;
248
249 void
cmsg(mtype,str)250 cmsg(mtype, str)
251 char * mtype;
252 char * str;
253 {
254 if (c_fname && (*c_fname || c_lineno))
255 fprintf(stderr, "%s:%d: ", c_fname, c_lineno);
256
257 if (mtype && *mtype)
258 fprintf(stderr, "%s: %s\n", mtype, str);
259 else
260 fprintf(stderr, "%s\n", str);
261 }
262
263 void
cfatal(str)264 cfatal(str)
265 char * str;
266 {
267 cmsg("CPP-FATAL error", str);
268 exit(255);
269 }
270
271 void
cerror(str)272 cerror(str)
273 char * str;
274 {
275 exit_code = 1;
276 cmsg("error", str);
277 }
278
279 void
cwarn(str)280 cwarn(str)
281 char * str;
282 {
283 cmsg("warning", str);
284 }
285
286 void
pr_indent(count)287 pr_indent(count)
288 int count;
289 {
290 if(count>10) count=10;
291 while(count>0) {fprintf(ofd, "\t"); count--; }
292 }
293
294 void
hash_line()295 hash_line()
296 {
297 if( strcmp(last_name, c_fname) != 0 ) last_line = -1;
298 if( c_lineno != last_line || last_line <= 0 )
299 {
300 if( outpos != 0 ) {
301 fputc('\n', ofd); outpos=0;
302 if (last_line > 0) last_line++;
303 }
304 while( c_lineno > last_line &&
305 (p_flag || c_lineno < last_line+4) &&
306 last_line > 0 &&
307 !debug_mode )
308 {
309 fputc('\n', ofd); last_line++;
310 }
311
312 if( !p_flag && (c_lineno != last_line || last_line <= 0 ))
313 {
314 fprintf(ofd, "# %d", c_lineno);
315 if( last_line <= 0 ) fprintf(ofd, " \"%s\"", c_fname);
316 fprintf(ofd, "\n");
317 }
318
319 strcpy(last_name, c_fname);
320 last_line = c_lineno;
321 }
322 }
323
324 void
print_toks_cpp()325 print_toks_cpp()
326 {
327 int i;
328 int indent=0;
329 int paren=0;
330
331 hash_line();
332 while( (i=gettok()) != EOF )
333 {
334 hash_line();
335 switch(i)
336 {
337 case '\n':
338 cwarn("newline received from tokeniser!");
339 break;
340
341 case TK_STR:
342 outpos += fprintf(ofd, "%s", curword);
343 break;
344
345 case TK_COPY:
346 if( outpos ) { fputc('\n', ofd); last_line++; }
347 outpos = 0; last_line++;
348 fprintf(ofd, "#%s\n", curword);
349 break;
350
351 case TK_FILE: sprintf(curword, "\"%s\"", c_fname); if(0) {
352 case TK_LINE: sprintf(curword, "%d", c_lineno);
353 }
354 /*FALLTHROUGH*/
355 default:
356 if (!alltok) {
357 if(i == '}' || i == TK_CASE || i == TK_DEFAULT ) indent--;
358 if(i ==')') paren--;
359
360 if(outpos) { fputc(' ', ofd); outpos++; }
361 else pr_indent(indent+(paren!=0));
362
363 if(i == '{' || i == TK_CASE || i == TK_DEFAULT ) indent++;
364 if(i ==';') paren=0;
365 if(i =='(') paren++;
366 }
367
368 outpos += fprintf(ofd, "%s", curword);
369
370 if ( i == '"' || i == '\'' )
371 {
372 while((i=gettok()) == TK_STR) {
373 outpos += fprintf(ofd, "%s", curword);
374 }
375 if (i != '\n')
376 outpos += fprintf(ofd, "%s", curword);
377 }
378 break;
379 }
380 }
381 if( outpos ) fputc('\n', ofd);
382 outpos = 0;
383 }
384
385 void
print_toks_raw()386 print_toks_raw()
387 {
388 int i;
389 long val;
390
391 hash_line();
392 while( (i=gettok()) != EOF )
393 {
394 hash_line();
395 switch(i)
396 {
397 case '"': case '\'':
398 if (debug_mode < 2) {
399 fprintf(ofd, "%-16s: %s", "Quoted string", curword);
400 while((i=gettok()) == TK_STR)
401 outpos+= fprintf(ofd, "%s", curword);
402 if ( i == '\n' ) fprintf(ofd, " --> EOL!!\n");
403 else outpos+= fprintf(ofd, "%s\n", curword);
404 break;
405 }
406 /*FALLTHROUGH*/
407 default: fprintf(ofd, "%-16s: '", token_txn(i));
408 {
409 char *p;
410 for(p=curword; *p; p++)
411 if(isprint(*p) && *p != '\'' && *p != '\\')
412 fputc(*p, ofd);
413 else if (*p == '\n') fprintf(ofd, "\\n");
414 else if (*p == '\t') fprintf(ofd, "\\t");
415 else if (*p == '\v') fprintf(ofd, "\\v");
416 else if (*p == '\b') fprintf(ofd, "\\b");
417 else if (*p == '\r') fprintf(ofd, "\\r");
418 else if (*p == '\f') fprintf(ofd, "\\f");
419 else if (*p == '\a') fprintf(ofd, "\\a");
420 else
421 fprintf(ofd, "\\x%02x", (unsigned char)*p);
422 }
423 fprintf(ofd, "'\n");
424 break;
425 case TK_NUM:
426 val = strtoul(curword, (void*)0, 0);
427 fprintf(ofd, "%-16s: ", token_txn(i));
428 fprintf(ofd, "%s => %ld\n", curword, val);
429 break;
430 case TK_COPY:
431 fprintf(ofd, "%-16s: ", token_txn(i));
432 fprintf(ofd, "#%s\n", curword);
433 break;
434 case '\n':
435 fprintf(ofd, "%-16s:\n", "Newline char");
436 break;
437 }
438 }
439 }
440
441 char *
token_txn(token)442 token_txn(token)
443 int token;
444 {
445 char * s = "UNKNOWN";
446 static char buf[17];
447
448 if (token> ' ' && token <= '~')
449 {
450 sprintf(buf, "TK_CHAR('%c')", token);
451 return buf;
452 }
453 if (token >= 0 && token < 0x100)
454 {
455 sprintf(buf, "TK_CHAR(%d)", token);
456 return buf;
457 }
458
459 switch(token)
460 {
461 case TK_WSPACE : s="TK_WSPACE"; break;
462 case TK_WORD : s="TK_WORD"; break;
463 case TK_NUM : s="TK_NUM"; break;
464 case TK_FLT : s="TK_FLT"; break;
465 case TK_QUOT : s="TK_QUOT"; break;
466 case TK_STR : s="TK_STR"; break;
467 case TK_FILE : s="TK_FILE"; break;
468 case TK_LINE : s="TK_LINE"; break;
469 case TK_COPY : s="TK_COPY"; break;
470 case TK_NE_OP : s="TK_NE_OP"; break;
471 case TK_MOD_ASSIGN : s="TK_MOD_ASSIGN"; break;
472 case TK_AND_OP : s="TK_AND_OP"; break;
473 case TK_AND_ASSIGN : s="TK_AND_ASSIGN"; break;
474 case TK_MUL_ASSIGN : s="TK_MUL_ASSIGN"; break;
475 case TK_INC_OP : s="TK_INC_OP"; break;
476 case TK_ADD_ASSIGN : s="TK_ADD_ASSIGN"; break;
477 case TK_DEC_OP : s="TK_DEC_OP"; break;
478 case TK_SUB_ASSIGN : s="TK_SUB_ASSIGN"; break;
479 case TK_PTR_OP : s="TK_PTR_OP"; break;
480 case TK_ELLIPSIS : s="TK_ELLIPSIS"; break;
481 case TK_DIV_ASSIGN : s="TK_DIV_ASSIGN"; break;
482 case TK_LEFT_OP : s="TK_LEFT_OP"; break;
483 case TK_LEFT_ASSIGN : s="TK_LEFT_ASSIGN"; break;
484 case TK_LE_OP : s="TK_LE_OP"; break;
485 case TK_EQ_OP : s="TK_EQ_OP"; break;
486 case TK_GE_OP : s="TK_GE_OP"; break;
487 case TK_RIGHT_OP : s="TK_RIGHT_OP"; break;
488 case TK_RIGHT_ASSIGN : s="TK_RIGHT_ASSIGN"; break;
489 case TK_XOR_ASSIGN : s="TK_XOR_ASSIGN"; break;
490 case TK_OR_ASSIGN : s="TK_OR_ASSIGN"; break;
491 case TK_OR_OP : s="TK_OR_OP"; break;
492 case TK_AUTO : s="TK_AUTO"; break;
493 case TK_BREAK : s="TK_BREAK"; break;
494 case TK_CASE : s="TK_CASE"; break;
495 case TK_CHAR : s="TK_CHAR"; break;
496 case TK_CONST : s="TK_CONST"; break;
497 case TK_CONTINUE : s="TK_CONTINUE"; break;
498 case TK_DEFAULT : s="TK_DEFAULT"; break;
499 case TK_DO : s="TK_DO"; break;
500 case TK_DOUBLE : s="TK_DOUBLE"; break;
501 case TK_ELSE : s="TK_ELSE"; break;
502 case TK_ENUM : s="TK_ENUM"; break;
503 case TK_EXTERN : s="TK_EXTERN"; break;
504 case TK_FLOAT : s="TK_FLOAT"; break;
505 case TK_FOR : s="TK_FOR"; break;
506 case TK_GOTO : s="TK_GOTO"; break;
507 case TK_IF : s="TK_IF"; break;
508 case TK_INT : s="TK_INT"; break;
509 case TK_LONG : s="TK_LONG"; break;
510 case TK_REGISTER : s="TK_REGISTER"; break;
511 case TK_RETURN : s="TK_RETURN"; break;
512 case TK_SHORT : s="TK_SHORT"; break;
513 case TK_SIGNED : s="TK_SIGNED"; break;
514 case TK_SIZEOF : s="TK_SIZEOF"; break;
515 case TK_STATIC : s="TK_STATIC"; break;
516 case TK_STRUCT : s="TK_STRUCT"; break;
517 case TK_SWITCH : s="TK_SWITCH"; break;
518 case TK_TYPEDEF : s="TK_TYPEDEF"; break;
519 case TK_UNION : s="TK_UNION"; break;
520 case TK_UNSIGNED : s="TK_UNSIGNED"; break;
521 case TK_VOID : s="TK_VOID"; break;
522 case TK_VOLATILE : s="TK_VOLATILE"; break;
523 case TK_WHILE : s="TK_WHILE"; break;
524 }
525 return s;
526 }
527