1 Provide NEdit Macro stack traces
5 http://sourceforge.net/tracker/index.php?func=detail&aid=970501&group_id=11005&atid=311005
6 [ 970501 ] Provide NEdit Macro stack traces
7 InterpretDebug.diff 2004-06-10 11:51
9 Macro function names are listed when a crash occurs in one of your macros.
10 The usual error message is followed by a list of the NEdit macro functions
11 called before getting there. (It doesn't tell you how the macro was invoked
12 however.) This provides a good clue as to where a macro programming
15 Also, debug tracing enhanced to show symbol values in stack traces listed to
16 terminal output: a boon to interpret.c hackers.
18 Try changing the definition
19 #define STACKDUMP(n, x) stackdump(n, x)
21 #define STACKDUMP(n, x) stackdump(n, x + 50)
22 and watching the output of NEdit in an xterm generated while running your
25 (You will need to add -DDEBUG_STACK and -DDEBUG_ASSEMBLY in your compilation
26 flags to enable the debug tracing.)
28 Thanks to Eddy De Greef!
30 InterpretDebug2.diff 2004-06-11 17:13
32 This version passes an extra "name" string to ParseMacro().
33 This name is used as a "function name" in the stack dumps,
34 when there is no available function symbol name available
35 (usually at the top level of invocation from NEdit's user
36 interface). It allows the user to determine which macro is
37 being invoked or which file is being interpreted when an error
42 source/interpret.c | 398 ++++++++++++++++++++++++++++++++++++++++++--------
43 source/interpret.h | 2
48 source/parse_noyacc.c | 9 +
49 source/smartIndent.c | 12 -
50 source/userCmds.c | 47 +++--
51 9 files changed, 400 insertions(+), 91 deletions(-)
53 diff --quilt old/source/interpret.c new/source/interpret.c
54 --- old/source/interpret.c
55 +++ new/source/interpret.c
56 @@ -36,11 +36,13 @@ static const char CVSID[] = "$Id: interp
70 @@ -141,21 +143,25 @@ static SparseArrayEntry *allocateSparseA
71 /*#define DEBUG_ASSEMBLY*/
72 /*#define DEBUG_STACK*/
74 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
75 #define DEBUG_DISASSEMBLER
76 +static const char *printd(const char *f, ...);
77 +static int outPrintd();
78 static void disasm(Inst *inst, int nInstr);
79 +static void disasmInternal(Inst *inst, int nInstr);
80 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
82 #ifdef DEBUG_ASSEMBLY /* for disassembly */
83 #define DISASM(i, n) disasm(i, n)
84 #else /* #ifndef DEBUG_ASSEMBLY */
86 #endif /* #ifndef DEBUG_ASSEMBLY */
88 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
89 static void stackdump(int n, int extra);
90 +static void stackdumpInternal(int n, int extra);
91 #define STACKDUMP(n, x) stackdump(n, x)
92 #define DISASM_RT(i, n) disasm(i, n)
93 #else /* #ifndef DEBUG_STACK */
94 #define STACKDUMP(n, x)
95 #define DISASM_RT(i, n)
96 @@ -211,17 +217,21 @@ static int (*OpFns[N_OPS])() = {returnNo
97 branchNever, arrayRef, arrayAssign, beginArrayIter, arrayIter, inArray,
98 deleteArrayElement, pushArraySymVal,
99 arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray};
101 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
102 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
103 +#define FP_ARG_ARRAY_INDEX (-1)
104 #define FP_ARG_COUNT_INDEX (-2)
105 -#define FP_OLD_FP_INDEX (-3)
106 -#define FP_RET_PC_INDEX (-4)
107 -#define FP_TO_ARGS_DIST (4) /* should be 0 - (above index) */
108 +#define FP_FUNCTION_NAME (-3) /* !! */
109 +#define FP_SYMBOL_TABLE (-4) /* !! */
110 +#define FP_OLD_FP_INDEX (-5)
111 +#define FP_RET_PC_INDEX (-6)
113 +#define FP_TO_ARGS_DIST (0 - FP_RET_PC_INDEX) /* should be 0 - (above index) */
115 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
116 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
117 +#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
118 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
119 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
120 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
121 #define FP_ARG_START_INDEX(xFrameP) (-(FP_GET_ARG_COUNT(xFrameP) + FP_TO_ARGS_DIST))
122 #define FP_GET_ARG_N(xFrameP,xN) (FP_GET_ITEM(xFrameP, xN + FP_ARG_START_INDEX(xFrameP)))
123 @@ -298,10 +308,11 @@ Program *FinishCreatingProgram(void)
124 progLen = ((char *)ProgP) - ((char *)Prog);
125 newProg->code = (Inst *)XtMalloc(progLen);
126 memcpy(newProg->code, Prog, progLen);
127 newProg->localSymList = LocalSymList;
129 + newProg->name = NULL;
131 /* Local variables' values are stored on the stack. Here we assign
132 frame pointer offsets to them. */
133 for (s = newProg->localSymList; s != NULL; s = s->next)
134 s->value.val.n = fpOffset++;
135 @@ -313,10 +324,13 @@ Program *FinishCreatingProgram(void)
137 void FreeProgram(Program *prog)
139 freeSymbolTable(prog->localSymList);
140 XtFree((char *)prog->code);
142 + XtFree((char *)prog->name);
144 XtFree((char *)prog);
148 ** Add an operator (instruction) to the end of the current program
149 @@ -494,10 +508,19 @@ int ExecuteMacro(WindowInfo *window, Pro
150 context->stackP->tag = NO_TAG;
153 *(context->stackP++) = noValue; /* old FrameP */
155 + context->stackP->tag = NO_TAG;
156 + context->stackP->val.sym = prog->localSymList; /* symbol table */
159 + context->stackP->tag = STRING_TAG;
160 + context->stackP->val.str.rep = prog->name ? prog->name : "<exec-macro>";
161 + context->stackP->val.str.len = strlen(context->stackP->val.str.rep);
164 context->stackP->tag = NO_TAG; /* nArgs */
165 context->stackP->val.n = nArgs;
168 *(context->stackP++) = noValue; /* cached arg array */
169 @@ -593,10 +616,19 @@ void RunMacroAsSubrCall(Program *prog)
171 StackP->tag = NO_TAG;
172 StackP->val.dataval = FrameP; /* old FrameP */
175 + StackP->tag = NO_TAG;
176 + StackP->val.sym = prog->localSymList; /* symbol table */
179 + StackP->tag = STRING_TAG;
180 + StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
181 + StackP->val.str.len = strlen(StackP->val.str.rep);
184 StackP->tag = NO_TAG; /* nArgs */
188 *(StackP++) = noValue; /* cached arg array */
189 @@ -2050,26 +2082,36 @@ static int callSubroutine(void)
190 ** Push all of the required information to resume, and make space on the
191 ** stack for local variables (and initialize them), on top of the argument
192 ** values which are already there.
194 if (sym->type == MACRO_FUNCTION_SYM) {
195 + prog = (Program *)sym->value.val.str.rep;
197 StackP->tag = NO_TAG; /* return PC */
198 StackP->val.inst = PC;
201 StackP->tag = NO_TAG; /* old FrameP */
202 StackP->val.dataval = FrameP;
205 + StackP->tag = NO_TAG;
206 + StackP->val.sym = prog->localSymList; /* symbol table */
209 + StackP->tag = STRING_TAG;
210 + StackP->val.str.rep = sym->name; /* function name */
211 + StackP->val.str.len = strlen(sym->name);
214 StackP->tag = NO_TAG; /* nArgs */
215 StackP->val.n = nArgs;
218 *(StackP++) = noValue; /* cached arg array */
221 - prog = (Program *)sym->value.val.str.rep;
223 for (s = prog->localSymList; s != NULL; s = s->next) {
224 FP_GET_SYM_VAL(FrameP, s) = noValue;
227 @@ -2532,11 +2574,11 @@ static int arrayRef(void)
233 - STACKDUMP(nDim, 3);
234 + STACKDUMP(nDim+1, 3);
237 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
238 if (errNum != STAT_OK) {
240 @@ -2583,11 +2625,11 @@ static int arrayAssign(void)
246 - STACKDUMP(nDim, 3);
247 + STACKDUMP(nDim+2, 3);
252 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
253 @@ -2621,13 +2663,13 @@ static int arrayAssign(void)
256 ** for use with assign-op operators (eg a[i,j] += k
258 ** Before: Prog-> [binOp], nDim, next, ...
259 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
260 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
261 ** After: Prog-> binOp, nDim, [next], ...
262 -** TheStack-> [rhs], arrayValue, next, ...
263 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
265 static int arrayRefAndAssignSetup(void)
268 DataValue srcArray, valueItem, moveExpr;
269 @@ -2638,11 +2680,11 @@ static int arrayRefAndAssignSetup(void)
275 - STACKDUMP(nDim + 1, 3);
276 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
282 @@ -2892,20 +2934,75 @@ static int errCheck(const char *s)
288 +** build a stack dump string, reallocating s as necessary.
290 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
295 + DataValue *nfp = fp;
300 + disasmInternal(PC - 1, 1);
301 + stackdumpInternal(0, 50);
302 + dump = printd(NULL);
305 + /* first measure the lengths */
306 + len = strlen(msg) + 1;
307 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
308 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
311 + len += strlen(dump);
315 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
324 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
326 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
341 ** combine two strings in a static area and set ErrMsg to point to the
342 ** result. Returns false so a single return execError() statement can
343 ** be used to both process the message and return.
345 static int execError(const char *s1, const char *s2)
347 static char msg[MAX_ERR_MSG_LEN];
348 + static char *err = NULL;
349 + static int errlen = 0;
351 sprintf(msg, s1, s2);
353 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
357 int StringToNum(const char *string, int *number)
359 @@ -2935,54 +3032,126 @@ int StringToNum(const char *string, int
364 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
365 +static char *printdBuffer = NULL;
366 +static int printdPos = 0;
367 +static int printdSize = 0;
369 +static const char *printd(const char *f, ...)
377 + printdPos = 0; /* reset for next time */
378 + return printdBuffer;
382 + vsprintf(buffer, f, args);
385 + len = strlen(buffer);
389 + printdBuffer = XtMalloc(printdSize);
394 + int needSize = printdPos + len + 1;
395 + if (needSize > printdSize)
397 + int newSize = printdSize;
398 + while (newSize < needSize)
400 + printdBuffer = XtRealloc(printdBuffer, newSize);
401 + printdSize = newSize;
404 + strcpy(&printdBuffer[printdPos], buffer);
407 + return printdBuffer;
412 + const char *s = printd(NULL);
415 + static int outIsTTY = -1;
416 + if (outIsTTY == -1)
417 + outIsTTY = isatty(fileno(stdout));
421 + for (cp = s; *cp; cp++)
423 + printf("\033[K\n");
429 + for (cp = s; *cp; cp++)
434 +#endif /* #ifdef DEBUG_DISASSEMBLER */
436 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
437 static void dumpVal(DataValue dv)
441 - printf("i=%d", dv.val.n);
442 + printd("i=%d", dv.val.n);
448 char *src = dv.val.str.rep;
450 - printf("s=<NULL>");
451 + printd("s=<NULL>");
454 for (k = 0; src[k] && k < sizeof s - 1; k++) {
455 s[k] = isprint(src[k]) ? src[k] : '?';
458 - printf("s=\"%s\"%s[%d]", s,
459 + printd("s=\"%s\"%s[%d]", s,
460 src[k] ? "..." : "", strlen(src));
466 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
470 - printf("<no value>");
471 + printd("<no value>");
474 - printf("?%8p", dv.val.inst);
475 + printd("?%8p", dv.val.inst);
479 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
480 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
484 #endif /* #ifdef DEBUG_DISASSEMBLER */
486 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
487 -static void disasm(Inst *inst, int nInstr)
488 +static void disasmInternal(Inst *inst, int nInstr)
490 static const char *opNames[N_OPS] = {
491 "RETURN_NO_VAL", /* returnNoVal */
492 "RETURN", /* returnVal */
493 "PUSH_SYM", /* pushSymVal */
494 @@ -3027,111 +3196,224 @@ static void disasm(Inst *inst, int nInst
495 "PUSH_ARG_COUNT", /* $arg[] */
496 "PUSH_ARG_ARRAY" /* $arg */
502 for (i = 0; i < nInstr; ++i) {
503 - printf("Prog %8p ", &inst[i]);
504 + printd("Prog %8p ", &inst[i]);
505 for (j = 0; j < N_OPS; ++j) {
506 if (inst[i].func == OpFns[j]) {
507 - printf("%22s ", opNames[j]);
508 + printd("%22s ", opNames[j]);
509 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
510 Symbol *sym = inst[i+1].sym;
511 - printf("%s", sym->name);
512 + printd("%s", sym->name);
513 if (sym->value.tag == STRING_TAG &&
514 strncmp(sym->name, "string #", 8) == 0) {
519 else if (j == OP_BRANCH || j == OP_BRANCH_FALSE ||
520 j == OP_BRANCH_NEVER || j == OP_BRANCH_TRUE) {
521 - printf("to=(%d) %p", inst[i+1].value,
522 + printd("to=(%d) %p", inst[i+1].value,
523 &inst[i+1] + inst[i+1].value);
526 else if (j == OP_CONCAT) {
527 printd("nExpr=%d", inst[i+1].value);
530 else if (j == OP_SUBR_CALL) {
531 - printf("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
532 + printd("%s (%d arg)", inst[i+1].sym->name, inst[i+2].value);
535 else if (j == OP_BEGIN_ARRAY_ITER) {
536 - printf("%s in", inst[i+1].sym->name);
537 + printd("%s in", inst[i+1].sym->name);
540 else if (j == OP_ARRAY_ITER) {
541 - printf("%s = %s++ end-loop=(%d) %p",
542 + printd("%s = %s++ end-loop=(%d) %p",
545 inst[i+3].value, &inst[i+3] + inst[i+3].value);
548 else if (j == OP_ARRAY_REF || j == OP_ARRAY_DELETE ||
549 j == OP_ARRAY_ASSIGN) {
550 - printf("nDim=%d", inst[i+1].value);
551 + printd("nDim=%d", inst[i+1].value);
554 else if (j == OP_ARRAY_REF_ASSIGN_SETUP) {
555 - printf("binOp=%s ", inst[i+1].value ? "true" : "false");
556 - printf("nDim=%d", inst[i+2].value);
557 + printd("binOp=%s ", inst[i+1].value ? "true" : "false");
558 + printd("nDim=%d", inst[i+2].value);
561 else if (j == OP_PUSH_ARRAY_SYM) {
562 - printf("%s", inst[++i].sym->name);
563 - printf(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
564 + printd("%s", inst[++i].sym->name);
565 + printd(" %s", inst[i+1].value ? "createAndRef" : "refOnly");
575 - printf("%x\n", inst[i].value);
576 + printd("%x\n", inst[i].value);
581 +static void disasm(Inst *inst, int nInstr)
583 + static int outIsTTY = -1;
584 + if (outIsTTY == -1) outIsTTY = isatty(fileno(stdout));
585 + if (outIsTTY) { printd("\033[H"); }
586 + disasmInternal(inst, nInstr);
589 #endif /* #ifdef DEBUG_DISASSEMBLER */
591 #ifdef DEBUG_STACK /* for run-time stack dumping */
592 #define STACK_DUMP_ARG_PREFIX "Arg"
593 -static void stackdump(int n, int extra)
594 +static void stackdumpframe(DataValue *arrow, DataValue *outpt, DataValue *fp,
595 + DataValue *sp, char topMark)
597 - /* TheStack-> symN-sym1(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
598 - int nArgs = FP_GET_ARG_COUNT(FrameP);
600 - char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
601 - printf("Stack ----->\n");
602 - for (i = 0; i < n + extra; i++) {
604 - DataValue *dv = &StackP[-i - 1];
605 - if (dv < TheStack) {
606 - printf("--------------Stack base--------------\n");
608 + DataValue *baseF = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
609 + DataValue *oldFP = baseF ? baseF->val.dataval : NULL;
610 + DataValue *arg1 = &FP_GET_ARG_N(fp, 0);
611 + DataValue *fnNm = &FP_GET_ITEM(fp, FP_FUNCTION_NAME);
613 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
614 + int nArgs = FP_GET_ARG_COUNT(fp);
617 + static int symLen = 0;
618 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
621 +#ifdef DEBUG_STACK_HEADFIRST
623 + /* do caller's frame */
624 + if (oldFP || arg1 > endDv)
625 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
626 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
628 + /* do current frame */
629 + /* how many symbols are there? */
630 + for (sym = syms, nSyms = 0; sym != NULL; sym = sym->next) {
633 + int len = strlen(sym->name);
640 - offset = dv - FrameP;
642 - printf("%4.4s", i < n ? ">>>>" : "");
643 - printf("%8p ", dv);
644 + /* output instructions between endDv and sp - 1 inclusive */
645 +#ifdef DEBUG_STACK_HEADFIRST
647 + while (--dv >= endDv)
649 + for (dv = endDv; dv < sp; dv++)
650 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
652 + const char *posFmt = "%-6s ";
653 + const char *symName = "";
656 + char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
657 + int offset = dv - fp;
658 + const char *leadIn = (dv >= arrow) ? ">>>>" :
659 + (dv == arg1) ? "----" :
660 + (dv == fnNm) ? "====" : "";
661 + printd("%4.4s", leadIn);
662 + printd("%8p%c", dv, topMark);
664 - case 0: pos = "FrameP"; break; /* first local symbol value */
665 - case FP_ARG_ARRAY_CACHE_INDEX: pos = "args"; break; /* arguments array */
666 - case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* number of arguments */
667 - case FP_OLD_FP_INDEX: pos = "OldFP"; break;
668 - case FP_RET_PC_INDEX: pos = "RetPC"; break;
669 + case FP_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
670 + case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
671 + case FP_FUNCTION_NAME: pos = "FnName"; break;
672 + case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
673 + case FP_OLD_FP_INDEX: pos = "OldFP"; break;
674 + case FP_RET_PC_INDEX: pos = "RetPC"; break;
676 - if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
677 + if (offset < -FP_TO_ARGS_DIST &&
678 + offset >= -FP_TO_ARGS_DIST - nArgs)
680 sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
681 offset + FP_TO_ARGS_DIST + nArgs + 1);
683 + else if (0 <= offset && offset < nSyms) {
684 + sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
687 + else if (offset == 0) {
692 - printf("%-6s ", pos);
693 + printd(posFmt, pos);
695 + /* local symbol names? */
696 + if (offset < nSyms) {
697 + for (sym = syms; sym != NULL; sym = sym->next) {
698 + if (sym->value.val.n == offset) {
699 + symName = sym->name;
704 + printd("%-*.*s ", symLen, symLen, symName);
706 + if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
707 + printd("%s", dv->val.str.rep);
715 +#ifdef DEBUG_STACK_HEADFIRST
716 + /* do caller's frame */
717 + if (oldFP || arg1 > endDv)
718 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
720 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
723 +static void stackdumpInternal(int n, int extra)
725 + DataValue *arrow = StackP - n;
726 + DataValue *outpt = StackP - n - extra;
728 +#ifdef DEBUG_STACK_HEADFIRST
729 + printd("Stack ----->\n");
730 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
731 + if (outpt < TheStack)
732 + printd("--------------Stack base--------------\n");
734 + if (outpt < TheStack)
735 + printd("--------------Stack base--------------\n");
736 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
737 + printd("Stack ----->\n");
738 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
741 +static void stackdump(int n, int extra)
743 + static int outIsTTY = -1;
744 + if (outIsTTY == -1)
745 + outIsTTY = isatty(fileno(stdout));
747 + stackdumpInternal(n, extra);
750 + printd("\033[J\n");
756 #endif /* ifdef DEBUG_STACK */
757 diff --quilt old/source/interpret.h new/source/interpret.h
758 --- old/source/interpret.h
759 +++ new/source/interpret.h
760 @@ -84,10 +84,11 @@ typedef struct DataValueTag {
761 struct ProgramTag* prog;
764 struct DataValueTag* dataval;
765 struct SparseArrayEntryTag *arrayPtr;
766 + struct SymbolRec *sym;
770 typedef struct SparseArrayEntryTag {
771 rbTreeNode nodePtrs; /* MUST BE FIRST ENTRY */
772 @@ -104,10 +105,11 @@ typedef struct SymbolRec {
775 typedef struct ProgramTag {
776 Symbol *localSymList;
781 /* Information needed to re-start a preempted macro */
784 diff --quilt old/source/macro.c new/source/macro.c
785 --- old/source/macro.c
786 +++ new/source/macro.c
787 @@ -829,11 +829,11 @@ void Replay(WindowInfo *window)
788 if (ReplayMacro != NULL &&
789 ReplayMacro[0] != 0 &&
790 window->macroCmdData == NULL) {
791 /* Parse the replay macro (it's stored in text form) and compile it into
792 an executable program "prog" */
793 - prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt);
794 + prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, "replay macro");
797 "NEdit internal error, learn/replay macro syntax error: %s\n",
800 @@ -963,11 +963,11 @@ static int readCheckMacroString(Widget d
802 if (errPos != NULL) *errPos = stoppedAt;
803 return ParseError(dialogParent, string, inPtr,
804 errIn, "expected '{'");
806 - prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
807 + prog = ParseMacro(inPtr, &errMsg, &stoppedAt, subrName);
809 if (errPos != NULL) *errPos = stoppedAt;
810 return ParseError(dialogParent, string, stoppedAt,
813 @@ -991,11 +991,11 @@ static int readCheckMacroString(Widget d
814 and WAIT for them to finish executing before proceeding. Note that
815 the code below is not perfect. If you interleave code blocks with
816 definitions in a file which is loaded from another macro file, it
817 will probably run the code blocks in reverse order! */
819 - prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
820 + prog = ParseMacro(inPtr, &errMsg, &stoppedAt, errIn);
822 if (errPos != NULL) {
826 @@ -1294,11 +1294,11 @@ void DoMacro(WindowInfo *window, const c
827 strncpy(tMacro, macro, macroLen);
828 tMacro[macroLen] = '\n';
829 tMacro[macroLen+1] = '\0';
831 /* Parse the macro and report errors if it fails */
832 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
833 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, errInName);
835 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
839 @@ -1558,11 +1558,11 @@ selEnd += $text_length - startLength\n}\
840 sprintf(loopedCmd, loopMacro, command);
842 sprintf(loopedCmd, loopMacro, how, command);
844 /* Parse the resulting macro into an executable program "prog" */
845 - prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt);
846 + prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, "repeat macro");
848 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
852 diff --quilt old/source/nedit.c new/source/nedit.c
853 --- old/source/nedit.c
854 +++ new/source/nedit.c
855 @@ -830,11 +830,11 @@ static int checkDoMacroArg(const char *m
856 strncpy(tMacro, macro, macroLen);
857 tMacro[macroLen] = '\n';
858 tMacro[macroLen+1] = '\0';
860 /* Do a test parse */
861 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt);
862 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, "-do Argument");
865 ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
868 diff --quilt old/source/parse.h new/source/parse.h
869 --- old/source/parse.h
870 +++ new/source/parse.h
872 #ifndef NEDIT_PARSE_H_INCLUDED
873 #define NEDIT_PARSE_H_INCLUDED
875 #include "interpret.h"
877 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt);
878 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name);
880 #endif /* NEDIT_PARSE_H_INCLUDED */
881 diff --quilt old/source/parse.y new/source/parse.y
882 --- old/source/parse.y
883 +++ new/source/parse.y
884 @@ -546,13 +546,14 @@ blank: /* nothing */
885 ** executed using ExecuteProgram. Returns program on success, or NULL
886 ** on failure. If the command failed, the error message is returned
887 ** as a pointer to a static string in msg, and the length of the string up
888 ** to where parsing failed in stoppedAt.
890 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
891 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
894 + static const char *prefix = ">> ";
896 BeginCreatingProgram();
898 /* call yyparse to parse the string and check for success. If the parse
899 failed, return the error message and string index (the grammar aborts
900 @@ -566,10 +567,16 @@ Program *ParseMacro(char *expr, char **m
903 /* get the newly created program */
904 prog = FinishCreatingProgram();
907 + name = "--unknown--";
909 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
910 + strcat(strcpy(prog->name, prefix), name);
912 /* parse succeeded */
917 diff --quilt old/source/parse_noyacc.c new/source/parse_noyacc.c
918 --- old/source/parse_noyacc.c
919 +++ new/source/parse_noyacc.c
920 @@ -744,13 +744,14 @@ int yystacksize;
921 ** executed using ExecuteProgram. Returns program on success, or NULL
922 ** on failure. If the command failed, the error message is returned
923 ** as a pointer to a static string in msg, and the length of the string up
924 ** to where parsing failed in stoppedAt.
926 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
927 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
930 + static const char *prefix = ">> ";
932 BeginCreatingProgram();
934 /* call yyparse to parse the string and check for success. If the parse
935 failed, return the error message and string index (the grammar aborts
936 @@ -764,10 +765,16 @@ Program *ParseMacro(char *expr, char **m
939 /* get the newly created program */
940 prog = FinishCreatingProgram();
943 + name = "--unknown--";
945 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
946 + strcat(strcpy(prog->name, prefix), name);
948 /* parse succeeded */
953 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
954 --- old/source/smartIndent.c
955 +++ new/source/smartIndent.c
956 @@ -745,21 +745,21 @@ void BeginSmartIndent(WindowInfo *window
957 /* Compile the newline and modify macros and attach them to the window */
958 winData = (windowSmartIndentData *)XtMalloc(sizeof(windowSmartIndentData));
959 winData->inNewLineMacro = 0;
960 winData->inModMacro = 0;
961 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
963 + &stoppedAt, "smart indent newline macro");
964 if (winData->newlineMacro == NULL) {
965 ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
966 - "newline macro", errMsg);
967 + "smart indent newline macro", errMsg);
970 if (indentMacros->modMacro == NULL)
971 winData->modMacro = NULL;
973 winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
975 + &stoppedAt, "smart indent modify macro");
976 if (winData->modMacro == NULL) {
977 ParseError(window->shell, indentMacros->modMacro, stoppedAt,
978 "smart indent modify macro", errMsg);
981 @@ -1429,11 +1429,12 @@ static int checkSmartIndentDialogData(vo
982 "Newline macro required", "OK");
986 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
987 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
988 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
989 + "smart indent newline macro");
991 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
992 "newline macro", errMsg);
993 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
994 stoppedAt - widgetText);
995 @@ -1445,11 +1446,12 @@ static int checkSmartIndentDialogData(vo
998 /* Test compile the modify macro */
999 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
1000 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
1001 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
1002 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
1003 + "smart indent modify macro");
1005 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1006 "modify macro", errMsg);
1007 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
1008 stoppedAt - widgetText);
1009 diff --quilt old/source/userCmds.c new/source/userCmds.c
1010 --- old/source/userCmds.c
1011 +++ new/source/userCmds.c
1012 @@ -239,10 +239,12 @@ static Widget MacroPasteReplayBtn = NULL
1013 static Widget BGMenuPasteReplayBtn = NULL;
1015 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
1016 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
1017 int nMenuItems, int sensitive);
1018 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1019 + menuItemRec **menu, int nMenu, const char *menuName);
1020 static void rebuildMenuOfAllWindows(int menuType);
1021 static void rebuildMenu(WindowInfo *window, int menuType);
1022 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
1023 const char *hierName);
1024 static char *copySubstring(const char *string, int length);
1025 @@ -1258,34 +1260,41 @@ int DoNamedShellMenuCmd(WindowInfo *wind
1027 ** Search through the Macro or background menu and execute the first command
1028 ** with menu item name "itemName". Returns True on successs and False on
1031 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1032 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1033 + menuItemRec **menu, int nMenu, const char *menuName)
1037 - for (i=0; i<NMacroMenuItems; i++) {
1038 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
1039 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
1042 + char *name = NULL;
1043 + Boolean result = False;
1045 + for (i = 0; i < nMenu; i++) {
1046 + if (!strcmp(menu[i]->name, itemName)) {
1047 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
1048 + strcat(strcpy(name, menuName), itemName);
1049 + DoMacro(window, menu[i]->cmd, name);
1060 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1062 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
1066 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
1070 - for (i=0; i<NBGMenuItems; i++) {
1071 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
1072 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
1077 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
1078 + "background-menu>");
1082 ** Cache user menus:
1083 ** Rebuild all of the Shell, Macro, Background menus of given editor window.
1084 @@ -2078,11 +2087,11 @@ static int checkMacro(userCmdDialog *ucd
1085 static int checkMacroText(char *macro, Widget errorParent, Widget errFocus)
1088 char *errMsg, *stoppedAt;
1090 - prog = ParseMacro(macro, &errMsg, &stoppedAt);
1091 + prog = ParseMacro(macro, &errMsg, &stoppedAt, "macro");
1093 if (errorParent != NULL) {
1094 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
1095 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1096 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1097 @@ -3017,11 +3026,11 @@ static char *copyMacroToEnd(char **inPtr
1098 ParseError(NULL, *inPtr, *inPtr-1, "macro menu item", "expecting '{'");
1102 /* Parse the input */
1103 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt);
1104 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, "macro menu item");
1106 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);