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