1
2 %token_prefix XLAT_
3 %token_type {FParseToken}
4 %token_destructor {} // just to avoid a compiler warning
5 %name XlatParse
6 %extra_argument { FParseContext *context }
7 %syntax_error { context->PrintError("syntax error");}
8
9
10 main ::= translation_unit.
11
12 translation_unit ::= . /* empty */
13 translation_unit ::= translation_unit external_declaration.
14
15 external_declaration ::= define_statement.
16 external_declaration ::= enum_statement.
17 external_declaration ::= linetype_declaration.
18 external_declaration ::= boom_declaration.
19 external_declaration ::= sector_declaration.
20 external_declaration ::= lineflag_declaration.
21 external_declaration ::= sector_bitmask.
22 external_declaration ::= maxlinespecial_def.
23 external_declaration ::= NOP.
24
25
26 %left OR.
27 %left XOR.
28 %left AND.
29 %left MINUS PLUS.
30 %left MULTIPLY DIVIDE MODULUS.
31 %left NEG.
32
33 %type exp {int}
exp(A)34 exp(A) ::= NUM(B). { A = B.val; }
exp(A)35 exp(A) ::= exp(B) PLUS exp(C). { A = B + C; }
exp(A)36 exp(A) ::= exp(B) MINUS exp(C). { A = B - C; }
exp(A)37 exp(A) ::= exp(B) MULTIPLY exp(C). { A = B * C; }
exp(A)38 exp(A) ::= exp(B) DIVIDE exp(C). { if (C != 0) A = B / C; else context->PrintError("Division by zero"); }
exp(A)39 exp(A) ::= exp(B) MODULUS exp(C). { if (C != 0) A = B % C; else context->PrintError("Division by zero"); }
exp(A)40 exp(A) ::= exp(B) OR exp(C). { A = B | C; }
exp(A)41 exp(A) ::= exp(B) AND exp(C). { A = B & C; }
exp(A)42 exp(A) ::= exp(B) XOR exp(C). { A = B ^ C; }
exp(A)43 exp(A) ::= MINUS exp(B). [NEG] { A = -B; }
exp(A)44 exp(A) ::= LPAREN exp(B) RPAREN. { A = B; }
45
46
47 //==========================================================================
48 //
49 // define
50 //
51 //==========================================================================
52
SYM(A)53 define_statement ::= DEFINE SYM(A) LPAREN exp(B) RPAREN.
54 {
55 context->AddSym (A.sym, B);
56 }
57
58 //==========================================================================
59 //
60 // enum
61 //
62 //==========================================================================
63
64 enum_statement ::= enum_open enum_list RBRACE.
65
66 enum_open ::= ENUM LBRACE.
67 {
68 context->EnumVal = 0;
69 }
70
71 enum_list ::= . /* empty */
72 enum_list ::= single_enum.
73 enum_list ::= enum_list COMMA single_enum.
74
SYM(A)75 single_enum ::= SYM(A).
76 {
77 context->AddSym (A.sym, context->EnumVal++);
78 }
79
SYM(A)80 single_enum ::= SYM(A) EQUALS exp(B).
81 {
82 context->AddSym (A.sym, B);
83 context->EnumVal = B+1;
84 }
85
86 //==========================================================================
87 //
88 // standard linetype
89 //
90 //==========================================================================
91
92 %type linetype_exp {int}
linetype_exp(Z)93 linetype_exp(Z) ::= exp(A).
94 {
95 Z = static_cast<XlatParseContext *>(context)->DefiningLineType = A;
96 }
97
linetype_exp(linetype)98 linetype_declaration ::= linetype_exp(linetype) EQUALS exp(flags) COMMA exp(special) LPAREN special_args(arg) RPAREN.
99 {
100 SimpleLineTranslations.SetVal(linetype,
101 FLineTrans(special&0xffff, flags+arg.addflags, arg.args[0], arg.args[1], arg.args[2], arg.args[3], arg.args[4]));
102 static_cast<XlatParseContext *>(context)->DefiningLineType = -1;
103 }
104
SYM(S)105 linetype_declaration ::= linetype_exp EQUALS exp COMMA SYM(S) LPAREN special_args RPAREN.
106 {
107 Printf ("%s, line %d: %s is undefined\n", context->SourceFile, context->SourceLine, S.sym);
108 static_cast<XlatParseContext *>(context)->DefiningLineType = -1;
109 }
110
111 %type exp_with_tag {int}
exp_with_tag(A)112 exp_with_tag(A) ::= NUM(B). { XlatExpressions.Push(B.val); A = XlatExpressions.Push(XEXP_Const); }
exp_with_tag(A)113 exp_with_tag(A) ::= TAG. { A = XlatExpressions.Push(XEXP_Tag); }
exp_with_tag(A)114 exp_with_tag(A) ::= exp_with_tag PLUS exp_with_tag. { A = XlatExpressions.Push(XEXP_Add); }
exp_with_tag(A)115 exp_with_tag(A) ::= exp_with_tag MINUS exp_with_tag. { A = XlatExpressions.Push(XEXP_Sub); }
exp_with_tag(A)116 exp_with_tag(A) ::= exp_with_tag MULTIPLY exp_with_tag. { A = XlatExpressions.Push(XEXP_Mul); }
exp_with_tag(A)117 exp_with_tag(A) ::= exp_with_tag DIVIDE exp_with_tag. { A = XlatExpressions.Push(XEXP_Div); }
exp_with_tag(A)118 exp_with_tag(A) ::= exp_with_tag MODULUS exp_with_tag. { A = XlatExpressions.Push(XEXP_Mod); }
exp_with_tag(A)119 exp_with_tag(A) ::= exp_with_tag OR exp_with_tag. { A = XlatExpressions.Push(XEXP_Or); }
exp_with_tag(A)120 exp_with_tag(A) ::= exp_with_tag AND exp_with_tag. { A = XlatExpressions.Push(XEXP_And); }
exp_with_tag(A)121 exp_with_tag(A) ::= exp_with_tag XOR exp_with_tag. { A = XlatExpressions.Push(XEXP_Xor); }
exp_with_tag(A)122 exp_with_tag(A) ::= MINUS exp_with_tag. [NEG] { A = XlatExpressions.Push(XEXP_Neg); }
exp_with_tag(A)123 exp_with_tag(A) ::= LPAREN exp_with_tag(B) RPAREN. { A = B; }
124
125
126 %type special_arg {SpecialArg}
127
special_arg(Z)128 special_arg(Z) ::= exp_with_tag(A).
129 {
130 if (XlatExpressions[A] == XEXP_Tag)
131 { // Store tags directly
132 Z.arg = 0;
133 Z.argop = ARGOP_Tag;
134 XlatExpressions.Delete(A);
135 }
136 else
137 { // Try and evaluate it. If it's a constant, store it and erase the
138 // expression. Otherwise, store the index to the expression. We make
139 // no attempt to simplify non-constant expressions.
140 FXlatExprState state;
141 int val;
142 const int *endpt;
143 int *xnode;
144
145 state.linetype = static_cast<XlatParseContext *>(context)->DefiningLineType;
146 state.tag = 0;
147 state.bIsConstant = true;
148 xnode = &XlatExpressions[A];
149 endpt = XlatExprEval[*xnode](&val, xnode, &state);
150 if (state.bIsConstant)
151 {
152 Z.arg = val;
153 Z.argop = ARGOP_Const;
154 endpt++;
155 assert(endpt >= &XlatExpressions[0]);
156 XlatExpressions.Resize((unsigned)(endpt - &XlatExpressions[0]));
157 }
158 else
159 {
160 Z.arg = A;
161 Z.argop = ARGOP_Expr;
162 }
163 }
164 }
165
166 %type multi_special_arg {SpecialArgs}
167
multi_special_arg(Z)168 multi_special_arg(Z) ::= special_arg(A).
169 {
170 Z.addflags = A.argop << LINETRANS_TAGSHIFT;
171 Z.argcount = 1;
172 Z.args[0] = A.arg;
173 Z.args[1] = 0;
174 Z.args[2] = 0;
175 Z.args[3] = 0;
176 Z.args[4] = 0;
177 }
multi_special_arg(Z)178 multi_special_arg(Z) ::= multi_special_arg(A) COMMA special_arg(B).
179 {
180 Z = A;
181 if (Z.argcount < LINETRANS_MAXARGS)
182 {
183 Z.addflags |= B.argop << (LINETRANS_TAGSHIFT + Z.argcount * TAGOP_NUMBITS);
184 Z.args[Z.argcount] = B.arg;
185 Z.argcount++;
186 }
187 else if (Z.argcount++ == LINETRANS_MAXARGS)
188 {
189 context->PrintError("Line special has too many arguments\n");
190 }
191 }
192
193 %type special_args {SpecialArgs}
194
special_args(Z)195 special_args(Z) ::= . /* empty */
196 {
197 Z.addflags = 0;
198 Z.argcount = 0;
199 Z.args[0] = 0;
200 Z.args[1] = 0;
201 Z.args[2] = 0;
202 Z.args[3] = 0;
203 Z.args[4] = 0;
204 }
special_args(Z)205 special_args(Z) ::= multi_special_arg(A).
206 {
207 Z = A;
208 }
209
210 //==========================================================================
211 //
212 // boom generalized linetypes
213 //
214 //==========================================================================
215
216 %type list_val {ListFilter}
217 %type arg_list {MoreFilters *}
218 %type boom_args {ParseBoomArg}
219 %type boom_op {int}
220 %type boom_selector {int}
221 %type boom_line {FBoomArg}
222 %type boom_body {MoreLines *}
223
224
exp(special)225 boom_declaration ::= LBRACKET exp(special) RBRACKET LPAREN exp(firsttype) COMMA exp(lasttype) RPAREN LBRACE boom_body(stores) RBRACE.
226 {
227 int i;
228 MoreLines *probe;
229
230 if (NumBoomish == MAX_BOOMISH)
231 {
232 MoreLines *probe = stores;
233
234 while (probe != NULL)
235 {
236 MoreLines *next = probe->next;
237 delete probe;
238 probe = next;
239 }
240 Printf ("%s, line %d: Too many BOOM translators\n", context->SourceFile, context->SourceLine);
241 }
242 else
243 {
244 Boomish[NumBoomish].FirstLinetype = firsttype;
245 Boomish[NumBoomish].LastLinetype = lasttype;
246 Boomish[NumBoomish].NewSpecial = special;
247
248 for (i = 0, probe = stores; probe != NULL; i++)
249 {
250 MoreLines *next = probe->next;
251 Boomish[NumBoomish].Args.Push(probe->arg);
252 delete probe;
253 probe = next;
254 }
255 NumBoomish++;
256 }
257 }
258
boom_body(A)259 boom_body(A) ::= . /* empty */
260 {
261 A = NULL;
262 }
boom_body(A)263 boom_body(A) ::= boom_line(B) boom_body(C).
264 {
265 A = new MoreLines;
266 A->next = C;
267 A->arg = B;
268 }
269
boom_line(A)270 boom_line(A) ::= boom_selector(sel) boom_op(op) boom_args(args).
271 {
272 A.bOrExisting = (op == OR_EQUAL);
273 A.bUseConstant = (args.filters == NULL);
274 A.ArgNum = sel;
275 A.ConstantValue = args.constant;
276 A.AndValue = args.mask;
277
278 if (args.filters != NULL)
279 {
280 int i;
281 MoreFilters *probe;
282
283 for (i = 0, probe = args.filters; probe != NULL; i++)
284 {
285 MoreFilters *next = probe->next;
286 if (i < 15)
287 {
288 A.ResultFilter[i] = probe->filter.filter;
289 A.ResultValue[i] = probe->filter.value;
290 }
291 else if (i == 15)
292 {
293 context->PrintError ("Lists can only have 15 elements");
294 }
295 delete probe;
296 probe = next;
297 }
298 A.ListSize = i > 15 ? 15 : i;
299 }
300 }
301
boom_selector(A)302 boom_selector(A) ::= FLAGS. { A = 4; }
boom_selector(A)303 boom_selector(A) ::= ARG2. { A = 0; }
boom_selector(A)304 boom_selector(A) ::= ARG3. { A = 1; }
boom_selector(A)305 boom_selector(A) ::= ARG4. { A = 2; }
boom_selector(A)306 boom_selector(A) ::= ARG5. { A = 3; }
307
boom_op(A)308 boom_op(A) ::= EQUALS. { A = '='; }
boom_op(A)309 boom_op(A) ::= OR_EQUAL. { A = OR_EQUAL; }
310
boom_args(A)311 boom_args(A) ::= exp(B).
312 {
313 A.constant = B;
314 A.filters = NULL;
315 }
boom_args(A)316 boom_args(A) ::= exp(B) LBRACKET arg_list(C) RBRACKET.
317 {
318 A.mask = B;
319 A.filters = C;
320 }
321
arg_list(A)322 arg_list(A) ::= list_val(B).
323 {
324 A = new MoreFilters;
325 A->next = NULL;
326 A->filter = B;
327 }
arg_list(A)328 arg_list(A) ::= list_val(B) COMMA arg_list(C).
329 {
330 A = new MoreFilters;
331 A->next = C;
332 A->filter = B;
333 }
334
list_val(A)335 list_val(A) ::= exp(B) COLON exp(C).
336 {
337 A.filter = B;
338 A.value = C;
339 }
340
341 //==========================================================================
342 //
343 // max line special
344 //
345 //==========================================================================
346
exp(mx)347 maxlinespecial_def ::= MAXLINESPECIAL EQUALS exp(mx) SEMICOLON.
348 {
349 // Just kill all specials higher than the max.
350 // If the translator wants to redefine some later, just let it.
351 SimpleLineTranslations.Resize(mx+1);
352 }
353
354 //==========================================================================
355 //
356 // sector types
357 //
358 //==========================================================================
359
360 %type sector_op {int}
361
exp(from)362 sector_declaration ::= SECTOR exp(from) EQUALS exp(to) SEMICOLON.
363 {
364 FSectorTrans tr(to, true);
365 SectorTranslations.SetVal(from, tr);
366 }
367
SYM(sy)368 sector_declaration ::= SECTOR exp EQUALS SYM(sy) SEMICOLON.
369 {
370 Printf("Unknown constant '%s'\n", sy.sym);
371 }
372
exp(from)373 sector_declaration ::= SECTOR exp(from) EQUALS exp(to) NOBITMASK SEMICOLON.
374 {
375 FSectorTrans tr(to, false);
376 SectorTranslations.SetVal(from, tr);
377 }
378
exp(mask)379 sector_bitmask ::= SECTOR BITMASK exp(mask) sector_op(op) exp(shift) SEMICOLON.
380 {
381 FSectorMask sm = { mask, op, shift};
382 SectorMasks.Push(sm);
383 }
384
exp(mask)385 sector_bitmask ::= SECTOR BITMASK exp(mask) SEMICOLON.
386 {
387 FSectorMask sm = { mask, 0, 0};
388 SectorMasks.Push(sm);
389 }
390
exp(mask)391 sector_bitmask ::= SECTOR BITMASK exp(mask) CLEAR SEMICOLON.
392 {
393 FSectorMask sm = { mask, 0, 1};
394 SectorMasks.Push(sm);
395 }
396
sector_op(A)397 sector_op(A) ::= LSHASSIGN. { A = 1; }
sector_op(A)398 sector_op(A) ::= RSHASSIGN. { A = -1; }
399
400 %type lineflag_op {int}
401
exp(from)402 lineflag_declaration ::= LINEFLAG exp(from) EQUALS exp(to) SEMICOLON.
403 {
404 if (from >= 0 && from < 16)
405 {
406 LineFlagTranslations[from].newvalue = to;
407 LineFlagTranslations[from].ismask = false;
408 }
409 }
410
exp(from)411 lineflag_declaration ::= LINEFLAG exp(from) AND exp(mask) SEMICOLON.
412 {
413 if (from >= 0 && from < 16)
414 {
415 LineFlagTranslations[from].newvalue = mask;
416 LineFlagTranslations[from].ismask = true;
417 }
418 }