1 From: Tony Balinski <ajbj@free.fr>
2 Subject: Provide NEdit Macro stack traces
6 http://sourceforge.net/tracker/index.php?func=detail&aid=970501&group_id=11005&atid=311005
7 [ 970501 ] Provide NEdit Macro stack traces
8 InterpretDebug.diff 2004-06-10 11:51
10 Macro function names are listed when a crash occurs in one of your macros.
11 The usual error message is followed by a list of the NEdit macro functions
12 called before getting there. (It doesn't tell you how the macro was invoked
13 however.) This provides a good clue as to where a macro programming problem
16 Also, debug tracing enhanced to show symbol values in stack traces listed to
17 terminal output: a boon to interpret.c hackers.
19 Try changing the definition
21 #define STACKDUMP(n, x) stackdump(n, x)
25 #define STACKDUMP(n, x) stackdump(n, x + 50)
27 and watching the output of NEdit in an xterm generated while running your
30 (You will need to add -DDEBUG_STACK and -DDEBUG_ASSEMBLY in your compilation
31 flags to enable the debug tracing.)
33 Thanks to Eddy De Greef!
35 InterpretDebug2.diff 2004-06-11 17:13
37 This version passes an extra "name" string to ParseMacro(). This name is
38 used as a "function name" in the stack dumps, when there is no available
39 function symbol name available (usually at the top level of invocation from
40 NEdit's user interface). It allows the user to determine which macro is
41 being invoked or which file is being interpreted when an error occurs.
45 source/interpret.c | 404 +++++++++++++++++++++++++++++++++++++++++---------
46 source/interpret.h | 2
51 source/parse_noyacc.c | 9 -
52 source/smartIndent.c | 22 +-
53 source/userCmds.c | 49 +++---
54 9 files changed, 404 insertions(+), 108 deletions(-)
56 diff --quilt old/source/interpret.c new/source/interpret.c
57 --- old/source/interpret.c
58 +++ new/source/interpret.c
59 @@ -38,7 +38,9 @@ static const char CVSID[] = "$Id: interp
69 @@ -104,7 +106,10 @@ static const char *tagToStr(enum typeTag
71 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
72 #define DEBUG_DISASSEMBLER
73 +static const char *printd(const char *f, ...);
74 +static int outPrintd();
75 static void disasm(Inst *inst, int nInstr);
76 +static void disasmInternal(Inst *inst, int nInstr);
77 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
79 #ifdef DEBUG_ASSEMBLY /* for disassembly */
80 @@ -115,6 +120,7 @@ static void disasm(Inst *inst, int nInst
82 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
83 static void stackdump(int n, int extra);
84 +static void stackdumpInternal(int n, int extra);
85 #define STACKDUMP(n, x) stackdump(n, x)
86 #define DISASM_RT(i, n) disasm(i, n)
87 #else /* #ifndef DEBUG_STACK */
88 @@ -172,14 +178,18 @@ static int (*OpFns[])() = {
91 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
92 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
93 +#define FP_ARG_ARRAY_INDEX (-1)
94 #define FP_ARG_COUNT_INDEX (-2)
95 -#define FP_OLD_FP_INDEX (-3)
96 -#define FP_RET_PC_INDEX (-4)
97 -#define FP_PROG_INDEX (-5)
98 -#define FP_TO_ARGS_DIST (5) /* should be 0 - (above index) */
99 +#define FP_FUNCTION_NAME (-3) /* !! */
100 +#define FP_SYMBOL_TABLE (-4) /* !! */
101 +#define FP_OLD_FP_INDEX (-5)
102 +#define FP_RET_PC_INDEX (-6)
103 +#define FP_PROG_INDEX (-7)
105 +#define FP_TO_ARGS_DIST (0 - FP_PROG_INDEX) /* should be 0 - (above index) */
107 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
108 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
109 +#define FP_GET_ARG_ARRAY(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
110 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
111 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
112 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
113 @@ -267,6 +277,7 @@ Program *FinishCreatingProgram(Accumulat
114 newProg->code = (Inst *)XtMalloc(progLen);
115 memcpy(newProg->code, Prog, progLen);
116 newProg->localSymList = LocalSymList;
117 + newProg->name = NULL;
118 newProg->refcount = 1;
120 /* Local variables' values are stored on the stack. Here we assign
121 @@ -291,6 +302,7 @@ void FreeProgram(Program *prog)
122 if (--prog->refcount == 0) {
123 freeSymbolTable(prog->localSymList);
124 XtFree((char *)prog->code);
125 + XtFree((char *)prog->name);
126 XtFree((char *)prog);
129 @@ -441,7 +453,8 @@ void FillLoopAddrs(Inst *breakAddr, Inst
130 ** helper function to setup the next frame
132 static void setupFrame(DataValue **frameP, DataValue **stackP,
133 - Inst **pc, Program *prog, int nArgs, DataValue *args, int passProg)
134 + Inst **pc, Program *prog, int nArgs, DataValue *args, int passProg,
137 static DataValue noValue = {NO_TAG, {0}};
139 @@ -475,6 +488,17 @@ static void setupFrame(DataValue **frame
140 (*stackP)->val.dataval = *frameP;
144 + (*stackP)->tag = NO_TAG;
145 + (*stackP)->val.sym = prog->localSymList;
149 + (*stackP)->tag = STRING_TAG;
150 + (*stackP)->val.str.rep = name;
151 + (*stackP)->val.str.len = strlen(name);
155 (*stackP)->tag = NO_TAG;
156 (*stackP)->val.n = nArgs;
157 @@ -551,7 +575,7 @@ int ExecuteMacro(WindowInfo *window, Pro
158 /* pre-set the return PC to NULL */
160 setupFrame(&context->frameP, &context->stackP, &context->pc,
161 - prog, nArgs, args, False);
162 + prog, nArgs, args, False, prog->name ? prog->name : "<exec-macro>");
164 /* Begin execution, return on error or preemption */
165 return ContinueMacro(context, result, msg);
166 @@ -627,7 +651,8 @@ int ContinueMacro(RestartData *continuat
168 void RunMacroAsSubrCall(Program *prog)
170 - setupFrame(&FrameP, &StackP, &PC, prog, 0, NULL, True);
171 + setupFrame(&FrameP, &StackP, &PC, prog, 0, NULL, True,
172 + prog->name ? prog->name : "<run-macro>");
175 void FreeRestartData(RestartData *context)
176 @@ -1419,7 +1444,7 @@ static int pushArgArray(void)
179 nArgs = FP_GET_ARG_COUNT(FrameP);
180 - resultArray = &FP_GET_ARG_ARRAY_CACHE(FrameP);
181 + resultArray = &FP_GET_ARG_ARRAY(FrameP);
182 if (resultArray->tag != ARRAY_TAG) {
183 resultArray->tag = ARRAY_TAG;
184 resultArray->val.arrayPtr = ArrayNew();
185 @@ -2184,7 +2209,7 @@ static int callSubroutine(void)
186 prog = sym->value.val.prog;
188 /* -nArgs means 'arguments are on stack' */
189 - setupFrame(&FrameP, &StackP, &PC, prog, -nArgs, NULL, True);
190 + setupFrame(&FrameP, &StackP, &PC, prog, -nArgs, NULL, True, sym->name);
194 @@ -2712,7 +2737,7 @@ static int arrayRef(void)
198 - STACKDUMP(nDim, 3);
199 + STACKDUMP(nDim+1, 3);
202 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
203 @@ -2763,7 +2788,7 @@ static int arrayAssign(void)
207 - STACKDUMP(nDim, 3);
208 + STACKDUMP(nDim+2, 3);
212 @@ -2801,9 +2826,9 @@ static int arrayAssign(void)
213 ** for use with assign-op operators (eg a[i,j] += k
215 ** Before: Prog-> [binOp], nDim, next, ...
216 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
217 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
218 ** After: Prog-> binOp, nDim, [next], ...
219 -** TheStack-> [rhs], arrayValue, next, ...
220 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
222 static int arrayRefAndAssignSetup(void)
224 @@ -2818,7 +2843,7 @@ static int arrayRefAndAssignSetup(void)
228 - STACKDUMP(nDim + 1, 3);
229 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
233 @@ -3072,6 +3097,59 @@ static int errCheck(const char *s)
237 +** build a stack dump string, reallocating s as necessary.
239 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
244 + DataValue *nfp = fp;
249 + disasmInternal(PC - 1, 1);
250 + stackdumpInternal(0, 50);
251 + dump = printd(NULL);
254 + /* first measure the lengths */
255 + len = strlen(msg) + 1;
256 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
257 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
260 + len += strlen(dump);
264 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
273 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
275 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
290 ** combine two strings in a static area and set ErrMsg to point to the
291 ** result. Returns false so a single return execError() statement can
292 ** be used to both process the message and return.
293 @@ -3079,9 +3157,11 @@ static int errCheck(const char *s)
294 static int execError(const char *s1, const char *s2)
296 static char msg[MAX_ERR_MSG_LEN];
297 + static char *err = NULL;
298 + static int errlen = 0;
300 sprintf(msg, s1, s2);
302 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
306 @@ -3131,11 +3211,83 @@ static const char *tagToStr(enum typeTag
309 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
310 +static char *printdBuffer = NULL;
311 +static int printdPos = 0;
312 +static int printdSize = 0;
314 +static const char *printd(const char *f, ...)
322 + printdPos = 0; /* reset for next time */
323 + return printdBuffer;
327 + vsprintf(buffer, f, args);
330 + len = strlen(buffer);
334 + printdBuffer = XtMalloc(printdSize);
339 + int needSize = printdPos + len + 1;
340 + if (needSize > printdSize)
342 + int newSize = printdSize;
343 + while (newSize < needSize)
345 + printdBuffer = XtRealloc(printdBuffer, newSize);
346 + printdSize = newSize;
349 + strcpy(&printdBuffer[printdPos], buffer);
352 + return printdBuffer;
357 + const char *s = printd(NULL);
360 + static int outIsTTY = -1;
361 + if (outIsTTY == -1)
362 + outIsTTY = isatty(fileno(stdout));
366 + for (cp = s; *cp; cp++)
368 + printf("\033[K\n");
374 + for (cp = s; *cp; cp++)
379 +#endif /* #ifdef DEBUG_DISASSEMBLER */
381 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
382 static void dumpVal(DataValue dv)
386 - printf("i=%d", dv.val.n);
387 + printd("i=%d", dv.val.n);
391 @@ -3143,38 +3295,38 @@ static void dumpVal(DataValue dv)
393 char *src = dv.val.str.rep;
395 - printf("s=<NULL>");
396 + printd("s=<NULL>");
399 for (k = 0; src[k] && k < sizeof s - 1; k++) {
400 s[k] = isprint(src[k]) ? src[k] : '?';
403 - printf("s=\"%s\"%s[%d]", s,
404 + printd("s=\"%s\"%s[%d]", s,
405 src[k] ? "..." : "", strlen(src));
411 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
415 - printf("<no value>");
416 + printd("<no value>");
419 - printf("?%8p", dv.val.inst);
420 + printd("?%8p", dv.val.inst);
424 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
425 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
429 #endif /* #ifdef DEBUG_DISASSEMBLER */
431 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
432 -static void disasm(Inst *inst, int nInstr)
433 +static void disasmInternal(Inst *inst, int nInstr)
435 static const char *opNames[] = {
436 #define OP(name, fn) #name,
437 @@ -3183,15 +3335,15 @@ static void disasm(Inst *inst, int nInst
443 for (i = 0; i < nInstr; ++i) {
444 - printf("Prog %8p ", &inst[i]);
445 + printd("Prog %8p ", &inst[i]);
446 for (j = 0; j < N_OPS; ++j) {
447 if (inst[i].func == OpFns[j]) {
448 - printf("%22s ", opNames[j]);
449 + printd("%22s ", opNames[j]);
450 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
451 Symbol *sym = inst[i+1].sym;
452 - printf("%s", sym->name);
453 + printd("%s", sym->name);
454 if (sym->value.tag == STRING_TAG &&
455 strncmp(sym->name, "string #", 8) == 0) {
457 @@ -3199,29 +3351,29 @@ static void disasm(Inst *inst, int nInst
460 else if (j == OP_PUSH_IMMED) {
461 - printf("%d", inst[i+1].value);
462 + printd("%d", inst[i+1].value);
465 else if (j == OP_BRANCH || j == OP_BRANCH_FALSE ||
466 j == OP_BRANCH_NEVER || j == OP_BRANCH_TRUE) {
467 - printf("to=(%d) %p", inst[i+1].value,
468 + printd("to=(%d) %p", inst[i+1].value,
469 &inst[i+1] + inst[i+1].value);
472 else if (j == OP_CONCAT) {
473 - printf("nExpr=%d", inst[i+1].value);
474 + printd("nExpr=%d", inst[i+1].value);
477 else if (j == OP_SUBR_CALL) {
478 - printf("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
479 + printd("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
482 else if (j == OP_BEGIN_ARRAY_ITER) {
483 - printf("%s in", inst[i+1].sym->name);
484 + printd("%s in", inst[i+1].sym->name);
487 else if (j == OP_ARRAY_ITER) {
488 - printf("%s = %s++ end-loop=(%d) %p",
489 + printd("%s = %s++ end-loop=(%d) %p",
492 inst[i+3].value, &inst[i+3] + inst[i+3].value);
493 @@ -3229,68 +3381,182 @@ static void disasm(Inst *inst, int nInst
495 else if (j == OP_ARRAY_REF || j == OP_ARRAY_DELETE ||
496 j == OP_ARRAY_ASSIGN) {
497 - printf("nDim=%d", inst[i+1].value);
498 + printd("nDim=%d", inst[i+1].value);
501 else if (j == OP_ARRAY_REF_ASSIGN_SETUP) {
502 - printf("binOp=%s ", inst[i+1].value ? "true" : "false");
503 - printf("nDim=%d", inst[i+2].value);
504 + printd("binOp=%s ", inst[i+1].value ? "true" : "false");
505 + printd("nDim=%d", inst[i+2].value);
508 else if (j == OP_PUSH_ARRAY_SYM) {
509 - printf("%s", inst[++i].sym->name);
510 - printf(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
511 + printd("%s", inst[++i].sym->name);
512 + printd(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
522 - printf("%x\n", inst[i].value);
523 + printd("%x\n", inst[i].value);
528 +static void disasm(Inst *inst, int nInstr)
530 + static int outIsTTY = -1;
531 + if (outIsTTY == -1) outIsTTY = isatty(fileno(stdout));
532 + if (outIsTTY) { printd("\033[H"); }
533 + disasmInternal(inst, nInstr);
534 + if (outIsTTY) { printd("\033[J\n"); }
537 #endif /* #ifdef DEBUG_DISASSEMBLER */
539 #ifdef DEBUG_STACK /* for run-time stack dumping */
540 -#define STACK_DUMP_ARG_PREFIX "Arg"
541 -static void stackdump(int n, int extra)
543 - /* TheStack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
544 - int nArgs = FP_GET_ARG_COUNT(FrameP);
546 - char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
547 - printf("Stack ----->\n");
548 - for (i = 0; i < n + extra; i++) {
550 - DataValue *dv = &StackP[-i - 1];
551 - if (dv < TheStack) {
552 - printf("--------------Stack base--------------\n");
554 +#define STACK_DUMP_ARG_PREFIX " $"
555 +static void stackdumpframe(DataValue *arrow, DataValue *outpt, DataValue *fp,
556 + DataValue *sp, char topMark)
558 + DataValue *baseF = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
559 + DataValue *oldFP = baseF ? baseF->val.dataval : NULL;
560 + DataValue *arg1 = &FP_GET_ARG_N(fp, 0);
561 + DataValue *fnNm = &FP_GET_ITEM(fp, FP_FUNCTION_NAME);
563 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
564 + int nArgs = FP_GET_ARG_COUNT(fp);
567 + static int symLen = 0;
568 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
571 +#ifdef DEBUG_STACK_HEADFIRST
573 + /* do caller's frame */
574 + if (oldFP || arg1 > endDv)
575 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
576 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
578 + /* do current frame */
579 + /* how many symbols are there? */
580 + for (sym = syms, nSyms = 0; sym != NULL; sym = sym->next) {
583 + int len = strlen(sym->name);
589 - offset = dv - FrameP;
592 + /* output instructions between endDv and sp - 1 inclusive */
593 +#ifdef DEBUG_STACK_HEADFIRST
595 + while (--dv >= endDv)
597 + for (dv = endDv; dv < sp; dv++)
598 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
600 + const char *posFmt = "%-6s ";
601 + const char *symName = "";
603 - printf("%4.4s", i < n ? ">>>>" : "");
604 - printf("%8p ", dv);
606 + char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
607 + int offset = dv - fp;
608 + const char *leadIn = (dv >= arrow) ? ">>>>" :
609 + (dv == arg1) ? "----" :
610 + (dv == fnNm) ? "====" : "";
611 + printd("%4.4s", leadIn);
612 + printd("%8p%c", dv, topMark);
614 - case 0: pos = "FrameP"; break; /* first local symbol value */
615 - case FP_ARG_ARRAY_CACHE_INDEX: pos = "args"; break; /* arguments array */
616 - case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* number of arguments */
617 - case FP_OLD_FP_INDEX: pos = "OldFP"; break;
618 - case FP_RET_PC_INDEX: pos = "RetPC"; break;
619 - case FP_PROG_INDEX: pos = "Prog"; break;
620 + case FP_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
621 + case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
622 + case FP_FUNCTION_NAME: pos = "FnName"; break;
623 + case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
624 + case FP_OLD_FP_INDEX: pos = "OldFP"; break;
625 + case FP_RET_PC_INDEX: pos = "RetPC"; break;
626 + case FP_PROG_INDEX: pos = "Prog"; break;
628 - if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
629 + if (offset < -FP_TO_ARGS_DIST &&
630 + offset >= -FP_TO_ARGS_DIST - nArgs)
632 sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
633 offset + FP_TO_ARGS_DIST + nArgs + 1);
635 + else if (0 <= offset && offset < nSyms) {
636 + sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
639 + else if (offset == 0) {
644 - printf("%-6s ", pos);
647 + printd(posFmt, pos);
649 + /* local symbol names? */
650 + if (0 <= offset && offset < nSyms) {
651 + for (sym = syms; sym != NULL; sym = sym->next) {
652 + if (sym->value.val.n == offset) {
653 + symName = sym->name;
658 + printd("%-*.*s ", symLen, symLen, symName);
660 + if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
661 + printd("%s", dv->val.str.rep);
668 +#ifdef DEBUG_STACK_HEADFIRST
669 + /* do caller's frame */
670 + if (oldFP || arg1 > endDv)
671 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
673 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
676 +static void stackdumpInternal(int n, int extra)
678 + DataValue *arrow = StackP - n;
679 + DataValue *outpt = StackP - n - extra;
681 +#ifdef DEBUG_STACK_HEADFIRST
682 + printd("Stack ----->\n");
683 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
684 + if (outpt < TheStack)
685 + printd("--------------Stack base--------------\n");
687 + if (outpt < TheStack)
688 + printd("--------------Stack base--------------\n");
689 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
690 + printd("Stack ----->\n");
691 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
694 +static void stackdump(int n, int extra)
696 + static int outIsTTY = -1;
697 + if (outIsTTY == -1)
698 + outIsTTY = isatty(fileno(stdout));
700 + stackdumpInternal(n, extra);
703 + printd("\033[J\n");
709 #endif /* ifdef DEBUG_STACK */
710 diff --quilt old/source/interpret.h new/source/interpret.h
711 --- old/source/interpret.h
712 +++ new/source/interpret.h
713 @@ -86,6 +86,7 @@ typedef struct DataValueTag {
715 struct DataValueTag* dataval;
716 struct SparseArrayEntryTag *arrayPtr;
717 + struct SymbolRec *sym;
721 @@ -107,6 +108,7 @@ typedef struct ProgramTag {
722 Symbol *localSymList;
728 /* Information needed to re-start a preempted macro */
729 diff --quilt old/source/macro.c new/source/macro.c
730 --- old/source/macro.c
731 +++ new/source/macro.c
732 @@ -842,7 +842,8 @@ void Replay(WindowInfo *window)
733 window->macroCmdData == NULL) {
734 /* Parse the replay macro (it's stored in text form) and compile it into
735 an executable program "prog" */
736 - prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False);
737 + prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False,
741 "NEdit internal error, learn/replay macro syntax error: %s\n",
742 @@ -940,7 +941,7 @@ static int readCheckMacroString(Widget d
743 char *stoppedAt, *errMsg;
746 - prog = ParseMacro(string, &errMsg, &stoppedAt, True);
747 + prog = ParseMacro(string, &errMsg, &stoppedAt, True, errIn);
749 if (errPos != NULL) {
751 @@ -1226,7 +1227,7 @@ void DoMacro(WindowInfo *window, const c
752 tMacro[macroLen+1] = '\0';
754 /* Parse the macro and report errors if it fails */
755 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
756 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, errInName);
758 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
760 @@ -1490,7 +1491,7 @@ selEnd += $text_length - startLength\n}\
761 sprintf(loopedCmd, loopMacro, how, command);
763 /* Parse the resulting macro into an executable program "prog" */
764 - prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False);
765 + prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False, "repeat macro");
767 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
769 diff --quilt old/source/nedit.c new/source/nedit.c
770 --- old/source/nedit.c
771 +++ new/source/nedit.c
772 @@ -832,10 +832,10 @@ static int checkDoMacroArg(const char *m
773 tMacro[macroLen+1] = '\0';
775 /* Do a test parse */
776 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
777 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, "-do macro");
780 - ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
781 + ParseError(NULL, tMacro, stoppedAt, "-do macro", errMsg);
785 diff --quilt old/source/parse.h new/source/parse.h
786 --- old/source/parse.h
787 +++ new/source/parse.h
790 #include "interpret.h"
792 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine);
793 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
796 #endif /* NEDIT_PARSE_H_INCLUDED */
797 diff --quilt old/source/parse.y new/source/parse.y
798 --- old/source/parse.y
799 +++ new/source/parse.y
800 @@ -625,10 +625,12 @@ blank: /* nothing */
801 ** as a pointer to a static string in msg, and the length of the string up
802 ** to where parsing failed in stoppedAt.
804 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine)
805 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
809 AccumulatorData *acc = (AccumulatorData *)XtMalloc(sizeof(*acc));
810 + static const char *prefix = ">> ";
812 BeginCreatingProgram(acc);
814 @@ -651,6 +653,12 @@ Program *ParseMacro(char *expr, char **m
815 prog = FinishCreatingProgram(acc);
819 + name = "--unknown--";
821 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
822 + strcat(strcpy(prog->name, prefix), name);
824 /* parse succeeded */
827 diff --quilt old/source/parse_noyacc.c new/source/parse_noyacc.c
828 --- old/source/parse_noyacc.c
829 +++ new/source/parse_noyacc.c
830 @@ -746,9 +746,10 @@ int yystacksize;
831 ** as a pointer to a static string in msg, and the length of the string up
832 ** to where parsing failed in stoppedAt.
834 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
835 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
838 + static const char *prefix = ">> ";
840 BeginCreatingProgram();
842 @@ -766,6 +767,12 @@ Program *ParseMacro(char *expr, char **m
843 /* get the newly created program */
844 prog = FinishCreatingProgram();
847 + name = "--unknown--";
849 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
850 + strcat(strcpy(prog->name, prefix), name);
852 /* parse succeeded */
855 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
856 --- old/source/smartIndent.c
857 +++ new/source/smartIndent.c
858 @@ -747,17 +747,17 @@ void BeginSmartIndent(WindowInfo *window
859 winData->inNewLineMacro = 0;
860 winData->inModMacro = 0;
861 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
862 - &stoppedAt, False);
863 + &stoppedAt, False, "smart indent newline macro");
864 if (winData->newlineMacro == NULL) {
865 - ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
866 - "newline macro", errMsg);
867 + ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
868 + "smart indent newline macro", errMsg);
871 if (indentMacros->modMacro == NULL)
872 winData->modMacro = NULL;
874 - winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
875 - &stoppedAt, False);
876 + winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
877 + &stoppedAt, False, "smart indent modify macro");
878 if (winData->modMacro == NULL) {
879 ParseError(window->shell, indentMacros->modMacro, stoppedAt,
880 "smart indent modify macro", errMsg);
881 @@ -1412,7 +1412,7 @@ static int checkSmartIndentDialogData(vo
882 if (!TextWidgetIsBlank(SmartIndentDialog.initMacro)) {
883 widgetText =ensureNewline(XmTextGetString(SmartIndentDialog.initMacro));
884 if (!CheckMacroString(SmartIndentDialog.shell, widgetText,
885 - "initialization macro", &stoppedAt)) {
886 + "smart indent initialization macro", &stoppedAt)) {
887 XmTextSetInsertionPosition(SmartIndentDialog.initMacro,
888 stoppedAt - widgetText);
889 XmProcessTraversal(SmartIndentDialog.initMacro, XmTRAVERSE_CURRENT);
890 @@ -1431,10 +1431,11 @@ static int checkSmartIndentDialogData(vo
893 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
894 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
895 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
896 + "smart indent newline macro");
898 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
899 - "newline macro", errMsg);
900 + "smart indent newline macro", errMsg);
901 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
902 stoppedAt - widgetText);
903 XmProcessTraversal(SmartIndentDialog.newlineMacro, XmTRAVERSE_CURRENT);
904 @@ -1447,10 +1448,11 @@ static int checkSmartIndentDialogData(vo
905 /* Test compile the modify macro */
906 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
907 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
908 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
909 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
910 + "smart indent modify macro");
912 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
913 - "modify macro", errMsg);
914 + "smart indent modify macro", errMsg);
915 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
916 stoppedAt - widgetText);
917 XmProcessTraversal(SmartIndentDialog.modMacro, XmTRAVERSE_CURRENT);
918 diff --quilt old/source/userCmds.c new/source/userCmds.c
919 --- old/source/userCmds.c
920 +++ new/source/userCmds.c
921 @@ -241,6 +241,8 @@ static Widget BGMenuPasteReplayBtn = NUL
922 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
923 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
924 int nMenuItems, int sensitive);
925 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
926 + menuItemRec **menu, int nMenu, const char *menuName);
927 static void rebuildMenuOfAllWindows(int menuType);
928 static void rebuildMenu(WindowInfo *window, int menuType);
929 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
930 @@ -1260,30 +1262,37 @@ int DoNamedShellMenuCmd(WindowInfo *wind
931 ** with menu item name "itemName". Returns True on successs and False on
934 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
935 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
936 + menuItemRec **menu, int nMenu, const char *menuName)
940 - for (i=0; i<NMacroMenuItems; i++) {
941 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
942 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
946 + Boolean result = False;
948 + for (i = 0; i < nMenu; i++) {
949 + if (!strcmp(menu[i]->name, itemName)) {
950 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
951 + strcat(strcpy(name, menuName), itemName);
952 + DoMacro(window, menu[i]->cmd, name);
963 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
965 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
969 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
973 - for (i=0; i<NBGMenuItems; i++) {
974 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
975 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
980 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
981 + "background-menu>");
985 @@ -2080,7 +2089,7 @@ static int checkMacroText(char *macro, W
987 char *errMsg, *stoppedAt;
989 - prog = ParseMacro(macro, &errMsg, &stoppedAt, False);
990 + prog = ParseMacro(macro, &errMsg, &stoppedAt, False, "macro");
992 if (errorParent != NULL) {
993 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
994 @@ -2092,7 +2101,7 @@ static int checkMacroText(char *macro, W
996 if (*stoppedAt != '\0') {
997 if (errorParent != NULL) {
998 - ParseError(errorParent, macro, stoppedAt,"macro","syntax error");
999 + ParseError(errorParent, macro, stoppedAt, "macro", "syntax error");
1000 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1001 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1003 @@ -3019,7 +3028,7 @@ static char *copyMacroToEnd(char **inPtr
1006 /* Parse the input */
1007 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False);
1008 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False, "macro menu item");
1010 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);