diff options
-rw-r--r-- | mh/fmtcheck.c | 12 | ||||
-rw-r--r-- | mh/mh.h | 2 | ||||
-rw-r--r-- | mh/mh_format.c | 167 | ||||
-rw-r--r-- | mh/tests/fmtcomp.at | 228 |
4 files changed, 286 insertions, 123 deletions
diff --git a/mh/fmtcheck.c b/mh/fmtcheck.c index 8c8509744..b0d7d37e2 100644 --- a/mh/fmtcheck.c +++ b/mh/fmtcheck.c @@ -31,6 +31,7 @@ static int debug_option; static char *input_file; static size_t width; static size_t msgno; +static int pc_option; void opt_formfile (struct mu_parseopt *po, struct mu_option *opt, char const *arg) @@ -58,12 +59,15 @@ static struct mu_option options[] = { { "format", 0, N_("FORMAT"), MU_OPTION_DEFAULT, N_("use this format string"), mu_c_string, NULL, opt_format }, - { "dump", 0, NULL, MU_OPTION_HIDDEN, + { "dump", 0, NULL, MU_OPTION_DEFAULT, N_("dump the listing of compiled format code"), mu_c_bool, &dump_option }, - { "disassemble", 0, NULL, MU_OPTION_HIDDEN, + { "disassemble", 0, NULL, MU_OPTION_DEFAULT, N_("dump disassembled format code"), mu_c_bool, &disass_option }, + { "pc", 0, NULL, MU_OPTION_DEFAULT, + N_("print program counter along with disassembled code (implies --disassemble)"), + mu_c_bool, &pc_option }, { "debug", 0, NULL, MU_OPTION_DEFAULT, N_("enable parser debugging output"), mu_c_bool, &debug_option }, @@ -94,6 +98,8 @@ int main (int argc, char **argv) { mh_getopt (&argc, &argv, options, 0, args_doc, prog_doc, NULL); + if (pc_option) + disass_option = 1; switch (argc) { case 0: @@ -123,7 +129,7 @@ main (int argc, char **argv) if (dump_option) mh_format_dump_code (format); if (disass_option) - mh_format_dump_disass (format); + mh_format_dump_disass (format, pc_option); if (input_file) run (); @@ -182,7 +182,7 @@ void mh_fvm_run (mh_fvm_t fvm, mu_message_t msg, size_t msgno); int mh_format_str (mh_format_t fmt, char *str, size_t width, char **pret); void mh_format_dump_code (mh_format_t fmt); -void mh_format_dump_disass (mh_format_t fmt); +void mh_format_dump_disass (mh_format_t fmt, int addr); #define MH_FMT_PARSE_DEFAULT 0 #define MH_FMT_PARSE_TREE 0x01 diff --git a/mh/mh_format.c b/mh/mh_format.c index 86eeb4ff3..0f1d4b728 100644 --- a/mh/mh_format.c +++ b/mh/mh_format.c @@ -1896,8 +1896,128 @@ _get_builtin_name (mh_builtin_fp ptr) return NULL; } +/* Label array is used when disassembling the code, in order to create. + meaningful label names. The array elements starting from index 1 keep + the code addesses to which branch instructions point, in ascending order. + Element 0 keeps the number of addresses stored. Thus, the label + array LAB with contents { 3, 2, 5, 7 } declares three labels: "L1" on + address 2, "L2", on address 5, and "L3" on address 7. +*/ + +/* Find in LAB the index of the label corresponding to the given PC. Return + 0 if no label found. */ +size_t +find_label (size_t *lab, size_t pc) +{ + if (lab) + { + size_t i; + for (i = 1; i <= lab[0]; i++) + { + if (lab[i] == pc) + return i; + } + } + return 0; +} + +static int +comp_pc (const void *a, const void *b) +{ + size_t pca = *(size_t*)a; + size_t pcb = *(size_t*)b; + if (pca < pcb) + return -1; + else if (pca > pcb) + return 1; + return 0; +} + +/* Extract a label array from a compiled format FMT. */ +static size_t * +extract_labels (mh_format_t fmt) +{ + size_t *lab; + size_t pc; + long n; + + lab = mu_calloc (fmt->progcnt, sizeof (lab[0])); + lab[0] = 0; + for (pc = 1; pc < fmt->progcnt; ) + { + mh_opcode_t opcode = MHI_OPCODE (fmt->prog[pc++]); + if (opcode == mhop_stop) + break; + switch (opcode) + { + case mhop_branch: + case mhop_brzn: + case mhop_brzs: + n = MHI_NUM (fmt->prog[pc++]); + if (!find_label (lab, pc + n - 1)) + lab[++lab[0]] = pc + n - 1; + break; + + case mhop_setn: + pc += 2; + break; + + case mhop_sets: + case mhop_ldcomp: + pc += 2 + MHI_NUM (fmt->prog[pc + 1]); + break; + + case mhop_movn: + case mhop_movs: + pc += 2; + break; + + case mhop_ldbody: + case mhop_call: + case mhop_fmtspec: + pc++; + break; + + case mhop_printlit: + pc += 1 + MHI_NUM (fmt->prog[pc]); + break; + + case mhop_atoi: + case mhop_itoa: + case mhop_printn: + case mhop_prints: + break; + + default: + abort (); + } + } + if (lab[0] > 0) + qsort (lab + 1, lab[0], sizeof lab[0], comp_pc); + return lab; +} + +/* Print to *PBUF (of size *PSZ) the label corresponding to the address PC. + If there's no label having this address (in particular, if LAB==NULL), + format the address itself to *PBUF. + Reallocate *PBUF, updating *PSZ, if necessary. +*/ void -mh_format_dump_disass (mh_format_t fmt) +format_label (size_t *lab, size_t pc, char **pbuf, size_t *psz) +{ + size_t ln = find_label (lab, pc); + if (ln) + mu_asnprintf (pbuf, psz, "L%ld", (long) ln); + else + mu_asnprintf (pbuf, psz, "%ld", (long) pc); +} + +/* Dump disassembled code of FMT to stdout. If ADDR is 0, print label names + where necessary, otherwise, prefix each line of output with its program + counter in decimal. +*/ +void +mh_format_dump_disass (mh_format_t fmt, int addr) { mh_instr_t *prog = fmt->prog; size_t pc = 1; @@ -1908,14 +2028,46 @@ mh_format_dump_disass (mh_format_t fmt) [R_ACC] = "acc" }; static char c_trans[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; + size_t *lab; + size_t lc; + char *lbuf = NULL; + size_t lsz = 0; if (!prog) return; + + if (!addr) + lab = extract_labels (fmt); + else + lab = NULL; + lc = lab ? 1 : 0; + while (!stop) { mh_opcode_t opcode; - printf ("% 4.4ld: ", (long) pc); + if (addr) + printf ("% 4.4ld: ", (long) pc); + else + { + int w = 0; + if (lc <= lab[0] && lab[lc] == pc) + { + w = printf ("L%ld:", (long) lc); + lc++; + } + if (w > 8) + { + putchar ('\n'); + w = 0; + } + while (w < 8) + { + putchar (' '); + w++; + } + } + switch (opcode = MHI_OPCODE (prog[pc++])) { case mhop_stop: @@ -1926,21 +2078,24 @@ mh_format_dump_disass (mh_format_t fmt) case mhop_branch: { long n = MHI_NUM (prog[pc++]); - printf ("branch %ld", pc + n - 1); + format_label (lab, pc + n - 1, &lbuf, &lsz); + printf ("branch %s", lbuf); } break; case mhop_brzn: { long n = MHI_NUM (prog[pc++]); - printf ("brzn %ld", pc + n - 1); + format_label (lab, pc + n - 1, &lbuf, &lsz); + printf ("brzn %s", lbuf); } break; case mhop_brzs: { long n = MHI_NUM (prog[pc++]); - printf ("brzs %ld", pc + n - 1); + format_label (lab, pc + n - 1, &lbuf, &lsz); + printf ("brzs %s", lbuf); } break; @@ -2049,6 +2204,8 @@ mh_format_dump_disass (mh_format_t fmt) } printf ("\n"); } + free (lbuf); + free (lab); } void diff --git a/mh/tests/fmtcomp.at b/mh/tests/fmtcomp.at index 687f54bfc..b0be1a20d 100644 --- a/mh/tests/fmtcomp.at +++ b/mh/tests/fmtcomp.at @@ -31,105 +31,105 @@ AT_CLEANUP]) FMTCOMP([literal], [text], [PRINT("text") - 0001: printlit "text" - 0006: stop + printlit "text" + stop ]) FMTCOMP([component], [%{from}], [PRINT(COMPONENT.from) - 0001: ldcomp reg, "from" - 0007: prints - 0008: stop + ldcomp reg, "from" + prints + stop ]) FMTCOMP([component formatted], [%-40{from}], [FORMAT(RALIGN|NOZEROPAD|NOCOMPWS, 40, COMPONENT.from) - 0001: ldcomp reg, "from" - 0007: fmtspec RALIGN|NOZEROPAD|NOCOMPWS, 40 - 0009: prints - 0010: stop + ldcomp reg, "from" + fmtspec RALIGN|NOZEROPAD|NOCOMPWS, 40 + prints + stop ]) FMTCOMP([function call], [%(msg)], [PRINT(msg()) - 0001: call msg - 0003: printn - 0004: stop + call msg + printn + stop ]) FMTCOMP([function call formatted], [%08(msg)], [FORMAT(NORALIGN|ZEROPAD|NOCOMPWS, 8, msg()) - 0001: call msg - 0003: fmtspec NORALIGN|ZEROPAD|NOCOMPWS, 8 - 0005: printn - 0006: stop + call msg + fmtspec NORALIGN|ZEROPAD|NOCOMPWS, 8 + printn + stop ]) FMTCOMP([function call with literal argument], [%(getenv PATH)], [PRINT(getenv("PATH")) - 0001: sets arg, "PATH" - 0007: call getenv - 0009: prints - 0010: stop + sets arg, "PATH" + call getenv + prints + stop ]) FMTCOMP([function call with numeric argument], [%(plus 10)], [PRINT(plus(10)) - 0001: setn arg, 10 - 0004: call plus - 0006: printn - 0007: stop + setn arg, 10 + call plus + printn + stop ]) FMTCOMP([function call with numeric argument and format spec], [%08(plus 10)], [FORMAT(NORALIGN|ZEROPAD|NOCOMPWS, 8, plus(10)) - 0001: setn arg, 10 - 0004: call plus - 0006: fmtspec NORALIGN|ZEROPAD|NOCOMPWS, 8 - 0008: printn - 0009: stop + setn arg, 10 + call plus + fmtspec NORALIGN|ZEROPAD|NOCOMPWS, 8 + printn + stop ]) FMTCOMP([function call with component argument], [%(decode{subject})], [PRINT(decode(COMPONENT.subject)) - 0001: ldcomp reg, "subject" - 0008: movs arg, reg - 0011: call decode - 0013: prints - 0014: stop + ldcomp reg, "subject" + movs arg, reg + call decode + prints + stop ]) FMTCOMP([nested function calls], [%(null(decode{subject}))], [PRINT(null(decode(COMPONENT.subject))) - 0001: ldcomp reg, "subject" - 0008: movs arg, reg - 0011: call decode - 0013: movs arg, reg - 0016: call null - 0018: printn - 0019: stop + ldcomp reg, "subject" + movs arg, reg + call decode + movs arg, reg + call null + printn + stop ]) FMTCOMP([nested function calls with typecast], [%(zero(decode{subject}))], [PRINT(zero(NUM(decode(COMPONENT.subject)))) - 0001: ldcomp reg, "subject" - 0008: movs arg, reg - 0011: call decode - 0013: atoi - 0014: movn arg, reg - 0017: call zero - 0019: printn - 0020: stop + ldcomp reg, "subject" + movs arg, reg + call decode + atoi + movn arg, reg + call zero + printn + stop ]) FMTCOMP([lit], @@ -140,26 +140,26 @@ FMTCOMP([lit], PRINT(lit("10")) PRINT(lit(["(comp"])) PRINT(lit("")) - 0001: sets reg, "string" - 0007: prints - 0008: sets reg, "10" - 0013: prints - 0014: sets reg, ["(comp"] - 0020: prints - 0021: sets reg, "" - 0026: prints - 0027: stop + sets reg, "string" + prints + sets reg, "10" + prints + sets reg, ["(comp"] + prints + sets reg, "" + prints + stop ]) FMTCOMP([num], [%(num 10)%(num)], [PRINT(num(10)) PRINT(num(0)) - 0001: setn reg, 10 - 0004: printn - 0005: setn reg, 0 - 0008: printn - 0009: stop + setn reg, 10 + printn + setn reg, 0 + printn + stop ]) FMTCOMP([simple conditional], @@ -167,13 +167,13 @@ FMTCOMP([simple conditional], [IF (COMPONENT.replied) THEN PRINT("-") FI - 0001: ldcomp reg, "replied" - 0008: brzs 16 - 0010: printlit "-" - 0014: branch 24 - 0016: setn reg, 0 - 0019: sets reg, "" - 0024: stop + ldcomp reg, "replied" + brzs L1 + printlit "-" + branch L2 +L1: setn reg, 0 + sets reg, "" +L2: stop ],[],[-format]) FMTCOMP([if-else], @@ -183,12 +183,12 @@ FMTCOMP([if-else], ELSE PRINT("+") FI - 0001: ldcomp reg, "replied" - 0008: brzs 16 - 0010: printlit "-" - 0014: branch 20 - 0016: printlit "+" - 0020: stop + ldcomp reg, "replied" + brzs L1 + printlit "-" + branch L2 +L1: printlit "+" +L2: stop ]) FMTCOMP([if-elsif-else], @@ -202,16 +202,16 @@ ELSE PRINT(" ") FI FI - 0001: ldcomp reg, "replied" - 0008: brzs 16 - 0010: printlit "-" - 0014: branch 35 - 0016: ldcomp reg, "encrypted" - 0023: brzs 31 - 0025: printlit "E" - 0029: branch 35 - 0031: printlit " " - 0035: stop + ldcomp reg, "replied" + brzs L1 + printlit "-" + branch L3 +L1: ldcomp reg, "encrypted" + brzs L2 + printlit "E" + branch L3 +L2: printlit " " +L3: stop ]) # The example below is taken from mh-format(1), subsection @@ -221,28 +221,28 @@ FI FMTCOMP([inline conditional], [%(formataddr %<{reply-to}%|%{from}%>)], [formataddr(IF (COMPONENT.reply-to) THEN; ; ELSE PRINT(COMPONENT.from); FI) - 0001: movs acc, reg - 0004: ldcomp reg, "reply-to" - 0011: brzs 15 - 0013: branch 22 - 0015: ldcomp reg, "from" - 0021: prints - 0022: movs arg, reg - 0025: call formataddr - 0027: stop + movs acc, reg + ldcomp reg, "reply-to" + brzs L1 + branch L2 +L1: ldcomp reg, "from" + prints +L2: movs arg, reg + call formataddr + stop ]) FMTCOMP([inline conditional (2)], [%(formataddr %<{reply-to}%|%(void{from})%>)], [formataddr(IF (COMPONENT.reply-to) THEN; ; ELSE COMPONENT.from; FI) - 0001: movs acc, reg - 0004: ldcomp reg, "reply-to" - 0011: brzs 15 - 0013: branch 21 - 0015: ldcomp reg, "from" - 0021: movs arg, reg - 0024: call formataddr - 0026: stop + movs acc, reg + ldcomp reg, "reply-to" + brzs L1 + branch L2 +L1: ldcomp reg, "from" +L2: movs arg, reg + call formataddr + stop ]) FMTCOMP([statement list], @@ -250,17 +250,17 @@ FMTCOMP([statement list], [formataddr(IF (COMPONENT.reply-to) THEN; ; ELSE COMPONENT.from; FI) width() putaddr("To: ") - 0001: movs acc, reg - 0004: ldcomp reg, "reply-to" - 0011: brzs 15 - 0013: branch 21 - 0015: ldcomp reg, "from" - 0021: movs arg, reg - 0024: call formataddr - 0026: call width - 0028: sets arg, "To: " - 0034: call putaddr - 0036: stop + movs acc, reg + ldcomp reg, "reply-to" + brzs L1 + branch L2 +L1: ldcomp reg, "from" +L2: movs arg, reg + call formataddr + call width + sets arg, "To: " + call putaddr + stop ]) m4_popdef[FMTCOMP]) |