|
|
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.