]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
8ad349bb | 4 | * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ |
1c79356b | 5 | * |
8ad349bb A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the | |
10 | * License may not be used to create, or enable the creation or | |
11 | * redistribution of, unlawful or unlicensed copies of an Apple operating | |
12 | * system, or to circumvent, violate, or enable the circumvention or | |
13 | * violation of, any terms of an Apple operating system software license | |
14 | * agreement. | |
15 | * | |
16 | * Please obtain a copy of the License at | |
17 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
18 | * file. | |
19 | * | |
20 | * The Original Code and all software distributed under the License are | |
21 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
22 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
23 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
24 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
25 | * Please see the License for the specific language governing rights and | |
26 | * limitations under the License. | |
27 | * | |
28 | * @APPLE_LICENSE_OSREFERENCE_HEADER_END@ | |
1c79356b A |
29 | */ |
30 | /* | |
31 | * @OSF_COPYRIGHT@ | |
32 | */ | |
33 | /* | |
34 | * HISTORY | |
35 | * | |
36 | * Revision 1.1.1.1 1998/09/22 21:05:48 wsanchez | |
37 | * Import of Mac OS X kernel (~semeria) | |
38 | * | |
39 | * Revision 1.1.1.1 1998/03/07 02:26:09 wsanchez | |
40 | * Import of OSF Mach kernel (~mburg) | |
41 | * | |
42 | * Revision 1.1.2.1 1997/03/27 18:46:52 barbou | |
43 | * Created. | |
44 | * [1997/03/27 13:58:42 barbou] | |
45 | * | |
46 | * $EndLog$ | |
47 | */ | |
48 | ||
49 | /* makedis.c - make a disassembler. */ | |
50 | ||
51 | /* , | |
52 | By Eamonn McManus <emcmanus@gr.osf.org>, April 1995. | |
53 | Copyright 1995 by Eamonn McManus. Non-commercial use is permitted. */ | |
54 | ||
55 | /* DESCRIPTION | |
56 | ||
57 | This program generates a disassembler in C from a file describing the | |
58 | opcodes of the machine in question. Lines in the description file are | |
59 | either comments beginning with #, or contain three fields, with the | |
60 | first two being terminated by space and the third containing the rest | |
61 | of the line. Long logical lines can be split onto several physical | |
62 | lines by ending each one except the last with a \. A logical line | |
63 | can also be split immediately after a |. Unlike \, | is considered | |
64 | part of the logical line. Leading spaces on continuation lines | |
65 | following either \ or | are ignored. | |
66 | ||
67 | Here is a concise description of the meanings of the three fields. | |
68 | Examples later will make it clearer what they are used for. | |
69 | ||
70 | The first field of the three is a function name. This will produce | |
71 | a function or array of the same name in the C output, so it should | |
72 | not conflict with other identifiers or C keywords. By default the | |
73 | function named returns a string (a (char *) in C), but if the first | |
74 | field is preceded by %, the function returns an unsigned long | |
75 | integer. | |
76 | ||
77 | The second field describes the arguments of the function. It consists | |
78 | of two parts, either but not both of which may be omitted. The first | |
79 | part is a string which is a bitmask describing the first argument of | |
80 | the function. Each character of the string represents one bit, | |
81 | with the least significant bit being the last. A character can be | |
82 | 0 or 1, representing that constant value, or a letter, representing | |
83 | part of a bitfield. A given bitfield consists of all of the | |
84 | contiguous bits containing the same letter. Upper and lower case | |
85 | letters are considered different. | |
86 | ||
87 | The second part of the second field is a list of parameters | |
88 | describing the parameters of the function, or the parameters after | |
89 | the first if the bitfield part was present. The list is contained | |
90 | in parentheses () and the individual parameters are separated by | |
91 | commas. Spaces are not allowed. Each parameter name is a single | |
92 | letter, optionally preceded by %. The parameter is an unsigned | |
93 | long integer if % is present, otherwise a string. Again, upper and | |
94 | lower case parameter names are different. | |
95 | ||
96 | The third field describes the value of the function. If a bitmask | |
97 | is present in the second field and it contains constant bits (0s or | |
98 | 1s), then the third field is the value of the function only in the | |
99 | case where its first argument contains matching values in those bit | |
100 | positions. There can be many different lines naming the same | |
101 | function but with different bitpatterns. The generated C code will | |
102 | arrange to return the value corresponding to the pattern that | |
103 | matches the actual first argument of the function when it is | |
104 | called. This argument should not have bits set in positions beyond | |
105 | those present in the bitpattern. | |
106 | ||
107 | It is only allowed for two different lines to name the same function | |
108 | if there is a bitstring in the second field. It is not allowed for | |
109 | two such lines to specify exactly the same constant bit values. But | |
110 | it is allowed for a line to have all the same constant bit values as | |
111 | another plus some extra constant values. In this case the more | |
112 | specific line applies when all of its constant bits match, and | |
113 | otherwise the less specific line applies. | |
114 | ||
115 | Apart from the contents of the bitstring, the second field must be | |
116 | identical on every line referring to a given function, and the | |
117 | bitstring must always be of the same length. | |
118 | ||
119 | For string-valued functions, the third field is the string value. | |
120 | For integer-valued functions, it is a C integer expression | |
121 | generating the value. In both cases there may be several special | |
122 | values: | |
123 | ||
124 | - A $ followed by a single letter is replaced by the value of the | |
125 | argument or bitfield with that name. The value of a bitfield is | |
126 | shifted as if that bitfield were in the least-significant bit | |
127 | position. Thus, a single-bit field always has value 0 or 1. | |
128 | ||
129 | - A $ followed by the name of a function and an argument list in | |
130 | parentheses () is replaced by the value returned by the function | |
131 | with those arguments. An integer value cannot be inserted into a | |
132 | string without being converted by a function, nor can a string | |
133 | value be used in an integer expression. | |
134 | ||
135 | - A $ followed by a bitstring enclosed in [] is replaced by the | |
136 | value of that bitstring. The bitstring has the same syntax as in | |
137 | the second field, described above. Each contiguous sequence of | |
138 | the same repeated letter in the bitstring is replaced by the | |
139 | value of the argument or bitfield-argument with that name, | |
140 | shifted into the appropriate position. | |
141 | ||
142 | - A list of strings, separated by |, enclosed in | |
143 | {}, and followed by an integer expression enclosed in [], is | |
144 | replaced by the string in the list whose number matches the value | |
145 | of the expression. The first string in the list is numbered 0. | |
146 | If there is no string corresponding to the value of the | |
147 | expression, the behaviour is undefined. The strings in the list | |
148 | may themselves contain $ or {} operations. | |
149 | ||
150 | - A \ followed by any character is replaced by that | |
151 | character, without regard to any meaning it may usually have. | |
152 | This is used to obtain strings containing characters such as | |
153 | {, $, or \. The use of backslash to split long logical | |
154 | lines takes precedence over this use, so \\ should not appear | |
155 | at the end of a line. | |
156 | ||
157 | The third field may also be a lone colon ":", in which case the | |
158 | function is assumed to be defined externally and only a function | |
159 | declaration (prototype) is generated. | |
160 | ||
161 | ||
162 | EXAMPLES | |
163 | ||
164 | Here are some examples from the description file for the Z80 | |
165 | microprocessor. This processor has 8-bit opcodes which are | |
166 | disassembled by a generated function "inst" which looks like this: | |
167 | ||
168 | typedef unsigned long bits; | |
169 | char *inst(bits code) {...} | |
170 | ||
171 | The simplest sort of line in the description file is one that looks | |
172 | like this: | |
173 | ||
174 | inst 01110110 halt | |
175 | ||
176 | The first field names the function, "inst". The second field | |
177 | implies that that function has exactly one argument which is an | |
178 | integer, and that this line specifies the value of the function | |
179 | when this integer has the binary value 01110110 (hex 0x76). This | |
180 | value will be the string "halt". | |
181 | ||
182 | A more complex line is one looking like this: | |
183 | ||
184 | inst 001aa111 {daa|cpl|scf|ccf}[$a] | |
185 | ||
186 | This line is compatible with the previous one, because it has the | |
187 | same number of bits and the constant bits are different. It | |
188 | specifies the value of inst when its argument looks like | |
189 | 001aa111, i.e., for the binary values | |
190 | 00100111, | |
191 | 00101111, | |
192 | 00110111, and | |
193 | 00111111. The value of $a for these four values will be | |
194 | respectively binary 00, 01, 10, 11, i.e., 0 to 3. The | |
195 | corresponding values of the inst function will be "daa", "cpl", | |
196 | "scf", and "ccf". | |
197 | ||
198 | The description defines a helper function "reg8" like this: | |
199 | ||
200 | reg8 rrr {b|c|d|e|h|l|(hl)|a}[$r] | |
201 | ||
202 | This simply selects one of the eight strings between {} depending | |
203 | on the value of the argument, which is assumed to be a three-bit | |
204 | value. This could just as easily have been written: | |
205 | ||
206 | reg8 (%r) {b|c|d|e|h|l|(hl)|a}[$r] | |
207 | ||
208 | The generated C code is the same -- in each case makedis realises | |
209 | that the function can be represented by an array rather than | |
210 | compiling a C function. | |
211 | ||
212 | The reg8 function is used in lines like this one: | |
213 | ||
214 | inst 01rrrsss ld $reg8($r),$reg8($s) | |
215 | ||
216 | Thus if the argument to inst is | |
217 | 01010011 | |
218 | then $r is 010 (2) and $s is 011 (3). Since reg8(2) is "d" and | |
219 | reg8(3) is "e", the value of inst with this argument will be the | |
220 | string "ld d,e". | |
221 | ||
222 | Note that the opcode for "halt" given above matches this pattern, | |
223 | but because the bitpattern for "halt" is more specific (has more | |
224 | constant bits) it is the one chosen when the argument is 01110110. | |
225 | ||
226 | The description also uses an external C function "hexprint" defined | |
227 | like this: | |
228 | ||
229 | char *hexprint(bits digits, bits n) { | |
230 | char *p = dis_alloc(digits + 1); | |
231 | sprintf(p, "%0*lx", (int) digits, n); | |
232 | return p; | |
233 | } | |
234 | ||
235 | The value of this function is a string containing the number n | |
236 | spelt out in hex with "digits" digits. In the description | |
237 | file this function is declared like this: | |
238 | ||
239 | hexprint (%w,%n) : | |
240 | ||
241 | The names of the parameters are not important in this case as long | |
242 | as they are letters and are different from each other. | |
243 | ||
244 | The hexprint function is used in lines like this one: | |
245 | ||
246 | inst 11vvv111 rst $hexprint(2,$v << 3) | |
247 | ||
248 | If the argument to inst is | |
249 | 11011111 | |
250 | then $v is 011 (3) and the arguments to hexprint are 2 and (3 << 3), | |
251 | i.e., 0x18. So the value of inst with this argument will be the | |
252 | string "rst 18". | |
253 | ||
254 | Instead of writing $v << 3, it would be possible to write | |
255 | $[00vvv000]. For instance when $v is binary 011, this becomes | |
256 | 00011000. The leading 0s could be omitted. | |
257 | ||
258 | The $[...] operation is particularly useful for moving bits around. | |
259 | For instance, the HP PA-RISC opcodes contain bits assigned to | |
260 | apparently random parts of the instruction word. One of the helper | |
261 | functions in its description file looks like this: | |
262 | ||
263 | im21l aaaaabbccddddddddddde l'$hex($[edddddddddddbbaaaaacc00000000000]) | |
264 | ||
265 | So 111110011000000000001 produces 10000000000000111111100000000000. | |
266 | ||
267 | The $[...] operation can also be used to spell out binary constants, | |
268 | since C has no syntax for this. | |
269 | ||
270 | ||
271 | ...More to come... */ | |
272 | ||
273 | /* To do: | |
274 | - More error detection, e.g., bitstring or arg not used in entry. | |
275 | - Better error recovery -- nearly all errors are currently fatal. | |
276 | - Clean up type handling, which is somewhat haphazard. It works but there | |
277 | is stuff that is surely redundant. | |
278 | - Make generated functions void by default, with $ prefix to indicate | |
279 | string-value. In a void function, instead of returning a string (or | |
280 | integer) it would be output via a user-supplied function. | |
281 | - Further optimise and tidy generated code, e.g.: arrays of one-character | |
282 | strings could be replaced by arrays of characters; switches with just | |
283 | one case could be replaced by ifs. | |
284 | */ | |
285 | ||
286 | #include <assert.h> | |
287 | #include <ctype.h> | |
288 | #include <errno.h> | |
289 | #include <limits.h> | |
290 | #include <stdio.h> | |
291 | #include <stdlib.h> | |
292 | #include <string.h> | |
293 | ||
294 | #ifndef LONG_BIT | |
295 | #define LONG_BIT (CHAR_BIT * sizeof (long)) | |
296 | #endif /* LONG_BIT */ | |
297 | ||
298 | #define MAXfunction 32 /* Max function name length. */ | |
299 | #define MAXBITS LONG_BIT /* Max bitstring length. */ | |
300 | typedef unsigned long bits; | |
301 | enum type {T_ERROR, T_UNKNOWN, T_INTEGER, T_STRING}; | |
302 | const char *const typename[] = {"error", "unknown", "integer", "string"}; | |
303 | enum walkstringop {COUNTARRAYS, DECLAREARRAYS, COMPILEARRAYS}; | |
304 | char *bitstype = "unsigned long"; | |
305 | ||
306 | int maxfunctionname, maxargwidth; | |
307 | char *progname = "makedis"; | |
308 | char **global_argv; | |
309 | char *filename; | |
310 | char *headerfilename; | |
311 | FILE *headerfile; | |
312 | int lineno; | |
313 | int indentation; | |
314 | int debug, dump, warnings; | |
315 | ||
316 | /* componentbits has a 1 bit for every possible number of strings we may want | |
317 | to concatenate together at some stage. A separate C function is compiled | |
318 | for each such case. */ | |
319 | bits componentbits; | |
320 | ||
321 | ||
322 | struct entry; | |
323 | struct arg; | |
324 | struct string; | |
325 | struct functioncall; | |
326 | struct array; | |
327 | struct bits; | |
328 | struct bitsplice; | |
329 | ||
330 | ||
331 | int main(int argc, char **argv); | |
332 | int makedis(FILE *f, char *fname); | |
333 | struct function *findfunction(char *function); | |
334 | int parseextern(struct function *fp, FILE *f); | |
335 | struct function *makefunction(char *function); | |
336 | int parsebits(struct function *fp, char *bitstring, int nbits); | |
337 | int parseentrybits(struct entry *ep, char *bitstring, int nbits, int issplice); | |
338 | int parsecontrol(char *name, char *value); | |
339 | int parseargs(struct function *fp, FILE *f, int *cp); | |
340 | int parsestring(struct function *fp, char *str); | |
341 | enum type makestring(struct function *fp, struct string **stringlink, | |
342 | char **stringp, char *magic, enum type targettype); | |
343 | int parsedollar(struct function *fp, char **stringp, struct string *sp); | |
344 | int parsebitsplice(struct function *fp, char *bitstring, int nbits, | |
345 | struct string *sp); | |
346 | int findvariable(struct function *fp, int name, struct string *sp); | |
347 | int parsefunctioncall(struct function *fp, char *start, char **stringp, | |
348 | struct string *sp); | |
349 | int parsearray(struct function *fp, char **stringp, struct string *sp, | |
350 | enum type t); | |
351 | void dumpfunctions(void); | |
352 | void dumpfunction(struct function *fp); | |
353 | void showentry(FILE *f, struct function *fp, struct entry *ep, bits highlight); | |
354 | void showbits(FILE *f, struct entry *ep, int nbits, bits highlight); | |
355 | void showargs(FILE *f, struct arg *ap, int fieldwidth); | |
356 | void showstring(FILE *f, struct string *sp); | |
357 | void showstringelement(FILE *f, struct string *sp); | |
358 | void showfunctioncall(FILE *f, struct functioncall *fcp); | |
359 | void showarray(FILE *f, struct array *ap); | |
360 | int outputfunctions(void); | |
361 | void outputidentity(FILE *f); | |
362 | int outputdeclarations(void); | |
363 | void outputconcats(void); | |
364 | void outputconcat(int n); | |
365 | void outputconcatheader(FILE *f, int n); | |
366 | void findarrays(void); | |
367 | int checkfixedlength(struct array *ap); | |
368 | int outputfunction(struct function *fp); | |
369 | void functionarray(struct function *fp); | |
370 | void functionheader(FILE *f, struct function *fp); | |
371 | int simplearray(struct array *ap); | |
372 | void compiletype(FILE *f, enum type *tp); | |
373 | int functionswitch(struct function *fp, bits mask, bits value); | |
374 | int compilestring(int assignto, struct string *sp, enum type type); | |
375 | int compilecheckedstring(int assignto, struct string *sp, enum type type); | |
376 | void compileassign(int assignto); | |
377 | void compiletemp(int tempno); | |
378 | void compiletext(char *s); | |
379 | int compileconcat(struct string *sp, enum type type); | |
380 | int compilenull(enum type type); | |
381 | int compilesimple(struct string *sp, enum type type); | |
382 | int compilearrayref(struct array *ap); | |
383 | int compilefunctioncall(struct string *sp); | |
384 | int walkstring(struct string *sp, enum walkstringop op, int tempno); | |
385 | int compilearray(struct array *ap); | |
386 | void compilesimplearray(enum type *tp, char *name, int num, struct array *ap); | |
387 | void declarearray(struct array *ap); | |
388 | void compilebitstring(struct bits *bp); | |
389 | void compilebitsplice(struct bitsplice *splicep); | |
390 | int bitcount(bits x); | |
391 | bits allbitsset(int nbits); | |
392 | void findent(FILE *f); | |
393 | void indent(void); | |
394 | void *xrealloc(char *oldp, size_t size); | |
395 | void *xmalloc(size_t size); | |
396 | void *xstrdup(char *s); | |
397 | int prematureeof(void); | |
398 | ||
399 | ||
400 | int main(int argc, char **argv) { | |
401 | int i; | |
402 | FILE *f; | |
403 | ||
404 | global_argv = argv; | |
405 | if (argc > 0) | |
406 | progname = argv[0]; | |
407 | for (i = 1; i < argc && argv[i][0] == '-'; i++) { | |
408 | switch (argv[i][1]) { | |
409 | case 'h': | |
410 | if (++i >= argc) | |
411 | goto Usage; | |
412 | headerfilename = argv[i]; break; | |
413 | case 'd': | |
414 | debug = 1; break; | |
415 | case 'D': | |
416 | dump = 1; break; | |
417 | case 'w': | |
418 | warnings = 1; break; | |
419 | default: | |
420 | Usage: | |
421 | fprintf(stderr, "Usage: %s [file]\n", progname); | |
422 | return 1; | |
423 | } | |
424 | } | |
425 | if (i == argc) | |
426 | return makedis(stdin, "<stdin>"); | |
427 | if (i + 1 != argc) | |
428 | goto Usage; | |
429 | if ((f = fopen(argv[i], "r")) == NULL) { | |
430 | fprintf(stderr, "%s: %s: %s\n", progname, argv[i], strerror(errno)); | |
431 | return 1; | |
432 | } | |
433 | return makedis(f, argv[i]); | |
434 | } | |
435 | ||
436 | ||
437 | int makedis(FILE *f, char *fname) { | |
438 | int c, i; | |
439 | char function[MAXfunction], bitstring[MAXBITS]; | |
440 | static char *string = NULL; | |
441 | int stringlen = 0; | |
442 | struct function *fp; | |
443 | ||
444 | filename = fname; | |
445 | lineno = 1; | |
446 | /* Loop for every line in the description. */ | |
447 | while (1) { | |
448 | /* Ignore initial spaces and newlines. */ | |
449 | while (isspace(c = getc(f))) | |
450 | if (c == '\n') | |
451 | lineno++; | |
452 | if (c == EOF) | |
453 | break; | |
454 | ||
455 | /* Ignore comments. # only allowed at start of line. */ | |
456 | if (c == '#') { | |
457 | while ((c = getc(f)) != '\n') | |
458 | if (c == EOF) | |
459 | return prematureeof(); | |
460 | lineno++; | |
461 | continue; | |
462 | } | |
463 | ||
464 | /* Read function name, terminated by space. */ | |
465 | for (i = 0; i < sizeof function && !isspace(c); i++, c = getc(f)) { | |
466 | if (c == EOF) | |
467 | return prematureeof(); | |
468 | function[i] = c; | |
469 | } | |
470 | if (i >= sizeof function) { | |
471 | fprintf(stderr, "%s: %s(%d): function name is too long: %.*s\n", | |
472 | progname, filename, lineno, i, function); | |
473 | return 1; | |
474 | } | |
475 | function[i] = '\0'; | |
476 | ||
477 | /* Skip to next field. */ | |
478 | while (isspace(c) && c != '\n') | |
479 | c = getc(f); | |
480 | ||
481 | /* If not a control statement, read bitstring and/or arguments. */ | |
482 | if (function[0] == ':') | |
483 | fp = 0; /* Silence gcc. */ | |
484 | else { | |
485 | fp = makefunction(function); | |
486 | if (fp == NULL) | |
487 | return 1; | |
488 | ||
489 | /* Read optional bitstring. */ | |
490 | for (i = 0; i < sizeof bitstring && isalnum(c); i++, c = getc(f)) { | |
491 | if (c == EOF) | |
492 | return prematureeof(); | |
493 | bitstring[i] = c; | |
494 | } | |
495 | if (isalnum(c)) { | |
496 | fprintf(stderr, "%s: %s(%d): bit string is too long: %.*s\n", | |
497 | progname, filename, lineno, i, bitstring); | |
498 | return 1; | |
499 | } | |
500 | if (parsebits(fp, bitstring, i) != 0) | |
501 | return 1; | |
502 | ||
503 | /* Read optional arguments. */ | |
504 | if (parseargs(fp, f, &c) != 0) | |
505 | return 1; | |
506 | ||
507 | /* Skip to next field. */ | |
508 | while (isspace(c) && c != '\n') | |
509 | c = getc(f); | |
510 | ||
511 | /* : indicates an external (C) function. */ | |
512 | if (c == ':') { | |
513 | if (parseextern(fp, f) != 0) | |
514 | return 1; | |
515 | continue; | |
516 | } | |
517 | } | |
518 | ||
519 | /* Read associated text. */ | |
520 | i = 0; | |
521 | while (1) { | |
522 | for ( ; c != '\n'; i++, c = getc(f)) { | |
523 | if (c == EOF) | |
524 | return prematureeof(); | |
525 | if (i >= stringlen) { | |
526 | stringlen = stringlen * 2 + 16; | |
527 | string = xrealloc(string, stringlen); | |
528 | } | |
529 | string[i] = c; | |
530 | } | |
531 | lineno++; | |
532 | if (i > 0) { | |
533 | switch (string[i - 1]) { | |
534 | case '\\': | |
535 | i--; | |
536 | /* Fall in... */ | |
537 | case '|': | |
538 | while (isspace(c = getc(f)) && c != '\n') ; | |
539 | continue; | |
540 | } | |
541 | } | |
542 | break; | |
543 | } | |
544 | if (i >= stringlen) { | |
545 | stringlen = stringlen * 2 + 16; | |
546 | string = xrealloc(string, stringlen); | |
547 | } | |
548 | string[i] = '\0'; | |
549 | ||
550 | /* Parse the line just read. */ | |
551 | if (function[0] == ':') { | |
552 | if (parsecontrol(function + 1, string) != 0) | |
553 | return 1; | |
554 | } else { | |
555 | if (parsestring(fp, string) != 0) | |
556 | return 1; | |
557 | } | |
558 | } | |
559 | if (dump) | |
560 | dumpfunctions(); | |
561 | return outputfunctions(); | |
562 | } | |
563 | ||
564 | ||
565 | /* A function in the description file. nbits and nargs are -1 until the | |
566 | real values are known. */ | |
567 | struct function { | |
568 | struct function *next; | |
569 | char *name; | |
570 | enum type type; | |
571 | int nbits; /* Number of bits in the bitpattern, 0 if none. */ | |
572 | int nargs; /* Number of (x,y,...) parameters, 0 if none. */ | |
573 | char isarray; /* Will be represented by a C array. */ | |
574 | int fixedlength; /* If a C array, will be a char [][N] not a char *[]. */ | |
575 | struct entry *first, *last; | |
576 | /* Links to the value(s) supplied. */ | |
577 | struct arg *args; /* List of (x,y,...) names and types. */ | |
578 | }; | |
579 | struct function *functions; | |
580 | ||
581 | ||
582 | /* Find the function with the given name. If not found, create a structure | |
583 | for it, fill it out with a template, and return that. */ | |
584 | struct function *findfunction(char *name) { | |
585 | struct function *fp; | |
586 | ||
587 | for (fp = functions; fp != NULL; fp = fp->next) { | |
588 | if (strcmp(fp->name, name) == 0) | |
589 | return fp; | |
590 | } | |
591 | if (strlen(name) > maxfunctionname) | |
592 | maxfunctionname = strlen(name); | |
593 | fp = xmalloc(sizeof *fp); | |
594 | fp->next = functions; | |
595 | functions = fp; | |
596 | fp->name = xstrdup(name); | |
597 | fp->type = T_UNKNOWN; | |
598 | fp->nbits = fp->nargs = -1; /* nbits will be set correctly later. */ | |
599 | fp->isarray = 0; | |
600 | fp->first = fp->last = NULL; | |
601 | return fp; | |
602 | } | |
603 | ||
604 | ||
605 | /* Parse an external (C) function declaration. This will look something like: | |
606 | malloc (%s) : | |
607 | We're called just after seeing the ':'. | |
608 | Return 0 if parsing is successful, 1 otherwise. */ | |
609 | int parseextern(struct function *fp, FILE *f) { | |
610 | int c; | |
611 | ||
612 | if ((c = getc(f)) != '\n') { | |
613 | fprintf(stderr, | |
614 | "%s: %s(%d): extern declaration should be a lone `:'\n", | |
615 | progname, filename, lineno); | |
616 | return 1; | |
617 | } | |
618 | if (fp->nbits != 0) { | |
619 | fprintf(stderr, | |
620 | "%s: %s(%d): extern functions should not have bitstrings\n", | |
621 | progname, filename, lineno); | |
622 | return 1; | |
623 | } | |
624 | free(fp->first); | |
625 | fp->first = fp->last = NULL; | |
626 | return 0; | |
627 | } | |
628 | ||
629 | ||
630 | /* A value supplied for a function (the third field in a description line). | |
631 | In general there can be any number of such values, differing in the | |
632 | bitpattern supplied. The mask and value fields describe the constant | |
633 | bits in the bitpattern: mask indicates which bits they are and value | |
634 | indicates the values of those bits. So this entry matches | |
635 | ((x & mask) == value). */ | |
636 | struct entry { | |
637 | struct entry *next; | |
638 | bits mask, value; | |
639 | struct bits *bits; /* List of named bitfields. */ | |
640 | struct string *string; /* Value of function when bitpattern matched. */ | |
641 | char done; /* This entry has already been compiled. */ | |
642 | }; | |
643 | ||
644 | ||
645 | /* We've just seen a definition of function "name". Make a structure for it | |
646 | if necessary, and a template entry that will describe the value given here. | |
647 | */ | |
648 | struct function *makefunction(char *name) { | |
649 | struct function *fp; | |
650 | struct entry *ep = xmalloc(sizeof *ep); | |
651 | enum type type; | |
652 | ||
653 | if (name[0] == '%') { | |
654 | name++; | |
655 | type = T_INTEGER; | |
656 | } else | |
657 | type = T_STRING; | |
658 | fp = findfunction(name); | |
659 | if (fp->type == T_UNKNOWN) | |
660 | fp->type = type; | |
661 | else if (fp->type != type) { | |
662 | fprintf(stderr, "%s: %s(%d): function %s previously declared as %s, " | |
663 | "here as %s\n", progname, filename, lineno, name, | |
664 | typename[fp->type], typename[type]); | |
665 | return NULL; | |
666 | } | |
667 | ep->next = NULL; | |
668 | ep->bits = NULL; | |
669 | ep->done = 0; | |
670 | if (fp->first != NULL) | |
671 | fp->last->next = ep; | |
672 | else | |
673 | fp->first = ep; | |
674 | fp->last = ep; | |
675 | return fp; | |
676 | } | |
677 | ||
678 | ||
679 | /* A named bitfield within the bitpattern of a function entry, or within a | |
680 | $[...] bitsplice. The mask covers the bitfield and the shift says how | |
681 | many 0 bits there are after the last 1 in the mask. */ | |
682 | struct bits { | |
683 | struct bits *next; | |
684 | int shift; | |
685 | bits mask; | |
686 | char name; | |
687 | }; | |
688 | ||
689 | ||
690 | /* Parse the bitstring supplied for the given function. nbits says how many | |
691 | bits there are; it can legitimately be 0. Return value is 0 on success. */ | |
692 | int parsebits(struct function *fp, char *bitstring, int nbits) { | |
693 | if (fp->nbits < 0) | |
694 | fp->nbits = nbits; | |
695 | else if (fp->nbits != nbits) { | |
696 | fprintf(stderr, "%s: %s(%d): bit string of length %d;\n", | |
697 | progname, filename, lineno, nbits); | |
698 | fprintf(stderr, " function %s has bit strings of length %d\n", | |
699 | fp->name, fp->nbits); | |
700 | return 1; | |
701 | } | |
702 | return parseentrybits(fp->last, bitstring, nbits, 0); | |
703 | } | |
704 | ||
705 | ||
706 | /* Parse a bitstring that is the pattern for a function entry or that is in a | |
707 | $[...] bitsplice. Put the result in ep. Return value is 0 on success. */ | |
708 | int parseentrybits(struct entry *ep, char *bitstring, int nbits, int issplice) { | |
709 | int i, j; | |
710 | char bit; | |
711 | bits mask, value, entrymask; | |
712 | struct bits *bp; | |
713 | ||
714 | mask = value = 0; | |
715 | for (i = 0; i < nbits; i++) { | |
716 | bit = bitstring[nbits - 1 - i]; | |
717 | switch (bit) { | |
718 | case '1': | |
719 | value |= 1 << i; | |
720 | /* Fall in... */ | |
721 | case '0': | |
722 | mask |= 1 << i; | |
723 | continue; | |
724 | } | |
725 | if (!isalpha(bit)) { | |
726 | fprintf(stderr, "%s: %s(%d): invalid character in bitstring: %c\n", | |
727 | progname, filename, lineno, bit); | |
728 | return 1; | |
729 | } | |
730 | if (!issplice) { | |
731 | for (bp = ep->bits; bp != NULL; bp = bp->next) { | |
732 | if (bp->name == bit) { | |
733 | fprintf(stderr, | |
734 | "%s: %s(%d): bitstring name %c used twice\n", | |
735 | progname, filename, lineno, bit); | |
736 | return 1; | |
737 | } | |
738 | } | |
739 | } | |
740 | entrymask = 1 << i; | |
741 | for (j = i + 1; j < nbits && bitstring[nbits - 1 - j] == bit; j++) | |
742 | entrymask |= 1 << j; | |
743 | bp = xmalloc(sizeof *bp); | |
744 | bp->shift = i; | |
745 | bp->mask = entrymask; | |
746 | bp->name = bit; | |
747 | bp->next = ep->bits; | |
748 | ep->bits = bp; | |
749 | i = j - 1; | |
750 | } | |
751 | ep->mask = mask; | |
752 | ep->value = value; | |
753 | return 0; | |
754 | } | |
755 | ||
756 | ||
757 | /* Parse a control line. This looks something like: | |
758 | :bitstype unsigned int | |
759 | in which case we will be called with name "bitstype" and | |
760 | value "unsigned int". */ | |
761 | int parsecontrol(char *name, char *value) { | |
762 | if (strcmp(name, "bitstype") == 0) | |
763 | bitstype = xstrdup(value); | |
764 | else { | |
765 | fprintf(stderr, "%s: %s(%d): unrecognised control keyword %s\n", | |
766 | progname, filename, lineno, name); | |
767 | return 1; | |
768 | } | |
769 | return 0; | |
770 | } | |
771 | ||
772 | ||
773 | /* A parameter to a function, e.g., x in: | |
774 | %f aaa(%x) $a + $x */ | |
775 | struct arg { | |
776 | struct arg *next; | |
777 | enum type type; | |
778 | char name; | |
779 | }; | |
780 | ||
781 | ||
782 | /* Parse the parameters (x,y,...) to a function and put the result in fp. | |
783 | The entry that is being built is fp->last. cp points to the opening | |
784 | (; if it does not point to a ( then there are no parameters. If | |
785 | this is the first entry for the function, fp->nargs will be -1 and | |
786 | we will build up an argument list. Otherwise, fp->nargs will be | |
787 | >= 0 and we will only check that the arguments here are consistent | |
788 | with what went before. Return value is 0 on success. */ | |
789 | int parseargs(struct function *fp, FILE *f, int *cp) { | |
790 | struct arg **arglink, *ap; | |
791 | struct bits *bp; | |
792 | int nargs, width; | |
793 | char name; | |
794 | enum type t; | |
795 | ||
796 | arglink = &fp->args; | |
797 | width = nargs = 0; | |
798 | if (*cp == '(') { | |
799 | *cp = getc(f); | |
800 | if (*cp != ')') { | |
801 | width = 1; | |
802 | while (1) { | |
803 | nargs++; | |
804 | width += 2; | |
805 | if (fp->nargs >= 0 && nargs > fp->nargs) { | |
806 | fprintf(stderr, | |
807 | "%s: %s(%d): %d arg(s) instead of %d for %s\n", | |
808 | progname, filename, lineno, nargs, fp->nargs, | |
809 | fp->name); | |
810 | return 1; | |
811 | } | |
812 | t = T_STRING; | |
813 | if (*cp == '%') { | |
814 | width++; | |
815 | t = T_INTEGER; | |
816 | *cp = getc(f); | |
817 | } | |
818 | name = *cp; | |
819 | if (!isalpha(name)) { | |
820 | fprintf(stderr, | |
821 | "%s: %s(%d): argument should be letter: %c\n", | |
822 | progname, filename, lineno, name); | |
823 | return 1; | |
824 | } | |
825 | for (bp = fp->last->bits; bp != NULL; bp = bp->next) { | |
826 | if (bp->name == name) { | |
827 | fprintf(stderr, | |
828 | "%s: %s(%d): %c is a bitstring and an arg\n", | |
829 | progname, filename, lineno, name); | |
830 | return 1; | |
831 | } | |
832 | } | |
833 | if (fp->nargs >= 0) { | |
834 | if ((*arglink)->name != name) { | |
835 | fprintf(stderr, | |
836 | "%s: %s(%d): arg %d of %s is %c not %c\n", | |
837 | progname, filename, lineno, nargs, fp->name, | |
838 | (*arglink)->name, name); | |
839 | return 1; | |
840 | } | |
841 | if ((*arglink)->type != t) { | |
842 | fprintf(stderr, | |
843 | "%s: %s(%d): arg %c of %s: inconsistent type\n", | |
844 | progname, filename, lineno, name, fp->name); | |
845 | return 1; | |
846 | } | |
847 | } else { | |
848 | for (ap = fp->args; ap != *arglink; ap = ap->next) { | |
849 | if (ap->name == name) { | |
850 | fprintf(stderr, | |
851 | "%s: %s(%d): argument name %c used twice\n", | |
852 | progname, filename, lineno, name); | |
853 | return 1; | |
854 | } | |
855 | } | |
856 | *arglink = xmalloc(sizeof **arglink); | |
857 | (*arglink)->name = name; | |
858 | (*arglink)->type = t; | |
859 | } | |
860 | arglink = &(*arglink)->next; | |
861 | *cp = getc(f); | |
862 | if (*cp == ')') | |
863 | break; | |
864 | if (*cp != ',') { | |
865 | fprintf(stderr, | |
866 | "%s: %s(%d): bad character in argument list: %c\n" | |
867 | " (arguments must be single letters)\n", | |
868 | progname, filename, lineno, *cp); | |
869 | return 1; | |
870 | } | |
871 | *cp = getc(f); | |
872 | } | |
873 | } | |
874 | *cp = getc(f); | |
875 | } | |
876 | if (fp->nargs < 0) { | |
877 | fp->nargs = nargs; | |
878 | width += fp->nbits; | |
879 | if (width > maxargwidth) | |
880 | maxargwidth = width; | |
881 | } else if (fp->nargs != nargs) { | |
882 | fprintf(stderr, "%s: %s(%d): argument list of length %d;\n", | |
883 | progname, filename, lineno, nargs); | |
884 | fprintf(stderr, " function %s has argument lists of length %d\n", | |
885 | fp->name, fp->nargs); | |
886 | return 1; | |
887 | } | |
888 | *arglink = NULL; | |
889 | return 0; | |
890 | } | |
891 | ||
892 | ||
893 | /* Parse the string describing the value of this entry for our | |
894 | function. Return 0 on success. */ | |
895 | int parsestring(struct function *fp, char *str) { | |
896 | enum type t; | |
897 | ||
898 | t = makestring(fp, &fp->last->string, &str, NULL, fp->type); | |
899 | if (t == T_ERROR) | |
900 | return 1; | |
901 | if (fp->type != t && t != T_UNKNOWN) { | |
902 | fprintf(stderr, "%s: %s(%d): function %s has inconsistent types\n", | |
903 | progname, filename, lineno, fp->name); | |
904 | return 1; | |
905 | } | |
906 | return 0; | |
907 | } | |
908 | ||
909 | ||
910 | /* A parsed representation of the whole string describing a value of a | |
911 | function, or certain strings within that (e.g., array indices). This is a | |
912 | linked list of substrings whose type is given by the type field. */ | |
913 | struct string { | |
914 | struct string *next; | |
915 | enum elementtype { | |
916 | S_TEXT, S_BITSTRING, S_BITSPLICE, S_PARAMETER, S_FUNCTIONCALL, S_ARRAY | |
917 | } type; | |
918 | union value { /* The fields here correspond to the enum values. */ | |
919 | char *text; /* plain text */ | |
920 | struct bits *bits; /* $x where x is a bitfield */ | |
921 | struct bitsplice *bitsplice; /* $[...] */ | |
922 | struct arg *parameter; /* $x where x is a parameter */ | |
923 | struct functioncall *functioncall; /* $func(...) */ | |
924 | struct array *array; /* {...}[...] */ | |
925 | } value; | |
926 | }; | |
927 | ||
928 | /* The representation of a function call $func(...) in the description of a | |
929 | function value. */ | |
930 | struct functioncall { | |
931 | struct function *function; | |
932 | struct stringlist *args; | |
933 | }; | |
934 | ||
935 | /* The representation of an array selection {...|...}[...] in the description | |
936 | of a function value. tempno is used when constructing a C variable name | |
937 | that will contain the strings or numbers in an array. */ | |
938 | struct array { | |
939 | struct string *index; /* what's between [...] */ | |
940 | struct stringlist *elements; /* what's between {...} */ | |
941 | enum type type; /* the type of each element */ | |
942 | int tempno; | |
943 | }; | |
944 | ||
945 | /* A list of strings, being the list of arguments in a function call or the | |
946 | list of elements of an array. This is a linked list of linked lists. */ | |
947 | struct stringlist { | |
948 | struct stringlist *next; | |
949 | enum type type; | |
950 | struct string *string; | |
951 | }; | |
952 | ||
953 | ||
954 | /* The following are the only characters with special meaning at the top level | |
955 | of parsing of a function value. When parsing arrays or function calls, | |
956 | other characters become special. */ | |
957 | #define MAKESTRING_MAGIC "${"/*}*/ | |
958 | ||
959 | ||
960 | /* Parse a function return-value string or substring and make a struct string | |
961 | list for it. The string starts at *stringp and ends at a \0 or at any | |
962 | character in the `magic' string other than { or $. *stringp is updated | |
963 | to point to the terminating character. The parsed representation is put | |
964 | at *stringlink. `fp' is the function whose return value is being parsed. | |
965 | `targettype' is the expected type of the result, if known. | |
966 | The return value is the actual type. */ | |
967 | enum type makestring(struct function *fp, struct string **stringlink, | |
968 | char **stringp, char *magic, enum type targettype) { | |
969 | char *p, *q; | |
970 | struct string *sp, **firststringlink; | |
971 | int n, components; | |
972 | int parenlevel = 0; | |
973 | enum type t = targettype, newt; | |
974 | ||
975 | if (magic == NULL) | |
976 | magic = MAKESTRING_MAGIC; | |
977 | p = *stringp; | |
978 | firststringlink = stringlink; | |
979 | components = 0; | |
980 | while (*p != '\0') { | |
981 | sp = xmalloc(sizeof *sp); | |
982 | q = p; | |
983 | n = 0; | |
984 | do { | |
985 | if (strchr(magic, *q) != NULL) { | |
986 | if (*q != ')' || parenlevel == 0) | |
987 | break; | |
988 | } | |
989 | switch (*q) { | |
990 | case '(': | |
991 | parenlevel++; break; | |
992 | case ')': | |
993 | parenlevel--; break; | |
994 | case '\\': | |
995 | if (q[1] != '\0') | |
996 | q++; | |
997 | break; | |
998 | } | |
999 | n++; | |
1000 | } while (*++q != '\0'); | |
1001 | if (n > 0) { | |
1002 | sp->type = S_TEXT; | |
1003 | sp->value.text = q = xmalloc(n + 1); | |
1004 | do { | |
1005 | if (*p == '\\') | |
1006 | p++; | |
1007 | *q++ = *p++; | |
1008 | } while (--n > 0); | |
1009 | *q = '\0'; | |
1010 | newt = t; | |
1011 | } else if (*p == '$') { | |
1012 | if (parsedollar(fp, &p, sp) != 0) | |
1013 | return T_ERROR; | |
1014 | switch (sp->type) { | |
1015 | case S_BITSTRING: | |
1016 | case S_BITSPLICE: | |
1017 | newt = T_INTEGER; | |
1018 | break; | |
1019 | case S_PARAMETER: | |
1020 | newt = sp->value.parameter->type; | |
1021 | break; | |
1022 | case S_FUNCTIONCALL: | |
1023 | newt = sp->value.functioncall->function->type; | |
1024 | break; | |
1025 | default: | |
1026 | fprintf(stderr, "makestring type %d\n", sp->type); | |
1027 | abort(); | |
1028 | } | |
1029 | } else if (*p == '{'/*}*/) { | |
1030 | if (parsearray(fp, &p, sp, t) != 0) | |
1031 | return T_ERROR; | |
1032 | newt = sp->value.array->type; | |
1033 | } else { | |
1034 | free(sp); | |
1035 | break; | |
1036 | } | |
1037 | if (t == T_UNKNOWN) | |
1038 | t = newt; | |
1039 | else if (newt != T_UNKNOWN && t != newt) { | |
1040 | if (stringlink == firststringlink) { | |
1041 | fprintf(stderr, "%s: %s(%d): expected %s type:\n", progname, | |
1042 | filename, lineno, typename[t]); | |
1043 | showstringelement(stderr, sp); | |
1044 | return T_ERROR; | |
1045 | } | |
1046 | *stringlink = NULL; | |
1047 | fprintf(stderr, "%s: %s(%d): mixed types in string:\n", | |
1048 | progname, filename, lineno); | |
1049 | showstring(stderr, *firststringlink); | |
1050 | fprintf(stderr, " -- %s\n", typename[t]); | |
1051 | showstringelement(stderr, sp); | |
1052 | fprintf(stderr, " -- %s\n", typename[newt]); | |
1053 | return T_ERROR; | |
1054 | } | |
1055 | *stringlink = sp; | |
1056 | stringlink = &sp->next; | |
1057 | components++; | |
1058 | } | |
1059 | *stringlink = NULL; | |
1060 | *stringp = p; | |
1061 | if (components >= MAXBITS) { | |
1062 | fprintf(stderr, "%s: %s(%d): excessively complicated string\n", | |
1063 | progname, filename, lineno); | |
1064 | return T_ERROR; | |
1065 | } | |
1066 | componentbits |= 1 << components; | |
1067 | return t; | |
1068 | } | |
1069 | ||
1070 | ||
1071 | /* Parse a $ operation at **stringp and update *stringp to point past it. | |
1072 | `fp' is the function whose return value is being parsed. The parsed | |
1073 | item will be put at *sp. Return 0 on success, nonzero on error. */ | |
1074 | int parsedollar(struct function *fp, char **stringp, struct string *sp) { | |
1075 | char *p, *start; | |
1076 | ||
1077 | p = *stringp; | |
1078 | assert(*p == '$'); | |
1079 | start = ++p; | |
1080 | if (*p == '[') | |
1081 | p++; | |
1082 | while (isalnum(*p) || *p == '_') | |
1083 | p++; | |
1084 | if (*start == '[') { | |
1085 | if (*p != ']') { | |
1086 | fprintf(stderr, "%s: %s(%d): missing ] or bad character in $[\n", | |
1087 | progname, filename, lineno); | |
1088 | return 1; | |
1089 | } | |
1090 | *stringp = p + 1; | |
1091 | return parsebitsplice(fp, start + 1, p - start - 1, sp); | |
1092 | } | |
1093 | if (p == start) { | |
1094 | fprintf(stderr, "%s: %s(%d): missing identifier after $\n", progname, | |
1095 | filename, lineno); | |
1096 | return 1; | |
1097 | } | |
1098 | if (p == start + 1) { | |
1099 | if (findvariable(fp, *start, sp) != 0) | |
1100 | return 1; | |
1101 | } else { | |
1102 | if (parsefunctioncall(fp, start, &p, sp) != 0) | |
1103 | return 1; | |
1104 | } | |
1105 | *stringp = p; | |
1106 | return 0; | |
1107 | } | |
1108 | ||
1109 | ||
1110 | /* The representation of a $[...] bitsplice. It is parsed into a | |
1111 | struct entry just as if it were a bitfield parameter, then analysed | |
1112 | into a chain of struct bitsplicebits. These in conjunction with | |
1113 | the constant portion of the struct entry will allow the bitsplice to | |
1114 | be compiled. Each bitsplicebits element represents either a numeric | |
1115 | argument to the current function, in which case it will be shifted | |
1116 | into place; or a bitfield name from the bitfield description of the | |
1117 | current function, in which case it will be shifted by the difference | |
1118 | between the position of the bitfield in the argument and the position | |
1119 | it occurs in the bitsplice. `shift' indicates how much to shift left | |
1120 | the associated value; if it is negative the value is shifted right. | |
1121 | For instance, in a function like this: | |
1122 | %oh xx00(%y) $[yyxx] | |
1123 | the bitsplicebits for y will have shift = 2 and value.arg pointing to y, | |
1124 | and those for x will have shift = -2 and value.mask = binary 1100. | |
1125 | As an optimisation, contiguous bitfields that are also contiguous in the | |
1126 | bitsplice will be combined. For instance: | |
1127 | %oh xxyy00 $[0xxyy0] | |
1128 | will compile the same code as: | |
1129 | %oh zzzz00 $[0zzzz0]. | |
1130 | As another optimisation, a bitfield that occupies the entire bitstring | |
1131 | for a function will be treated like a parameter in that it will not be | |
1132 | masked in the bitsplice. For instance: | |
1133 | %oh xxxxxx $[0xxxxxx0] | |
1134 | will compile the same code as: | |
1135 | %oh (%x) $[0xxxxxx0]. */ | |
1136 | struct bitsplice { | |
1137 | struct entry entry; | |
1138 | int nbits; | |
1139 | struct bitsplicebits *splice; | |
1140 | }; | |
1141 | struct bitsplicebits { | |
1142 | struct bitsplicebits *next; | |
1143 | int shift; | |
1144 | enum elementtype type; | |
1145 | union { | |
1146 | struct arg *arg; | |
1147 | bits mask; | |
1148 | } value; | |
1149 | }; | |
1150 | ||
1151 | ||
1152 | int parsebitsplice(struct function *fp, char *bitstring, int nbits, | |
1153 | struct string *sp) { | |
1154 | struct bitsplice *splicep; | |
1155 | struct bitsplicebits *bsp, *lastbsp, **bspp; | |
1156 | struct bits *bp; | |
1157 | int shift, nfrombits, ntobits; | |
1158 | bits allbits, b; | |
1159 | ||
1160 | splicep = xmalloc(sizeof *splicep); | |
1161 | splicep->nbits = nbits; | |
1162 | if (parseentrybits(&splicep->entry, bitstring, nbits, 1) != 0) | |
1163 | return 1; | |
1164 | bspp = &splicep->splice; | |
1165 | lastbsp = NULL; | |
1166 | for (bp = splicep->entry.bits; bp != NULL; bp = bp->next) { | |
1167 | if (findvariable(fp, bp->name, sp) != 0) | |
1168 | return 1; | |
1169 | shift = bp->shift; | |
1170 | if (sp->type == S_BITSTRING) { | |
1171 | nfrombits = bitcount(sp->value.bits->mask); | |
1172 | ntobits = bitcount(bp->mask); | |
1173 | if (warnings) { | |
1174 | if (nfrombits != ntobits) { | |
1175 | fprintf(stderr, "%s: %s(%d): warning: " | |
1176 | "bitstring $%c %ser than its place " | |
1177 | "in bitsplice\n", | |
1178 | progname, filename, lineno, bp->name, | |
1179 | (nfrombits > ntobits) ? "bigg" : "small"); | |
1180 | } | |
1181 | } | |
1182 | shift -= sp->value.bits->shift; | |
1183 | ||
1184 | /* See if this bitfield can be combined with a previous contiguous | |
1185 | bitfield. */ | |
1186 | if (lastbsp != NULL && lastbsp->type == S_BITSTRING | |
1187 | && lastbsp->shift == shift) { | |
1188 | lastbsp->value.mask |= sp->value.bits->mask; | |
1189 | continue; | |
1190 | } | |
1191 | } else { | |
1192 | assert(sp->type == S_PARAMETER); | |
1193 | if (sp->value.parameter->type != T_INTEGER) { | |
1194 | fprintf(stderr, | |
1195 | "%s: %s(%d): variable %c in $[...] should be integer\n", | |
1196 | progname, filename, lineno, sp->value.parameter->name); | |
1197 | return 1; | |
1198 | } | |
1199 | } | |
1200 | *bspp = bsp = xmalloc(sizeof *bsp); | |
1201 | bsp->type = sp->type; | |
1202 | bsp->shift = shift; | |
1203 | if (sp->type == S_PARAMETER) | |
1204 | bsp->value.arg = sp->value.parameter; | |
1205 | else | |
1206 | bsp->value.mask = sp->value.bits->mask; | |
1207 | bspp = &bsp->next; | |
1208 | lastbsp = bsp; | |
1209 | } | |
1210 | *bspp = NULL; | |
1211 | ||
1212 | /* Look for a spliced element that is the entire bitstring argument to | |
1213 | this function and therefore doesn't need to be masked. */ | |
1214 | allbits = allbitsset(fp->nbits); | |
1215 | for (bsp = splicep->splice; bsp != NULL; bsp = bsp->next) { | |
1216 | if (bsp->type == S_BITSTRING) { | |
1217 | for (b = bsp->value.mask; b != 0 && !(b & 1); b >>= 1) ; | |
1218 | if (b == allbits) | |
1219 | bsp->value.mask = 0; | |
1220 | } | |
1221 | } | |
1222 | sp->type = S_BITSPLICE; | |
1223 | sp->value.bitsplice = splicep; | |
1224 | return 0; | |
1225 | } | |
1226 | ||
1227 | ||
1228 | int findvariable(struct function *fp, int name, struct string *sp) { | |
1229 | struct bits *bp; | |
1230 | struct arg *ap; | |
1231 | ||
1232 | for (bp = fp->last->bits; bp != NULL; bp = bp->next) { | |
1233 | if (bp->name == name) { | |
1234 | sp->type = S_BITSTRING; | |
1235 | sp->value.bits = bp; | |
1236 | return 0; | |
1237 | } | |
1238 | } | |
1239 | for (ap = fp->args; ap != NULL; ap = ap->next) { | |
1240 | if (ap->name == name) { | |
1241 | sp->type = S_PARAMETER; | |
1242 | sp->value.parameter = ap; | |
1243 | return 0; | |
1244 | } | |
1245 | } | |
1246 | fprintf(stderr, "%s: %s(%d): undefined parameter %c\n", progname, filename, | |
1247 | lineno, name); | |
1248 | return 1; | |
1249 | } | |
1250 | ||
1251 | ||
1252 | int parsefunctioncall(struct function *fp, char *start, char **stringp, | |
1253 | struct string *sp) { | |
1254 | char *p; | |
1255 | struct functioncall *fcp; | |
1256 | struct stringlist **arglink, *arg; | |
1257 | enum type t; | |
1258 | ||
1259 | p = *stringp; | |
1260 | if (*p != '(') { | |
1261 | fprintf(stderr, "%s: %s(%d): missing ( after function %.*s\n", progname, | |
1262 | filename, lineno, p - start, start); | |
1263 | return 1; | |
1264 | } | |
1265 | sp->type = S_FUNCTIONCALL; | |
1266 | sp->value.functioncall = fcp = xmalloc(sizeof *fcp); | |
1267 | *p = '\0'; /* Ugly. */ | |
1268 | fcp->function = findfunction(start); | |
1269 | *p = '('; | |
1270 | arglink = &fcp->args; | |
1271 | if (*++p != ')') { | |
1272 | while (1) { | |
1273 | arg = xmalloc(sizeof *arg); | |
1274 | t = makestring(fp, &arg->string, &p, MAKESTRING_MAGIC ",)", | |
1275 | T_UNKNOWN); | |
1276 | if (t == T_ERROR) | |
1277 | return 1; | |
1278 | arg->type = t; | |
1279 | *arglink = arg; | |
1280 | arglink = &arg->next; | |
1281 | if (*p == ')') | |
1282 | break; | |
1283 | assert(*p == ','); | |
1284 | p++; | |
1285 | } | |
1286 | } | |
1287 | *arglink = NULL; | |
1288 | assert(*p == ')'); | |
1289 | *stringp = p + 1; | |
1290 | return 0; | |
1291 | } | |
1292 | ||
1293 | ||
1294 | int parsearray(struct function *fp, char **stringp, struct string *sp, | |
1295 | enum type t) { | |
1296 | char *p; | |
1297 | struct array *ap; | |
1298 | struct stringlist **elementlink, *element; | |
1299 | ||
1300 | p = *stringp; | |
1301 | assert(*p == '{'/*}*/); | |
1302 | sp->type = S_ARRAY; | |
1303 | sp->value.array = ap = xmalloc(sizeof *ap); | |
1304 | ap->tempno = -1; | |
1305 | elementlink = &ap->elements; | |
1306 | ap->type = t; | |
1307 | if (*++p != /*{*/'}') { | |
1308 | while (1) { | |
1309 | element = xmalloc(sizeof *element); | |
1310 | t = makestring(fp, &element->string, &p, | |
1311 | MAKESTRING_MAGIC /*{*/"|}", t); | |
1312 | if (t == T_ERROR) | |
1313 | return 1; | |
1314 | element->type = t; | |
1315 | if (ap->type == T_UNKNOWN) | |
1316 | ap->type = t; | |
1317 | else if (t != T_UNKNOWN && ap->type != t) { | |
1318 | fprintf(stderr, "%s: %s(%d): mixed types in array:\n", | |
1319 | progname, filename, lineno); | |
1320 | showstring(stderr, ap->elements->string); | |
1321 | fprintf(stderr, " -- %s\n", typename[ap->type]); | |
1322 | showstring(stderr, element->string); | |
1323 | fprintf(stderr, " -- %s\n", typename[t]); | |
1324 | return 1; | |
1325 | } | |
1326 | *elementlink = element; | |
1327 | elementlink = &element->next; | |
1328 | if (*p == /*{*/'}') | |
1329 | break; | |
1330 | assert(*p == '|'); | |
1331 | p++; | |
1332 | } | |
1333 | } | |
1334 | *elementlink = NULL; | |
1335 | assert(*p == /*{*/'}'); | |
1336 | if (*++p != '[') { | |
1337 | fprintf(stderr, "%s: %s(%d): missing [index] after array\n", | |
1338 | progname, filename, lineno); | |
1339 | return 1; | |
1340 | } | |
1341 | ++p; | |
1342 | t = makestring(fp, &ap->index, &p, MAKESTRING_MAGIC "]", T_INTEGER); | |
1343 | if (t == T_ERROR) | |
1344 | return 1; | |
1345 | if (t == T_STRING) { | |
1346 | fprintf(stderr, "%s: %s(%d): array index cannot be string:\n", | |
1347 | progname, filename, lineno); | |
1348 | showstring(stderr, ap->index); | |
1349 | return 1; | |
1350 | } | |
1351 | if (*p != ']') { | |
1352 | fprintf(stderr, "%s: %s(%d): [ without ]\n", progname, filename, | |
1353 | lineno); | |
1354 | return 1; | |
1355 | } | |
1356 | *stringp = p + 1; | |
1357 | return 0; | |
1358 | } | |
1359 | ||
1360 | ||
1361 | void dumpfunctions() { | |
1362 | struct function *fp; | |
1363 | ||
1364 | for (fp = functions; fp != NULL; fp = fp->next) | |
1365 | dumpfunction(fp); | |
1366 | } | |
1367 | ||
1368 | ||
1369 | void dumpfunction(struct function *fp) { | |
1370 | struct entry *ep; | |
1371 | ||
1372 | for (ep = fp->first; ep != NULL; ep = ep->next) | |
1373 | showentry(stderr, fp, ep, 0); | |
1374 | } | |
1375 | ||
1376 | ||
1377 | /* Entries are not shown exactly as they would be input, since \ would | |
1378 | need to be provided before some characters such as $ or {. But the | |
1379 | characters "|},]" pose a problem since a \ is only needed in certain | |
1380 | contexts and is annoying otherwise. It's not worth doing this right, | |
1381 | since it's only used for error messages. */ | |
1382 | void showentry(FILE *f, struct function *fp, struct entry *ep, bits highlight) { | |
1383 | if (fp->type == T_INTEGER) | |
1384 | putc('%', f); | |
1385 | fprintf(f, "%-*s ", maxfunctionname + 1, fp->name); | |
1386 | if (fp->nbits == 0 && fp->nargs == 0) | |
1387 | fprintf(f, "%-*s", maxargwidth, "()"); | |
1388 | else { | |
1389 | showbits(f, ep, fp->nbits, 0); | |
1390 | showargs(f, fp->args, maxargwidth - fp->nbits); | |
1391 | } | |
1392 | putc(' ', f); | |
1393 | showstring(f, ep->string); | |
1394 | putc('\n', f); | |
1395 | if (highlight != 0) { | |
1396 | fprintf(f, "%-*s ", maxfunctionname + 1, ""); | |
1397 | showbits(f, ep, fp->nbits, highlight); | |
1398 | putc('\n', f); | |
1399 | } | |
1400 | } | |
1401 | ||
1402 | ||
1403 | void showbits(FILE *f, struct entry *ep, int nbits, bits highlight) { | |
1404 | struct bits *bp; | |
1405 | bits i, value; | |
1406 | char zero, one; | |
1407 | ||
1408 | if (nbits == 0) | |
1409 | return; | |
1410 | i = 1 << (nbits - 1); | |
1411 | bp = ep->bits; | |
1412 | if (highlight) { | |
1413 | value = highlight; | |
1414 | zero = ' '; | |
1415 | one = '^'; | |
1416 | } else { | |
1417 | value = ep->value; | |
1418 | zero = '0'; | |
1419 | one = '1'; | |
1420 | } | |
1421 | do { | |
1422 | if (highlight != 0 || (ep->mask & i)) { | |
1423 | putc((value & i) ? one : zero, f); | |
1424 | i >>= 1; | |
1425 | } else { | |
1426 | assert(bp != NULL && (bp->mask & i)); | |
1427 | do { | |
1428 | putc(bp->name, f); | |
1429 | i >>= 1; | |
1430 | } while (bp->mask & i); | |
1431 | bp = bp->next; | |
1432 | } | |
1433 | } while (i != 0); | |
1434 | } | |
1435 | ||
1436 | ||
1437 | void showargs(FILE *f, struct arg *ap, int fieldwidth) { | |
1438 | int width; | |
1439 | int lastc; | |
1440 | int isint; | |
1441 | ||
1442 | if (ap == NULL) | |
1443 | width = 0; | |
1444 | else { | |
1445 | width = 1; | |
1446 | lastc = '('; | |
1447 | do { | |
1448 | isint = (ap->type == T_INTEGER); | |
1449 | fprintf(f, "%c%s%c", lastc, isint ? "%" : "", ap->name); | |
1450 | width += 2 + isint; | |
1451 | ap = ap->next; | |
1452 | lastc = ','; | |
1453 | } while (ap != NULL); | |
1454 | putc(')', f); | |
1455 | } | |
1456 | fprintf(f, "%-*s", fieldwidth - width, ""); | |
1457 | } | |
1458 | ||
1459 | ||
1460 | void showstring(FILE *f, struct string *sp) { | |
1461 | for ( ; sp != NULL; sp = sp->next) | |
1462 | showstringelement(f, sp); | |
1463 | } | |
1464 | ||
1465 | ||
1466 | void showstringelement(FILE *f, struct string *sp) { | |
1467 | struct bitsplice *bsp; | |
1468 | ||
1469 | switch (sp->type) { | |
1470 | case S_TEXT: | |
1471 | fputs(sp->value.text, f); | |
1472 | break; | |
1473 | case S_BITSTRING: | |
1474 | fprintf(f, "$%c", sp->value.bits->name); | |
1475 | break; | |
1476 | case S_BITSPLICE: | |
1477 | fprintf(f, "$["); | |
1478 | bsp = sp->value.bitsplice; | |
1479 | showbits(f, &bsp->entry, bsp->nbits, 0); | |
1480 | fprintf(f, "]"); | |
1481 | break; | |
1482 | case S_PARAMETER: | |
1483 | fprintf(f, "$%c", sp->value.parameter->name); | |
1484 | break; | |
1485 | case S_FUNCTIONCALL: | |
1486 | showfunctioncall(f, sp->value.functioncall); | |
1487 | break; | |
1488 | case S_ARRAY: | |
1489 | showarray(f, sp->value.array); | |
1490 | break; | |
1491 | default: | |
1492 | fprintf(stderr, "showstring case %d\n", sp->type); | |
1493 | abort(); | |
1494 | } | |
1495 | } | |
1496 | ||
1497 | ||
1498 | void showfunctioncall(FILE *f, struct functioncall *fcp) { | |
1499 | struct stringlist *sp; | |
1500 | char *last; | |
1501 | ||
1502 | fprintf(f, "$%s(", fcp->function->name); | |
1503 | last = ""; | |
1504 | for (sp = fcp->args; sp != NULL; sp = sp->next) { | |
1505 | fputs(last, f); | |
1506 | last = ","; | |
1507 | showstring(f, sp->string); | |
1508 | } | |
1509 | putc(')', f); | |
1510 | } | |
1511 | ||
1512 | ||
1513 | void showarray(FILE *f, struct array *ap) { | |
1514 | struct stringlist *sp; | |
1515 | char *last; | |
1516 | ||
1517 | putc('{'/*}*/, f); | |
1518 | last = ""; | |
1519 | for (sp = ap->elements; sp != NULL; sp = sp->next) { | |
1520 | fputs(last, f); | |
1521 | last = "|"; | |
1522 | showstring(f, sp->string); | |
1523 | } | |
1524 | fputs(/*{*/"}[", f); | |
1525 | showstring(f, ap->index); | |
1526 | putc(']', f); | |
1527 | } | |
1528 | ||
1529 | ||
1530 | const char commonpreamble[] = "\ | |
1531 | typedef %s bits;\n\ | |
1532 | \n\ | |
1533 | "; | |
1534 | ||
1535 | const char concatpreamble[] = "\ | |
1536 | static char *dis_buf;\n\ | |
1537 | static int dis_bufindex, dis_buflen;\n\ | |
1538 | \n\ | |
1539 | void *dis_alloc(size_t size)\n\ | |
1540 | {\n\ | |
1541 | void *p;\n\ | |
1542 | int newindex = dis_bufindex + size;\n\ | |
1543 | if (newindex > dis_buflen) {\n\ | |
1544 | dis_buflen = newindex * 4;\n\ | |
1545 | dis_buf = malloc(dis_buflen);\n\ | |
1546 | /* We can't use realloc because there might be pointers extant into\n\ | |
1547 | the old buffer. So we waste the memory of the old buffer. We\n\ | |
1548 | should soon reach an adequate buffer size and stop leaking. */\n\ | |
1549 | if (dis_buf == 0) {\n\ | |
1550 | perror(\"malloc\");\n\ | |
1551 | exit(1);\n\ | |
1552 | }\n\ | |
1553 | dis_bufindex = 0;\n\ | |
1554 | }\n\ | |
1555 | p = dis_buf + dis_bufindex;\n\ | |
1556 | dis_bufindex = newindex;\n\ | |
1557 | return p;\n\ | |
1558 | }\n\ | |
1559 | \n\ | |
1560 | void dis_done()\n\ | |
1561 | {\n\ | |
1562 | dis_bufindex = 0;\n\ | |
1563 | }\n\ | |
1564 | \n\ | |
1565 | "; | |
1566 | ||
1567 | const char concatdeclarations[] = "\ | |
1568 | #include <string.h>\n\ | |
1569 | #include <stdlib.h>\n\ | |
1570 | #include <errno.h>\n\ | |
1571 | \n\ | |
1572 | extern void *dis_realloc(void *p, size_t size); /* User-provided. */\n\ | |
1573 | void *dis_alloc(size_t size);\n\ | |
1574 | void dis_done(void);\n\ | |
1575 | "; | |
1576 | ||
1577 | const char nonconcatpreamble[] = "\ | |
1578 | void dis_done() {}\n\ | |
1579 | "; | |
1580 | ||
1581 | ||
1582 | int outputfunctions() { | |
1583 | struct function *fp; | |
1584 | ||
1585 | outputidentity(stdout); | |
1586 | if (headerfilename != NULL) { | |
1587 | if ((headerfile = fopen(headerfilename, "w")) == NULL) { | |
1588 | fprintf(stderr, "%s: create %s: %s\n", progname, headerfilename, | |
1589 | strerror(errno)); | |
1590 | return 1; | |
1591 | } | |
1592 | outputidentity(headerfile); | |
1593 | fprintf(headerfile, commonpreamble, bitstype); | |
1594 | printf("\n#include \"%s\"\n", headerfilename); | |
1595 | } else | |
1596 | printf(commonpreamble, bitstype); | |
1597 | findarrays(); | |
1598 | if (outputdeclarations() != 0) | |
1599 | return 1; | |
1600 | outputconcats(); | |
1601 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1602 | if (fp->isarray) | |
1603 | functionarray(fp); | |
1604 | } | |
1605 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1606 | if (fp->first != NULL && !fp->isarray) { | |
1607 | if (outputfunction(fp) != 0) | |
1608 | return 1; | |
1609 | } | |
1610 | } | |
1611 | return 0; | |
1612 | } | |
1613 | ||
1614 | ||
1615 | void outputidentity(FILE *f) { | |
1616 | char **p; | |
1617 | ||
1618 | fprintf(f, "/*\n * This file was generated by:\n *"); | |
1619 | for (p = global_argv; *p != NULL; p++) | |
1620 | fprintf(f, " %s", *p); | |
1621 | fprintf(f, "\n */\n\n"); | |
1622 | } | |
1623 | ||
1624 | ||
1625 | int outputdeclarations() { | |
1626 | FILE *f = headerfile ? headerfile : stdout; | |
1627 | struct function *fp; | |
1628 | ||
1629 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1630 | if (fp->type != T_UNKNOWN) { | |
1631 | if (fp->isarray) { | |
1632 | fprintf(f, "extern "); | |
1633 | if (fp->fixedlength > 0) | |
1634 | fprintf(f, "char %s[][%d]", fp->name, fp->fixedlength); | |
1635 | else { | |
1636 | compiletype(f, &fp->type); | |
1637 | fprintf(f, "%s[]", fp->name); | |
1638 | } | |
1639 | } else | |
1640 | functionheader(f, fp); | |
1641 | fprintf(f, ";\n"); | |
1642 | } | |
1643 | } | |
1644 | return 0; | |
1645 | } | |
1646 | ||
1647 | ||
1648 | void outputconcats() { | |
1649 | int i; | |
1650 | ||
1651 | if (componentbits & ~3) { | |
1652 | fputs(concatdeclarations, headerfile ? headerfile : stdout); | |
1653 | fputs(concatpreamble, stdout); | |
1654 | } else | |
1655 | fputs(nonconcatpreamble, stdout); | |
1656 | for (i = 2; i < MAXBITS; i++) { | |
1657 | if (componentbits & (1 << i)) | |
1658 | outputconcat(i); | |
1659 | } | |
1660 | } | |
1661 | ||
1662 | ||
1663 | void outputconcat(int n) { | |
1664 | int i; | |
1665 | char *last; | |
1666 | ||
1667 | assert(n > 1); | |
1668 | if (headerfile) { | |
1669 | outputconcatheader(headerfile, n); | |
1670 | fprintf(headerfile, ";\n"); | |
1671 | } | |
1672 | outputconcatheader(stdout, n); | |
1673 | printf("\n{\n void *p;\n int len = "); | |
1674 | last = ""; | |
1675 | for (i = 0; i < n; i++) { | |
1676 | printf("%sstrlen(p%d)", last, i); | |
1677 | last = " + "; | |
1678 | } | |
1679 | printf(";\n p = dis_alloc(len + 1);\n return "); | |
1680 | for (i = 1; i < n; i++) | |
1681 | printf("strcat("); | |
1682 | printf("strcpy(p, p0)"); | |
1683 | for (i = 1; i < n; i++) | |
1684 | printf(", p%d)", i); | |
1685 | printf(";\n}\n\n"); | |
1686 | } | |
1687 | ||
1688 | ||
1689 | void outputconcatheader(FILE *f, int n) { | |
1690 | int i; | |
1691 | char *last = ""; | |
1692 | ||
1693 | fprintf(f, "char *dis_concat%d(", n); | |
1694 | for (i = 0; i < n; i++) { | |
1695 | fprintf(f, "%schar *p%d", last, i); | |
1696 | last = ", "; | |
1697 | } | |
1698 | fprintf(f, ")"); | |
1699 | } | |
1700 | ||
1701 | ||
1702 | void findarrays() { | |
1703 | struct function *fp; | |
1704 | struct entry *ep; | |
1705 | struct string *estr, *indexstr; | |
1706 | struct bits *bp; | |
1707 | ||
1708 | for (fp = functions; fp != NULL; fp = fp->next) { | |
1709 | if (fp->nbits > 0 && fp->nargs > 0) | |
1710 | continue; | |
1711 | if (fp->nargs > 1) | |
1712 | continue; | |
1713 | ep = fp->first; | |
1714 | if (ep == NULL || ep->next != NULL) | |
1715 | continue; | |
1716 | estr = ep->string; | |
1717 | if (estr == NULL || estr->next != NULL || estr->type != S_ARRAY) | |
1718 | continue; | |
1719 | indexstr = estr->value.array->index; | |
1720 | if (indexstr->next != NULL) | |
1721 | continue; | |
1722 | if (fp->nbits > 0) { | |
1723 | bp = ep->bits; | |
1724 | if (bp == NULL || bp->next != NULL || bp->shift != 0) | |
1725 | continue; | |
1726 | if (bp->mask != allbitsset(fp->nbits)) | |
1727 | continue; | |
1728 | if (indexstr->type != S_BITSTRING || indexstr->value.bits != bp) | |
1729 | continue; | |
1730 | } else { | |
1731 | if (indexstr->type != S_PARAMETER | |
1732 | || indexstr->value.parameter != fp->args) | |
1733 | continue; | |
1734 | } | |
1735 | if (!simplearray(estr->value.array)) | |
1736 | continue; | |
1737 | fp->isarray = 1; | |
1738 | fp->fixedlength = | |
1739 | (fp->type == T_INTEGER) ? 0 : checkfixedlength(estr->value.array); | |
1740 | } | |
1741 | } | |
1742 | ||
1743 | ||
1744 | int checkfixedlength(struct array *ap) { | |
1745 | int len, maxlen, wasted, n; | |
1746 | struct stringlist *lp; | |
1747 | ||
1748 | maxlen = 0; | |
1749 | for (lp = ap->elements; lp != NULL; lp = lp->next) { | |
1750 | if (lp->string == NULL) | |
1751 | continue; | |
1752 | assert(lp->string->type == S_TEXT); | |
1753 | len = strlen(lp->string->value.text); | |
1754 | if (len > maxlen) | |
1755 | maxlen = len; | |
1756 | } | |
1757 | for (wasted = n = 0, lp = ap->elements; lp != NULL; n++, lp = lp->next) { | |
1758 | if (lp->string == NULL) | |
1759 | continue; | |
1760 | wasted += maxlen - strlen(lp->string->value.text); | |
1761 | } | |
1762 | if (wasted < n * sizeof(char *)) /* Should be target's sizeof. */ | |
1763 | return maxlen + 1; | |
1764 | return 0; | |
1765 | } | |
1766 | ||
1767 | ||
1768 | int outputfunction(struct function *fp) { | |
1769 | printf("\n"); | |
1770 | functionheader(stdout, fp); | |
1771 | printf("\n{\n"/*}*/); | |
1772 | switch (functionswitch(fp, 0, 0)) { | |
1773 | case -1: | |
1774 | return 1; | |
1775 | case 0: | |
1776 | if (warnings) { | |
1777 | fprintf(stderr, "%s: warning: not all cases of %s covered\n", | |
1778 | progname, fp->name); | |
1779 | } | |
1780 | } | |
1781 | printf(/*{*/"}\n"); | |
1782 | return 0; | |
1783 | } | |
1784 | ||
1785 | ||
1786 | void functionarray(struct function *fp) { | |
1787 | struct array *ap; | |
1788 | ||
1789 | ap = fp->first->string->value.array; | |
1790 | printf("\n"); | |
1791 | compilesimplearray(&fp->type, fp->name, 0, ap); | |
1792 | } | |
1793 | ||
1794 | ||
1795 | void functionheader(FILE *f, struct function *fp) { | |
1796 | char *last; | |
1797 | struct arg *ap; | |
1798 | ||
1799 | compiletype(f, &fp->type); | |
1800 | fprintf(f, "%s(", fp->name); | |
1801 | last = ""; | |
1802 | if (fp->nbits > 0) { | |
1803 | fprintf(f, "bits code"); | |
1804 | last = ", "; | |
1805 | } | |
1806 | for (ap = fp->args; ap != NULL; ap = ap->next) { | |
1807 | fprintf(f, last); | |
1808 | compiletype(f, &ap->type); | |
1809 | putc(ap->name, f); | |
1810 | last = ", "; | |
1811 | } | |
1812 | if (*last == '\0') | |
1813 | fprintf(f, "void"); | |
1814 | putc(')', f); | |
1815 | } | |
1816 | ||
1817 | ||
1818 | int simplearray(struct array *ap) { | |
1819 | struct stringlist *lp; | |
1820 | ||
1821 | for (lp = ap->elements; lp != NULL; lp = lp->next) { | |
1822 | if (lp->string != NULL | |
1823 | && (lp->string->next != NULL || lp->string->type != S_TEXT)) | |
1824 | break; | |
1825 | } | |
1826 | return (lp == NULL); | |
1827 | } | |
1828 | ||
1829 | ||
1830 | void compiletype(FILE *f, enum type *tp) { | |
1831 | switch (*tp) { | |
1832 | case T_UNKNOWN: | |
1833 | *tp = T_STRING; | |
1834 | /* Fall in... */ | |
1835 | case T_STRING: | |
1836 | fprintf(f, "char *"); | |
1837 | break; | |
1838 | case T_INTEGER: | |
1839 | fprintf(f, "bits "); | |
1840 | break; | |
1841 | default: | |
1842 | fprintf(stderr, "compiletype type %d\n", *tp); | |
1843 | abort(); | |
1844 | } | |
1845 | } | |
1846 | ||
1847 | ||
1848 | /* Generate code for entries in function fp whose bitstring b satisfies | |
1849 | the constraint (b & mask) == value. Return 1 if generated switch | |
1850 | always does `return', 0 if not, -1 on error. | |
1851 | The algorithm is as follows. Scan the eligible entries to find the | |
1852 | largest set of bits not in the passed-in mask which always have a | |
1853 | constant value (are not variable). One `default' entry is allowed | |
1854 | all of whose bits are variable. For each value of the constant bits, | |
1855 | generate a `switch' case and invoke the function recursively with | |
1856 | that value included in the constraint parameters. The recursion | |
1857 | stops when no set of constant bits is found, perhaps because the | |
1858 | mask parameter has all bits set. | |
1859 | This algorithm could be improved. Currently it will fail if there | |
1860 | are input lines "xxyy", "00xx" and "yy00", each of which is default with | |
1861 | respect to the others. The correct behaviour would then be to select | |
1862 | a bit that is sometimes constant and deal with those cases first. | |
1863 | But this problem has not yet arisen in real life. */ | |
1864 | int functionswitch(struct function *fp, bits mask, bits value) { | |
1865 | struct entry *ep, *defaultcase; | |
1866 | bits allbits, constbits, missingcases; | |
1867 | int nhits, ncases, nconstbits, alwaysreturns; | |
1868 | ||
1869 | indentation++; | |
1870 | allbits = allbitsset(fp->nbits); | |
1871 | constbits = allbits & ~mask; | |
1872 | if (debug) { | |
1873 | findent(stderr); | |
1874 | fprintf(stderr, | |
1875 | "functionswitch(%s): (x & 0x%lx) == 0x%lx; const == 0x%lx\n", | |
1876 | fp->name, mask, value, constbits); | |
1877 | } | |
1878 | defaultcase = NULL; | |
1879 | ncases = nhits = 0; | |
1880 | alwaysreturns = 1; | |
1881 | for (ep = fp->first; ep != NULL; ep = ep->next) { | |
1882 | /* If this is not one of the entries under consideration, skip. */ | |
1883 | if (ep->done | |
1884 | || (ep->mask & mask) != mask || (ep->value & mask) != value) | |
1885 | continue; | |
1886 | if (debug) { | |
1887 | findent(stderr); | |
1888 | showentry(stderr, fp, ep, 0); | |
1889 | } | |
1890 | /* If this entry has no constant bits in the still-variable portion, | |
1891 | it's the default. */ | |
1892 | if ((constbits & ep->mask) == 0) { | |
1893 | if (defaultcase != NULL) { | |
1894 | fprintf(stderr, | |
1895 | "%s: function %s: unable to distinguish between:\n", | |
1896 | progname, fp->name); | |
1897 | showentry(stderr, fp, defaultcase, 0); | |
1898 | showentry(stderr, fp, ep, 0); | |
1899 | return -1; | |
1900 | } | |
1901 | defaultcase = ep; | |
1902 | if (debug) { | |
1903 | findent(stderr); | |
1904 | fprintf(stderr, "^^ default case\n"); | |
1905 | } | |
1906 | } else { | |
1907 | if (debug && (constbits & ~ep->mask)) { | |
1908 | findent(stderr); | |
1909 | fprintf(stderr, "const now 0x%lx\n", constbits & ep->mask); | |
1910 | } | |
1911 | constbits &= ep->mask; | |
1912 | nhits++; | |
1913 | } | |
1914 | } | |
1915 | if (nhits > 0) { | |
1916 | indent(); | |
1917 | if (constbits == allbits) | |
1918 | printf("switch (code) {\n"/*}*/); | |
1919 | else | |
1920 | printf("switch (code & 0x%lx) {\n"/*}*/, constbits); | |
1921 | for (ep = fp->first; ep != NULL; ep = ep->next) { | |
1922 | /* If this is not one of the entries under consideration, skip. */ | |
1923 | if ((ep->mask & mask) != mask || (ep->value & mask) != value) | |
1924 | continue; | |
1925 | if (ep->done || ep == defaultcase) | |
1926 | continue; | |
1927 | ncases++; | |
1928 | indent(); | |
1929 | printf("case 0x%lx:\n", ep->value & constbits); | |
1930 | switch (functionswitch(fp, mask | constbits, | |
1931 | value | (ep->value & constbits))) { | |
1932 | case -1: | |
1933 | return -1; | |
1934 | case 0: | |
1935 | alwaysreturns = 0; | |
1936 | indentation++; indent(); indentation--; | |
1937 | printf("break;\n"); | |
1938 | } | |
1939 | } | |
1940 | indent(); | |
1941 | printf(/*{*/"}\n"); | |
1942 | } | |
1943 | nconstbits = bitcount(constbits); | |
1944 | missingcases = ((nconstbits == MAXBITS) ? 0 : 1 << nconstbits) - ncases; | |
1945 | if (alwaysreturns) { | |
1946 | switch (missingcases) { | |
1947 | case 0: | |
1948 | if (defaultcase != NULL) { | |
1949 | fprintf(stderr, "%s: warning: redundant entry:\n", progname); | |
1950 | showentry(stderr, fp, defaultcase, 0); | |
1951 | defaultcase = NULL; | |
1952 | } | |
1953 | break; | |
1954 | case 1: | |
1955 | if (defaultcase != NULL && nconstbits != 0) { | |
1956 | fprintf(stderr, | |
1957 | "%s: warning: variable bit(s) could be constant:\n", | |
1958 | progname); | |
1959 | showentry(stderr, fp, defaultcase, constbits); | |
1960 | break; | |
1961 | } | |
1962 | /* Fall in... */ | |
1963 | default: | |
1964 | alwaysreturns = 0; | |
1965 | } | |
1966 | } | |
1967 | if (defaultcase != NULL) { | |
1968 | /* If defaultcase has some constant bits of its own, recursion will | |
1969 | check that they have the required value. */ | |
1970 | if ((defaultcase->mask & ~mask) == 0) { | |
1971 | alwaysreturns = 1; | |
1972 | if (compilestring(-1, defaultcase->string, fp->type) != 0) | |
1973 | return -1; | |
1974 | defaultcase->done = 1; | |
1975 | } else { | |
1976 | indentation--; | |
1977 | alwaysreturns = functionswitch(fp, mask, value); | |
1978 | indentation++; | |
1979 | } | |
1980 | } | |
1981 | indentation--; | |
1982 | return alwaysreturns; | |
1983 | } | |
1984 | ||
1985 | ||
1986 | int compilestring(int assignto, struct string *sp, enum type type) { | |
1987 | int tempno; | |
1988 | ||
1989 | tempno = walkstring(sp, COUNTARRAYS, assignto); | |
1990 | if (tempno > assignto) { | |
1991 | indent(); | |
1992 | printf("{\n"/*}*/); | |
1993 | indentation++; | |
1994 | (void) walkstring(sp, DECLAREARRAYS, assignto); | |
1995 | if (walkstring(sp, COMPILEARRAYS, assignto) < 0) | |
1996 | return 1; | |
1997 | } | |
1998 | if (compilecheckedstring(assignto, sp, type) != 0) | |
1999 | return 1; | |
2000 | if (tempno > assignto) { | |
2001 | indentation--; | |
2002 | indent(); | |
2003 | printf(/*{*/"}\n"); | |
2004 | } | |
2005 | return 0; | |
2006 | } | |
2007 | ||
2008 | ||
2009 | int compilecheckedstring(int assignto, struct string *sp, enum type type) { | |
2010 | compileassign(assignto); | |
2011 | if (compileconcat(sp, type) != 0) | |
2012 | return 1; | |
2013 | printf(";\n"); | |
2014 | return 0; | |
2015 | } | |
2016 | ||
2017 | ||
2018 | void compileassign(int assignto) { | |
2019 | indent(); | |
2020 | if (assignto < 0) | |
2021 | printf("return "); | |
2022 | else { | |
2023 | compiletemp(assignto); | |
2024 | printf(" = "); | |
2025 | } | |
2026 | } | |
2027 | ||
2028 | ||
2029 | void compiletemp(int tempno) { | |
2030 | printf("t__%d", tempno); | |
2031 | } | |
2032 | ||
2033 | ||
2034 | void compiletext(char *s) { | |
2035 | putchar('"'); | |
2036 | if (s != NULL) { | |
2037 | for ( ; *s != '\0'; s++) { | |
2038 | switch (*s) { | |
2039 | case '"': | |
2040 | case '\\': | |
2041 | putchar('\\'); | |
2042 | } | |
2043 | putchar(*s); | |
2044 | } | |
2045 | } | |
2046 | putchar('"'); | |
2047 | } | |
2048 | ||
2049 | ||
2050 | int compileconcat(struct string *sp, enum type type) { | |
2051 | int elements; | |
2052 | struct string *sp1; | |
2053 | char *last; | |
2054 | ||
2055 | if (sp == NULL) | |
2056 | return compilenull(type); | |
2057 | if (sp->next == NULL) | |
2058 | return compilesimple(sp, type); | |
2059 | if (type != T_INTEGER) { | |
2060 | for (elements = 0, sp1 = sp; sp1 != NULL; elements++, sp1 = sp1->next) ; | |
2061 | printf("dis_concat%d(", elements); | |
2062 | } | |
2063 | last = ""; | |
2064 | for (sp1 = sp; sp1 != NULL; sp1 = sp1->next) { | |
2065 | printf(last); | |
2066 | if (type != T_INTEGER) | |
2067 | last = ", "; | |
2068 | if (sp1->type == S_ARRAY) | |
2069 | compilearrayref(sp1->value.array); | |
2070 | else | |
2071 | if (compilesimple(sp1, type) != 0) | |
2072 | return 1; | |
2073 | } | |
2074 | if (type != T_INTEGER) | |
2075 | printf(")"); | |
2076 | return 0; | |
2077 | } | |
2078 | ||
2079 | ||
2080 | int compilenull(enum type type) { | |
2081 | if (type == T_INTEGER) { | |
2082 | fprintf(stderr, "%s: empty integer expression\n", progname); | |
2083 | return 1; | |
2084 | } | |
2085 | printf("\"\""); | |
2086 | return 0; | |
2087 | } | |
2088 | ||
2089 | ||
2090 | int compilesimple(struct string *sp, enum type type) { | |
2091 | if (sp == NULL) | |
2092 | return compilenull(type); | |
2093 | switch (sp->type) { | |
2094 | case S_TEXT: | |
2095 | if (type == T_INTEGER) | |
2096 | printf("%s", sp->value.text); | |
2097 | else | |
2098 | compiletext(sp->value.text); | |
2099 | break; | |
2100 | case S_BITSTRING: | |
2101 | compilebitstring(sp->value.bits); | |
2102 | break; | |
2103 | case S_BITSPLICE: | |
2104 | compilebitsplice(sp->value.bitsplice); | |
2105 | break; | |
2106 | case S_PARAMETER: | |
2107 | putchar(sp->value.parameter->name); | |
2108 | break; | |
2109 | case S_FUNCTIONCALL: | |
2110 | return compilefunctioncall(sp); | |
2111 | case S_ARRAY: | |
2112 | if (compilearrayref(sp->value.array) != 0) | |
2113 | return 1; | |
2114 | break; | |
2115 | default: | |
2116 | fprintf(stderr, "compilesimple case %d", sp->type); | |
2117 | abort(); | |
2118 | } | |
2119 | return 0; | |
2120 | } | |
2121 | ||
2122 | ||
2123 | int compilearrayref(struct array *ap) { | |
2124 | compiletemp(ap->tempno); | |
2125 | if (simplearray(ap)) { | |
2126 | printf("["); | |
2127 | if (compileconcat(ap->index, T_INTEGER) != 0) | |
2128 | return 1; | |
2129 | printf("]"); | |
2130 | } | |
2131 | return 0; | |
2132 | } | |
2133 | ||
2134 | ||
2135 | int compilefunctioncall(struct string *sp) { | |
2136 | struct function *fp; | |
2137 | struct stringlist *actualp; | |
2138 | struct arg *formalp; | |
2139 | char *last; | |
2140 | int nbits; | |
2141 | enum type formaltype; | |
2142 | ||
2143 | assert(sp->type == S_FUNCTIONCALL); | |
2144 | fp = sp->value.functioncall->function; | |
2145 | printf("%s%c", fp->name, fp->isarray ? '[' : '('); | |
2146 | last = ""; | |
2147 | nbits = fp->nbits; | |
2148 | formalp = fp->args; | |
2149 | actualp = sp->value.functioncall->args; | |
2150 | while (actualp != NULL) { | |
2151 | if (nbits > 0) { | |
2152 | nbits = 0; | |
2153 | formaltype = T_INTEGER; | |
2154 | } else { | |
2155 | if (formalp == NULL) { | |
2156 | fprintf(stderr, "%s: too many arguments to %s:\n", progname, | |
2157 | fp->name); | |
2158 | showstring(stderr, sp); | |
2159 | putc('\n', stderr); | |
2160 | return 1; | |
2161 | } | |
2162 | formaltype = formalp->type; | |
2163 | formalp = formalp->next; | |
2164 | } | |
2165 | if (actualp->type != T_UNKNOWN && actualp->type != formaltype) { | |
2166 | fprintf(stderr, "%s: argument to %s has the wrong type:\n", | |
2167 | progname, fp->name); | |
2168 | showstring(stderr, actualp->string); | |
2169 | putc('\n', stderr); | |
2170 | return 1; | |
2171 | } | |
2172 | printf(last); | |
2173 | last = ", "; | |
2174 | if (compileconcat(actualp->string, formaltype) != 0) | |
2175 | return 1; | |
2176 | actualp = actualp->next; | |
2177 | } | |
2178 | putchar(fp->isarray ? ']' : ')'); | |
2179 | return 0; | |
2180 | } | |
2181 | ||
2182 | ||
2183 | int walkstring(struct string *sp, enum walkstringop op, int tempno) { | |
2184 | struct stringlist *lp; | |
2185 | struct array *ap; | |
2186 | ||
2187 | for ( ; sp != NULL; sp = sp->next) { | |
2188 | switch (sp->type) { | |
2189 | case S_ARRAY: | |
2190 | ap = sp->value.array; | |
2191 | for (lp = ap->elements; lp != NULL; lp = lp->next) | |
2192 | tempno = walkstring(lp->string, op, tempno); | |
2193 | tempno = walkstring(ap->index, op, tempno); | |
2194 | ap->tempno = ++tempno; | |
2195 | switch (op) { | |
2196 | case DECLAREARRAYS: | |
2197 | if (simplearray(ap)) { | |
2198 | indent(); | |
2199 | printf("static "); | |
2200 | compilesimplearray(&ap->type, NULL, tempno, ap); | |
2201 | } else | |
2202 | declarearray(ap); | |
2203 | break; | |
2204 | case COMPILEARRAYS: | |
2205 | if (!simplearray(ap)) | |
2206 | if (compilearray(ap) != 0) | |
2207 | return -1; | |
2208 | break; | |
2209 | default: | |
2210 | break; | |
2211 | } | |
2212 | break; | |
2213 | case S_FUNCTIONCALL: | |
2214 | for (lp = sp->value.functioncall->args; lp != NULL; lp = lp->next) | |
2215 | tempno = walkstring(lp->string, op, tempno); | |
2216 | break; | |
2217 | default: | |
2218 | break; | |
2219 | } | |
2220 | } | |
2221 | return tempno; | |
2222 | } | |
2223 | ||
2224 | ||
2225 | int compilearray(struct array *ap) { | |
2226 | struct stringlist *ep; | |
2227 | int i; | |
2228 | ||
2229 | indent(); | |
2230 | printf("switch ("); | |
2231 | if (compileconcat(ap->index, T_INTEGER) != 0) | |
2232 | return 1; | |
2233 | printf(") {\n"/*}*/); | |
2234 | for (i = 0, ep = ap->elements; ep != NULL; i++, ep = ep->next) { | |
2235 | indent(); | |
2236 | printf("case %d:\n", i); | |
2237 | indentation++; | |
2238 | if (compilecheckedstring(ap->tempno, ep->string, ap->type) != 0) | |
2239 | return 1; | |
2240 | indent(); | |
2241 | printf("break;\n"); | |
2242 | indentation--; | |
2243 | } | |
2244 | indent(); | |
2245 | printf(/*{*/"}\n"); | |
2246 | return 0; | |
2247 | } | |
2248 | ||
2249 | ||
2250 | void compilesimplearray(enum type *tp, char *name, int num, struct array *ap) { | |
2251 | struct stringlist *lp; | |
2252 | int fixedlength; | |
2253 | ||
2254 | fixedlength = (*tp == T_INTEGER) ? 0 : checkfixedlength(ap); | |
2255 | if (fixedlength > 0) | |
2256 | printf("char "); | |
2257 | else | |
2258 | compiletype(stdout, tp); | |
2259 | if (name != NULL) | |
2260 | printf(name); | |
2261 | else | |
2262 | compiletemp(num); | |
2263 | printf("[]"); | |
2264 | if (fixedlength > 0) | |
2265 | printf("[%d]", fixedlength); | |
2266 | printf(" = {\n"/*}*/); | |
2267 | indentation++; | |
2268 | for (lp = ap->elements; lp != NULL; lp = lp->next) { | |
2269 | indent(); | |
2270 | compilesimple(lp->string, lp->type); | |
2271 | printf(",\n"); | |
2272 | } | |
2273 | indentation--; | |
2274 | indent(); | |
2275 | printf(/*{*/"};\n"); | |
2276 | } | |
2277 | ||
2278 | ||
2279 | void declarearray(struct array *ap) { | |
2280 | indent(); | |
2281 | compiletype(stdout, &ap->type); | |
2282 | compiletemp(ap->tempno); | |
2283 | printf(";\n"); | |
2284 | } | |
2285 | ||
2286 | ||
2287 | void compilebitstring(struct bits *bp) { | |
2288 | printf("("); | |
2289 | if (bp->shift != 0) | |
2290 | printf("("); | |
2291 | printf("code & 0x%lx", bp->mask); | |
2292 | if (bp->shift != 0) | |
2293 | printf(") >> %d", bp->shift); | |
2294 | printf(")"); | |
2295 | } | |
2296 | ||
2297 | ||
2298 | void compilebitsplice(struct bitsplice *splicep) { | |
2299 | struct bitsplicebits *bsp; | |
2300 | char *last = ""; | |
2301 | ||
2302 | printf("("); | |
2303 | for (bsp = splicep->splice; bsp != NULL; bsp = bsp->next) { | |
2304 | printf(last); | |
2305 | last = " | "; | |
2306 | if (bsp->type == S_PARAMETER) | |
2307 | putchar(bsp->value.arg->name); | |
2308 | else { | |
2309 | assert(bsp->type == S_BITSTRING); | |
2310 | if (bsp->value.mask == 0) | |
2311 | printf("code"); | |
2312 | else | |
2313 | printf("(code & 0x%lx)", bsp->value.mask); | |
2314 | } | |
2315 | if (bsp->shift > 0) | |
2316 | printf(" << %d", bsp->shift); | |
2317 | else if (bsp->shift < 0) | |
2318 | printf(" >> %d", -bsp->shift); | |
2319 | } | |
2320 | if (splicep->entry.value != 0) | |
2321 | printf("%s0x%lx", last, splicep->entry.value); | |
2322 | printf(")"); | |
2323 | } | |
2324 | ||
2325 | ||
2326 | int bitcount(bits x) { | |
2327 | int nbits; | |
2328 | ||
2329 | for (nbits = 0; x != 0; x >>= 1) { | |
2330 | if (x & 1) | |
2331 | nbits++; | |
2332 | } | |
2333 | return nbits; | |
2334 | } | |
2335 | ||
2336 | ||
2337 | bits allbitsset(int nbits) { | |
2338 | return (nbits == MAXBITS) ? ~0 : (1 << nbits) - 1; | |
2339 | } | |
2340 | ||
2341 | ||
2342 | void findent(FILE *f) { | |
2343 | int i; | |
2344 | ||
2345 | for (i = 1; i < indentation; i += 2) | |
2346 | putc('\t', f); | |
2347 | if (i == indentation) | |
2348 | fputs(" ", f); | |
2349 | } | |
2350 | ||
2351 | ||
2352 | void indent() { | |
2353 | findent(stdout); | |
2354 | } | |
2355 | ||
2356 | ||
2357 | void *xrealloc(char *oldp, size_t size) { | |
2358 | void *p; | |
2359 | ||
2360 | if (oldp == NULL) | |
2361 | p = malloc(size); | |
2362 | else | |
2363 | p = realloc(oldp, size); | |
2364 | if (p == NULL) { | |
2365 | fprintf(stderr, "%s: allocate of %d bytes failed: %s\n", progname, | |
2366 | (int) size, strerror(errno)); | |
2367 | exit(1); | |
2368 | } | |
2369 | return p; | |
2370 | } | |
2371 | ||
2372 | ||
2373 | void *xmalloc(size_t size) { | |
2374 | return xrealloc(NULL, size); | |
2375 | } | |
2376 | ||
2377 | ||
2378 | void *xstrdup(char *s) { | |
2379 | char *p; | |
2380 | ||
2381 | p = xmalloc(strlen(s) + 1); | |
2382 | strcpy(p, s); | |
2383 | return p; | |
2384 | } | |
2385 | ||
2386 | ||
2387 | int prematureeof() { | |
2388 | fprintf(stderr, "%s: %s(%d): premature end of file\n", progname, filename, | |
2389 | lineno); | |
2390 | return 1; | |
2391 | } |