1 /****************************************************************************
2 *
3 * This code is Public Domain.
4 *
5 * ========================================================================
6 *
7 * Description: preprocessor
8 *
9 ****************************************************************************/
10
11 #include <ctype.h>
12 #include <stdarg.h>
13
14 #include "globals.h"
15 #include "memalloc.h"
16 #include "parser.h"
17 #include "condasm.h"
18 #include "tokenize.h"
19 #include "equate.h"
20 #include "macro.h"
21 #include "input.h"
22 #include "fastpass.h"
23 #include "listing.h"
24
25 #define REMOVECOMENT 0 /* 1=remove comments from source */
26
27 extern ret_code (* const directive_tab[])( int, struct asm_tok[] );
28
29 #ifdef DEBUG_OUT
30 int_32 cntppl0; /* count preprocessed lines 1 */
31 int_32 cntppl1; /* count preprocessed lines 2 */
32 int_32 cntppl2; /* count lines NOT handled by preprocessor */
33 #endif
34
35 /* preprocessor directive or macro procedure is preceded
36 * by a code label.
37 */
WriteCodeLabel(char * line,struct asm_tok tokenarray[])38 ret_code WriteCodeLabel( char *line, struct asm_tok tokenarray[] )
39 /****************************************************************/
40 {
41 int oldcnt;
42 int oldtoken;
43 char oldchar;
44
45 if ( tokenarray[0].token != T_ID ) {
46 return( EmitErr( SYNTAX_ERROR_EX, tokenarray[0].string_ptr ) );
47 }
48 /* ensure the listing is written with the FULL source line */
49 if ( CurrFile[LST] ) LstWrite( LSTTYPE_LABEL, 0, NULL );
50 /* v2.04: call ParseLine() to parse the "label" part of the line */
51 oldcnt = Token_Count;
52 oldtoken = tokenarray[2].token;
53 oldchar = *tokenarray[2].tokpos;
54 Token_Count = 2;
55 tokenarray[2].token = T_FINAL;
56 *tokenarray[2].tokpos = NULLC;
57 ParseLine( tokenarray );
58 if ( Options.preprocessor_stdout == TRUE )
59 WritePreprocessedLine( line );
60 Token_Count = oldcnt;
61 tokenarray[2].token = oldtoken;
62 *tokenarray[2].tokpos = oldchar;
63 return( NOT_ERROR );
64 }
65
66 /* PreprocessLine() is the "preprocessor".
67 * 1. the line is tokenized with Tokenize(), Token_Count set
68 * 2. (text) macros are expanded by ExpandLine()
69 * 3. "preprocessor" directives are executed
70 */
PreprocessLine(char * line,struct asm_tok tokenarray[])71 int PreprocessLine( char *line, struct asm_tok tokenarray[] )
72 /***********************************************************/
73 {
74 int i;
75
76 /* v2.11: GetTextLine() removed - this is now done in ProcessFile() */
77
78 /* v2.08: moved here from GetTextLine() */
79 ModuleInfo.CurrComment = NULL;
80 /* v2.06: moved here from Tokenize() */
81 ModuleInfo.line_flags = 0;
82 /* Token_Count is the number of tokens scanned */
83 Token_Count = Tokenize( line, 0, tokenarray, TOK_DEFAULT );
84
85 #ifdef DEBUG_OUT
86 cntppl0++;
87 if ( ModuleInfo.GeneratedCode )
88 DebugMsg1(("PreprocessLine: >%s<\n", line ));
89 else
90 DebugMsg1(("PreprocessLine(%s): >%s< cmt=%s\n", GetTopSrcName(), line, ModuleInfo.CurrComment ? ModuleInfo.CurrComment : "" ));
91 #endif
92
93 #if REMOVECOMENT == 0
94 if ( Token_Count == 0 && ( CurrIfState == BLOCK_ACTIVE || ModuleInfo.listif ) )
95 LstWriteSrcLine();
96 #endif
97
98 if ( Token_Count == 0 )
99 return( 0 );
100
101 #ifdef DEBUG_OUT
102 /* option -np, skip preprocessor? */
103 if ( Options.skip_preprocessor )
104 return( Token_Count );
105 #endif
106
107 /* CurrIfState != BLOCK_ACTIVE && Token_Count == 1 | 3 may happen
108 * if a conditional assembly directive has been detected by Tokenize().
109 * However, it's important NOT to expand then */
110 if ( CurrIfState == BLOCK_ACTIVE ) {
111 if ( ( tokenarray[Token_Count].bytval & TF3_EXPANSION ? ExpandText( line, tokenarray, TRUE ) : ExpandLine( line, tokenarray ) ) < NOT_ERROR )
112 return( 0 );
113 }
114
115 DebugCmd( cntppl1++ );
116
117 i = 0;
118 if ( Token_Count > 2 && ( tokenarray[1].token == T_COLON || tokenarray[1].token == T_DBL_COLON ) )
119 i = 2;
120
121 /* handle "preprocessor" directives:
122 * IF, ELSE, ENDIF, ...
123 * FOR, REPEAT, WHILE, ...
124 * PURGE
125 * INCLUDE
126 * since v2.05, error directives are no longer handled here!
127 */
128 if ( tokenarray[i].token == T_DIRECTIVE &&
129 tokenarray[i].dirtype <= DRT_INCLUDE ) {
130
131 /* if i != 0, then a code label is located before the directive */
132 if ( i > 1 ) {
133 if ( ERROR == WriteCodeLabel( line, tokenarray ) )
134 return( 0 );
135 }
136 directive_tab[tokenarray[i].dirtype]( i, tokenarray );
137 return( 0 );
138 }
139
140 /* handle preprocessor directives which need a label */
141
142 if ( tokenarray[0].token == T_ID && tokenarray[1].token == T_DIRECTIVE ) {
143 struct asym *sym;
144 switch ( tokenarray[1].dirtype ) {
145 case DRT_EQU:
146 /*
147 * EQU is a special case:
148 * If an EQU directive defines a text equate
149 * it MUST be handled HERE and 0 must be returned to the caller.
150 * This will prevent further processing, nothing will be stored
151 * if FASTPASS is on.
152 * Since one cannot decide whether EQU defines a text equate or
153 * a number before it has scanned its argument, we'll have to
154 * handle it in ANY case and if it defines a number, the line
155 * must be stored and, if -EP is set, written to stdout.
156 */
157 if ( sym = CreateConstant( tokenarray ) ) {
158 if ( sym->state != SYM_TMACRO ) {
159 #if FASTPASS
160 if ( StoreState ) FStoreLine( 0 );
161 #endif
162 if ( Options.preprocessor_stdout == TRUE )
163 WritePreprocessedLine( line );
164 }
165 /* v2.03: LstWrite() must be called AFTER StoreLine()! */
166 if ( ModuleInfo.list == TRUE ) {
167 LstWrite( sym->state == SYM_INTERNAL ? LSTTYPE_EQUATE : LSTTYPE_TMACRO, 0, sym );
168 }
169 }
170 return( 0 );
171 case DRT_MACRO:
172 case DRT_CATSTR: /* CATSTR + TEXTEQU directives */
173 case DRT_SUBSTR:
174 directive_tab[tokenarray[1].dirtype]( 1, tokenarray );
175 return( 0 );
176 }
177 }
178
179 DebugCmd( cntppl2++ );
180 return( Token_Count );
181 }
182
183