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