1 /*
2 * The contents of this file are subject to the Mozilla Public License
3 * Version 1.0 (the "License"); you may not use this file except in
4 * compliance with the License. You may obtain a copy of the License at
5 * http://www.mozilla.org/MPL/
6 *
7 * Software distributed under the License is distributed on an "AS IS"
8 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
9 * License for the specific language governing rights and limitations
10 * under the License.
11 *
12 * The Initial Developer of this code is David Baum.
13 * Portions created by David Baum are Copyright (C) 1998 David Baum.
14 * All Rights Reserved.
15 *
16 * Portions created by John Hansen are Copyright (C) 2005 John Hansen.
17 * All Rights Reserved.
18 *
19 */
20
21 /*
22 * PreProc reads tokens from the Lexer and emits a preprocessed token stream.
23 * The entire process is 'pulled' by calling PreProc::Get(), which in turn calls
24 * down through the layers of the Preprocessor:
25 *
26 * Get() - dispatches directives (DoInclude(), DoDefine(), etc)
27 * When processing a directive, GetRawToken() is called - in effect, macro
28 * substitution happens on playback, not record.
29 *
30 * GetReplacedToken() - matches ID tokens against macros, and pushes the macro
31 * definition when a macro is used. Use this call when macro calls should
32 * be expanded.
33 *
34 * GetRawToken() - maintains the queue of expansions, subsitutes arguments during
35 * expansion, manages the lexer (calls yylex(), maintains fNLRead, etc)
36 *
37 */
38
39 #include <cstring>
40 #include "PreProc.h"
41 #include "Symbol.h"
42 #include "Macro.h"
43 #include "Expansion.h"
44 #include "Program.h"
45 #include "Error.h"
46
47 // make sure we get an error if we try to use yylval
48 #define yylval
49
50 // values for argCount
51 #define kErrorArgs -2
52
53
54 PreProc *gPreProc = new PreProc();
55
56
PreProc()57 PreProc::PreProc()
58 {
59 fActive = fConditional.IsActive();
60 fEndOfFiles = false;
61 }
62
63
~PreProc()64 PreProc::~PreProc()
65 {
66 }
67
68
Get(TokenVal & v)69 int PreProc::Get(TokenVal &v)
70 {
71 int t;
72 long x;
73
74 // read token from lexer, and process any preprocessor commands;
75 while(1)
76 {
77 t = GetReplacedToken(v);
78
79 // strip newlines
80 if (t==NL) continue;
81
82 fNLRead = false;
83
84 // check for end
85 if (t==0)
86 {
87 if (!fConditional.IsTopLevel())
88 Error(kErr_UnterminatedIfdef).RaiseLex();
89 return 0;
90 }
91
92 // preprocessor commands
93 switch(t)
94 {
95 case PP_INCLUDE:
96 if (fActive)
97 DoInclude();
98 break;
99 case PP_DEFINE:
100 if (fActive)
101 DoDefine();
102 DiscardLine();
103 break;
104 case PP_IFDEF:
105 DoIfdef((bool)v.fInt);
106 fActive = fConditional.IsActive();
107 DiscardLine();
108 break;
109 case PP_IF:
110 fParser.Parse(x);
111 fConditional.If(x ? true : false);
112 fActive = fConditional.IsActive();
113 DiscardLine();
114 break;
115
116 case PP_ELIF:
117 fActive=true;
118 fParser.Parse(x);
119 if (!fConditional.Elif(x ? true : false))
120 Error(kErr_UnexpectedElse, "#elif").RaiseLex();
121 else
122 fActive = fConditional.IsActive();
123 DiscardLine();
124 break;
125
126 case PP_ELSE:
127 if (!fConditional.Else())
128 Error(kErr_UnexpectedElse, "#else").RaiseLex();
129 else
130 fActive = fConditional.IsActive();
131 DiscardLine();
132 break;
133 case PP_ENDIF:
134 if (!fConditional.Endif())
135 Error(kErr_UnexpectedElse, "#endif").RaiseLex();
136 else
137 fActive = fConditional.IsActive();
138 DiscardLine();
139 break;
140 case PP_UNDEF:
141 DoUndef();
142 DiscardLine();
143 break;
144 case PP_PRAGMA:
145 if (fActive)
146 {
147 if (!DoPragma())
148 Error(kWarn_IllegalPragma).RaiseLex();
149 }
150 DiscardLine();
151 break;
152 case PP_ERROR:
153 Error(kErr_ErrorDirective).RaiseLex();
154 DiscardLine();
155 break;
156 case PP_WARNING:
157 Error(kWarn_WarningDirective).RaiseLex();
158 DiscardLine();
159 break;
160 case PP_UNKNOWN:
161 if (fActive)
162 Error(kErr_UnknownDirective).RaiseLex();
163 DiscardLine();
164 break;
165 default:
166 if (fActive) return t;
167 break;
168 }
169 }
170 }
171
172
GetReplacedToken(TokenVal & v)173 int PreProc::GetReplacedToken(TokenVal &v)
174 {
175 int t;
176
177 while(1)
178 {
179 t = GetRawToken(v);
180
181 // macro substitution
182 if (t==ID && (v.fSymbol->IsDefined()) && fActive)
183 {
184 BeginExpansion(v.fSymbol);
185 }
186 else
187 return t;
188 }
189 }
190
191
192
GetRawToken(TokenVal & v)193 int PreProc::GetRawToken(TokenVal &v)
194 {
195 int t;
196
197 while(1)
198 {
199 Expansion *e = fExpList.GetHead();
200
201 if (e)
202 {
203 if (e->IsDone())
204 {
205 fExpList.RemoveHead();
206 delete e;
207 }
208 else
209 {
210 t = e->NextToken(v);
211 if (t == PP_ARG)
212 {
213 fExpList.InsertHead(new Expansion(e, v.fInt));
214 }
215 else
216 return t;
217 }
218 }
219 else
220 {
221 if (fEndOfFiles)
222 {
223 return 0;
224 }
225
226 t = yylex(v);
227
228 if (t==NL)
229 fNLRead = true;
230 else if (t==0)
231 fEndOfFiles = true;
232
233 return t;
234 }
235 }
236 }
237
238
DoInclude()239 bool PreProc::DoInclude()
240 {
241 TokenVal v;
242
243 int t = GetRawToken(v);
244 DiscardLine();
245
246 if (t != STRING)
247 {
248 Error(kErr_IncludeNeedsName).RaiseLex();
249 return false;
250 }
251
252 if (!LexFindAndPushFile(v.fString))
253 {
254 Error(kErr_FileOpen, v.fString);
255 return false;
256 }
257
258 return true;
259 }
260
261
DoDefine()262 bool PreProc::DoDefine()
263 {
264 Symbol *s;
265 TokenVal v;
266 int t;
267 int argCount;
268
269 t = GetRawToken(v);
270 if (t != ID)
271 {
272 Error(kErr_SymbolNameNeeded, "#define").RaiseLex();
273 return false;
274 }
275
276 s = v.fSymbol;
277 if (s->IsDefined())
278 {
279 Error(kErr_DefineRedef, s->GetKey()).RaiseLex();
280 return false;
281 }
282
283 argCount = ReadDefineArgs();
284 if (argCount == kErrorArgs) return false;
285
286 // hack to detect empty macro
287 if (fNLRead)
288 {
289 s->Define(new Macro(0, nil, -1));
290 return true;
291 }
292
293 ReadDefineBody();
294
295 s->Define(new Macro(&fTokenBuf[0], fTokenBuf.size(), argCount));
296 return true;
297 }
298
299
ReadDefineBody()300 void PreProc::ReadDefineBody()
301 {
302 int t;
303 TokenVal v;
304 int count = 0;
305 fTokenBuf.resize(0);
306 int argnum;
307
308 while(1)
309 {
310 t = GetRawToken(v);
311
312 switch(t)
313 {
314 case 0:
315 case NL:
316 return;
317 case ID:
318 argnum = MatchArg(v.fSymbol);
319 if (argnum != -1)
320 {
321 t = PP_ARG;
322 v.fInt = argnum;
323 }
324 break;
325
326 }
327
328 fTokenBuf.resize(count+1);
329 fTokenBuf[count].fType = t;
330 fTokenBuf[count].fValue = v;
331 count++;
332 }
333 }
334
335
MatchArg(const Symbol * s)336 int PreProc::MatchArg(const Symbol *s)
337 {
338 size_t i;
339
340 for(i=0; i<fArguments.size(); i++)
341 if (fArguments[i] == s) return i;
342
343 return -1;
344 }
345
346
ReadDefineArgs()347 int PreProc::ReadDefineArgs()
348 {
349 int t;
350 TokenVal v;
351
352 fArguments.resize(0);
353
354 // check for space or '('
355 LexReturnWhitespace(1);
356 t = GetRawToken(v);
357 LexReturnWhitespace(0);
358
359 switch(t)
360 {
361 case WS:
362 case NL:
363 return Macro::kNoArgs;
364 case '(':
365 break;
366 default:
367 Error(kErr_DefineArgs).RaiseLex();
368 return kErrorArgs;
369 }
370
371 while(1)
372 {
373 t = GetRawToken(v);
374
375 // check for empty arg list
376 if (t==')' && fArguments.size()==0) return 0;
377
378 if (t != ID)
379 {
380 if (t != NL) DiscardLine();
381 return kErrorArgs;
382 }
383
384 fArguments.push_back(v.fSymbol);
385
386 t = GetRawToken(v);
387 if (t == ')')
388 return fArguments.size();
389 else if (t != ',')
390 {
391 if (t != NL) DiscardLine();
392 return kErrorArgs;
393 }
394 }
395 }
396
397
BeginExpansion(Symbol * s)398 bool PreProc::BeginExpansion(Symbol *s)
399 {
400 Expansion *e;
401 Macro *def = s->GetDefinition();
402
403 if (def->IsMarked())
404 {
405 Error(kErr_CircularDef, s->GetKey()).RaiseLex();
406 return false;
407 }
408
409 e = new Expansion(def);
410
411 if (!ReadExpansionArgs(e))
412 {
413 delete e;
414 Error(kErr_WrongArgCount, s->GetKey()).RaiseLex();
415 return false;
416 }
417
418 fExpList.InsertHead(e);
419 return true;
420 }
421
422
ReadExpansionArgs(Expansion * e)423 bool PreProc::ReadExpansionArgs(Expansion *e)
424 {
425 int argCount = e->GetArgCount();
426 int t;
427 TokenVal v;
428
429 if (argCount == Macro::kNoArgs) return true;
430
431 t = GetRawToken(v);
432 if (t != '(') return false;
433
434 for(int i=0; i<argCount-1; i++)
435 if (!ReadExpansionArg(e, i, ',')) return false;
436
437 if (argCount == 0)
438 {
439 t = GetRawToken(v);
440 if (t != ')') return false;
441 }
442 else
443 if (!ReadExpansionArg(e, argCount-1, ')')) return false;
444
445 return true;
446 }
447
448
ReadExpansionArg(Expansion * e,int i,int delim)449 bool PreProc::ReadExpansionArg(Expansion *e, int i, int delim)
450 {
451 int nesting = 0;
452 int count = 0;
453 int t;
454 TokenVal v;
455
456 fTokenBuf.resize(0);
457
458 while(1)
459 {
460 t = GetRawToken(v);
461
462 switch(t)
463 {
464 case 0:
465 return false;
466 case '(':
467 nesting++;
468 break;
469 case ')':
470 if (nesting)
471 {
472 nesting--;
473 break;
474 }
475 // fall through
476 case ',':
477 if (nesting) break;
478 if (t != delim) return false;
479 e->SetArg(i, &fTokenBuf[0], fTokenBuf.size());
480 return true;
481 }
482
483 fTokenBuf.resize(count+1);
484 fTokenBuf[count].fType = t;
485 fTokenBuf[count].fValue = v;
486 count++;
487 }
488
489 }
490
491
DoIfdef(bool b)492 bool PreProc::DoIfdef(bool b)
493 {
494 TokenVal v;
495 int t;
496 bool defined;
497
498 t = GetRawToken(v);
499 if (t != ID)
500 {
501 Error(kErr_SymbolNameNeeded, "#ifdef / #ifndef").RaiseLex();
502 return false;
503 }
504
505 defined = v.fSymbol->IsDefined();
506 fConditional.If(b == defined);
507
508 return true;
509 }
510
511
DoUndef()512 bool PreProc::DoUndef()
513 {
514 TokenVal v;
515 int t;
516
517 t = GetRawToken(v);
518 if (t != ID)
519 {
520 Error(kErr_SymbolNameNeeded, "#undef").RaiseLex();
521 return false;
522 }
523
524 v.fSymbol->Undefine();
525 return true;
526 }
527
528
DoPragma()529 bool PreProc::DoPragma()
530 {
531 TokenVal v;
532
533 int t = GetRawToken(v);
534 if (t != ID) return false;
535
536 const char *pragma = v.fSymbol->GetKey();
537
538 if (strcmp(pragma, "noinit") == 0)
539 {
540 gProgram->SetInitName(0, 0);
541 return true;
542 }
543 else if (strcmp(pragma, "init") == 0)
544 {
545 t = GetRawToken(v);
546 if (t != ID) return false;
547 LexLocation loc;
548 LexCurrentLocation(loc);
549 gProgram->SetInitName(v.fSymbol, &loc);
550 return true;
551 }
552 else if (strcmp(pragma, "reserve") == 0)
553 {
554 int start, end;
555
556 t = GetRawToken(v);
557 if (t != NUMBER) return false;
558 start = v.fInt;
559
560 t = GetRawToken(v);
561 if (t == NUMBER)
562 end = v.fInt;
563 else if (t == NL)
564 end = start;
565 else
566 return false;
567
568 if (!gProgram->ReserveVars(start, end))
569 Error(kErr_CouldNotReserveVars).RaiseLex();
570
571 return true;
572 }
573
574 return false;
575 }
576
577
DiscardLine()578 void PreProc::DiscardLine()
579 {
580 TokenVal v;
581 int t;
582
583 if (fNLRead) return;
584
585 while((t=GetRawToken(v)) != 0)
586 {
587 if (t==NL) return;
588 }
589 }
590