core-typeof-syntax: push up
[nedit-bw.git] / InterpretDebug.diff
blob9c0c8d4c31d9b3f58f9a41ef4ae1ce50def93159
1 Provide NEdit Macro stack traces
3 Avaliable as a patch:
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
13 problem lies.
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
23 favorite macros!
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
38 occurs.
40 ---
42 source/interpret.c | 398 ++++++++++++++++++++++++++++++++++++++++++--------
43 source/interpret.h | 2
44 source/macro.c | 10 -
45 source/nedit.c | 2
46 source/parse.h | 2
47 source/parse.y | 9 +
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 @@ -37,10 +37,11 @@ static const char CVSID[] = "$Id: interp
57 #include "menu.h"
58 #include "text.h"
59 #include "rbTree.h"
61 #include <stdio.h>
62 +#include <stdarg.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <math.h>
66 #include <limits.h>
67 #include <ctype.h>
68 @@ -141,21 +142,25 @@ static SparseArrayEntry *allocateSparseA
69 /*#define DEBUG_ASSEMBLY*/
70 /*#define DEBUG_STACK*/
72 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
73 #define DEBUG_DISASSEMBLER
74 +static const char *printd(const char *f, ...);
75 +static int outPrintd();
76 static void disasm(Inst *inst, int nInstr);
77 +static void disasmInternal(Inst *inst, int nInstr);
78 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
80 #ifdef DEBUG_ASSEMBLY /* for disassembly */
81 #define DISASM(i, n) disasm(i, n)
82 #else /* #ifndef DEBUG_ASSEMBLY */
83 #define DISASM(i, n)
84 #endif /* #ifndef DEBUG_ASSEMBLY */
86 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
87 static void stackdump(int n, int extra);
88 +static void stackdumpInternal(int n, int extra);
89 #define STACKDUMP(n, x) stackdump(n, x)
90 #define DISASM_RT(i, n) disasm(i, n)
91 #else /* #ifndef DEBUG_STACK */
92 #define STACKDUMP(n, x)
93 #define DISASM_RT(i, n)
94 @@ -211,17 +216,21 @@ static int (*OpFns[N_OPS])() = {returnNo
95 branchNever, arrayRef, arrayAssign, beginArrayIter, arrayIter, inArray,
96 deleteArrayElement, pushArraySymVal,
97 arrayRefAndAssignSetup, pushArgVal, pushArgCount, pushArgArray};
99 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
100 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
101 +#define FP_ARG_ARRAY_INDEX (-1)
102 #define FP_ARG_COUNT_INDEX (-2)
103 -#define FP_OLD_FP_INDEX (-3)
104 -#define FP_RET_PC_INDEX (-4)
105 -#define FP_TO_ARGS_DIST (4) /* should be 0 - (above index) */
106 +#define FP_FUNCTION_NAME (-3) /* !! */
107 +#define FP_SYMBOL_TABLE (-4) /* !! */
108 +#define FP_OLD_FP_INDEX (-5)
109 +#define FP_RET_PC_INDEX (-6)
111 +#define FP_TO_ARGS_DIST (0 - FP_RET_PC_INDEX) /* should be 0 - (above index) */
113 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
114 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
115 +#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
116 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
117 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
118 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
119 #define FP_ARG_START_INDEX(xFrameP) (-(FP_GET_ARG_COUNT(xFrameP) + FP_TO_ARGS_DIST))
120 #define FP_GET_ARG_N(xFrameP,xN) (FP_GET_ITEM(xFrameP, xN + FP_ARG_START_INDEX(xFrameP)))
121 @@ -298,10 +307,11 @@ Program *FinishCreatingProgram(void)
122 progLen = ((char *)ProgP) - ((char *)Prog);
123 newProg->code = (Inst *)XtMalloc(progLen);
124 memcpy(newProg->code, Prog, progLen);
125 newProg->localSymList = LocalSymList;
126 LocalSymList = NULL;
127 + newProg->name = NULL;
129 /* Local variables' values are stored on the stack. Here we assign
130 frame pointer offsets to them. */
131 for (s = newProg->localSymList; s != NULL; s = s->next)
132 s->value.val.n = fpOffset++;
133 @@ -313,10 +323,13 @@ Program *FinishCreatingProgram(void)
135 void FreeProgram(Program *prog)
137 freeSymbolTable(prog->localSymList);
138 XtFree((char *)prog->code);
139 + if (prog->name) {
140 + XtFree((char *)prog->name);
142 XtFree((char *)prog);
146 ** Add an operator (instruction) to the end of the current program
147 @@ -494,10 +507,19 @@ int ExecuteMacro(WindowInfo *window, Pro
148 context->stackP->tag = NO_TAG;
149 context->stackP++;
151 *(context->stackP++) = noValue; /* old FrameP */
153 + context->stackP->tag = NO_TAG;
154 + context->stackP->val.sym = prog->localSymList; /* symbol table */
155 + context->stackP++;
157 + context->stackP->tag = STRING_TAG;
158 + context->stackP->val.str.rep = prog->name ? prog->name : "<exec-macro>";
159 + context->stackP->val.str.len = strlen(context->stackP->val.str.rep);
160 + context->stackP++;
162 context->stackP->tag = NO_TAG; /* nArgs */
163 context->stackP->val.n = nArgs;
164 context->stackP++;
166 *(context->stackP++) = noValue; /* cached arg array */
167 @@ -596,10 +618,19 @@ void RunMacroAsSubrCall(Program *prog)
169 StackP->tag = NO_TAG;
170 StackP->val.dataval = FrameP; /* old FrameP */
171 StackP++;
173 + StackP->tag = NO_TAG;
174 + StackP->val.sym = prog->localSymList; /* symbol table */
175 + StackP++;
177 + StackP->tag = STRING_TAG;
178 + StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
179 + StackP->val.str.len = strlen(StackP->val.str.rep);
180 + StackP++;
182 StackP->tag = NO_TAG; /* nArgs */
183 StackP->val.n = 0;
184 StackP++;
186 *(StackP++) = noValue; /* cached arg array */
187 @@ -2071,26 +2102,36 @@ static int callSubroutine(void)
188 ** Push all of the required information to resume, and make space on the
189 ** stack for local variables (and initialize them), on top of the argument
190 ** values which are already there.
192 if (sym->type == MACRO_FUNCTION_SYM) {
193 + prog = (Program *)sym->value.val.str.rep;
195 StackP->tag = NO_TAG; /* return PC */
196 StackP->val.inst = PC;
197 StackP++;
199 StackP->tag = NO_TAG; /* old FrameP */
200 StackP->val.dataval = FrameP;
201 StackP++;
203 + StackP->tag = NO_TAG;
204 + StackP->val.sym = prog->localSymList; /* symbol table */
205 + StackP++;
207 + StackP->tag = STRING_TAG;
208 + StackP->val.str.rep = sym->name; /* function name */
209 + StackP->val.str.len = strlen(sym->name);
210 + StackP++;
212 StackP->tag = NO_TAG; /* nArgs */
213 StackP->val.n = nArgs;
214 StackP++;
216 *(StackP++) = noValue; /* cached arg array */
218 FrameP = StackP;
219 - prog = (Program *)sym->value.val.str.rep;
220 PC = prog->code;
221 for (s = prog->localSymList; s != NULL; s = s->next) {
222 FP_GET_SYM_VAL(FrameP, s) = noValue;
223 StackP++;
225 @@ -2554,11 +2595,11 @@ static int arrayRef(void)
227 nDim = PC->value;
228 PC++;
230 DISASM_RT(PC-2, 2);
231 - STACKDUMP(nDim, 3);
232 + STACKDUMP(nDim+1, 3);
234 if (nDim > 0) {
235 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
236 if (errNum != STAT_OK) {
237 return(errNum);
238 @@ -2609,11 +2650,11 @@ static int arrayAssign(void)
240 nDim = PC->value;
241 PC++;
243 DISASM_RT(PC-2, 1);
244 - STACKDUMP(nDim, 3);
245 + STACKDUMP(nDim+2, 3);
247 if (nDim > 0) {
248 POP(srcValue)
250 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
251 @@ -2647,13 +2688,13 @@ static int arrayAssign(void)
254 ** for use with assign-op operators (eg a[i,j] += k
256 ** Before: Prog-> [binOp], nDim, next, ...
257 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
258 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
259 ** After: Prog-> binOp, nDim, [next], ...
260 -** TheStack-> [rhs], arrayValue, next, ...
261 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
263 static int arrayRefAndAssignSetup(void)
265 int errNum;
266 DataValue srcArray, valueItem, moveExpr;
267 @@ -2664,11 +2705,11 @@ static int arrayRefAndAssignSetup(void)
268 PC++;
269 nDim = PC->value;
270 PC++;
272 DISASM_RT(PC-3, 3);
273 - STACKDUMP(nDim + 1, 3);
274 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
276 if (binaryOp) {
277 POP(moveExpr)
280 @@ -2918,21 +2959,76 @@ static int errCheck(const char *s)
281 else
282 return STAT_OK;
286 +** build a stack dump string, reallocating s as necessary.
288 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
290 + int len;
291 + const char *op;
292 + char *np;
293 + DataValue *nfp = fp;
295 +#ifdef DEBUG_STACK
296 + const char *dump;
297 + printd("\n\n");
298 + disasmInternal(PC - 1, 1);
299 + stackdumpInternal(0, 50);
300 + dump = printd(NULL);
301 +#endif
303 + /* first measure the lengths */
304 + len = strlen(msg) + 1;
305 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
306 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
308 +#ifdef DEBUG_STACK
309 + len += strlen(dump);
310 +#endif
311 + if (*pLen < len)
313 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
314 + *pLen = len;
316 + /* now copy */
317 + np = *s;
318 + op = msg;
319 + while (*op)
320 + *np++ = *op++;
322 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
323 + *np++ = '\n';
324 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
325 + while (*op)
326 + *np++ = *op++;
328 +#ifdef DEBUG_STACK
329 + op = dump;
330 + while (*op)
331 + *np++ = *op++;
332 +#endif
334 + *np = 0;
335 + return *s;
339 ** combine two strings in a static area and set ErrMsg to point to the
340 ** result. Returns false so a single return execError() statement can
341 ** be used to both process the message and return.
343 static int execError(const char *s1, const char *s2)
345 static char msg[MAX_ERR_MSG_LEN];
346 + static char *err = NULL;
347 + static int errlen = 0;
349 sprintf(msg, s1, s2);
350 msg[MAX_ERR_MSG_LEN - 1] = '\0';
351 - ErrMsg = msg;
352 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
353 return STAT_ERROR;
357 ** read an integer from a string, returning True if successful. The string must
358 @@ -2981,54 +3077,126 @@ int StringToNum(const char *string, int
360 return haveDigit;
363 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
364 +static char *printdBuffer = NULL;
365 +static int printdPos = 0;
366 +static int printdSize = 0;
368 +static const char *printd(const char *f, ...)
370 + char buffer[4096];
371 + int len;
372 + va_list args;
374 + if (!f)
376 + printdPos = 0; /* reset for next time */
377 + return printdBuffer;
380 + va_start(args, f);
381 + vsprintf(buffer, f, args);
382 + va_end(args);
384 + len = strlen(buffer);
385 + if (!printdBuffer)
387 + printdSize = 4096;
388 + printdBuffer = XtMalloc(printdSize);
389 + printdPos = 0;
391 + else
393 + int needSize = printdPos + len + 1;
394 + if (needSize > printdSize)
396 + int newSize = printdSize;
397 + while (newSize < needSize)
398 + newSize *= 2;
399 + printdBuffer = XtRealloc(printdBuffer, newSize);
400 + printdSize = newSize;
403 + strcpy(&printdBuffer[printdPos], buffer);
404 + printdPos += len;
406 + return printdBuffer;
409 +int outPrintd()
411 + const char *s = printd(NULL);
412 + const char *cp;
414 + static int outIsTTY = -1;
415 + if (outIsTTY == -1)
416 + outIsTTY = isatty(fileno(stdout));
418 + if (outIsTTY)
420 + for (cp = s; *cp; cp++)
421 + if (*cp == '\n')
422 + printf("\033[K\n");
423 + else
424 + putchar(*cp);
426 + else
428 + for (cp = s; *cp; cp++)
429 + putchar(*cp);
431 + return cp - s;
433 +#endif /* #ifdef DEBUG_DISASSEMBLER */
435 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
436 static void dumpVal(DataValue dv)
438 switch (dv.tag) {
439 case INT_TAG:
440 - printf("i=%d", dv.val.n);
441 + printd("i=%d", dv.val.n);
442 break;
443 case STRING_TAG:
445 int k;
446 char s[21];
447 char *src = dv.val.str.rep;
448 if (!src) {
449 - printf("s=<NULL>");
450 + printd("s=<NULL>");
452 else {
453 for (k = 0; src[k] && k < sizeof s - 1; k++) {
454 s[k] = isprint(src[k]) ? src[k] : '?';
456 s[k] = 0;
457 - printf("s=\"%s\"%s[%d]", s,
458 + printd("s=\"%s\"%s[%d]", s,
459 src[k] ? "..." : "", strlen(src));
462 break;
463 case ARRAY_TAG:
464 - printf("<array>");
465 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
466 break;
467 case NO_TAG:
468 if (!dv.val.inst) {
469 - printf("<no value>");
470 + printd("<no value>");
472 else {
473 - printf("?%8p", dv.val.inst);
474 + printd("?%8p", dv.val.inst);
476 break;
477 default:
478 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
479 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
480 break;
483 #endif /* #ifdef DEBUG_DISASSEMBLER */
485 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
486 -static void disasm(Inst *inst, int nInstr)
487 +static void disasmInternal(Inst *inst, int nInstr)
489 static const char *opNames[N_OPS] = {
490 "RETURN_NO_VAL", /* returnNoVal */
491 "RETURN", /* returnVal */
492 "PUSH_SYM", /* pushSymVal */
493 @@ -3073,111 +3241,225 @@ static void disasm(Inst *inst, int nInst
494 "PUSH_ARG_COUNT", /* $arg[] */
495 "PUSH_ARG_ARRAY" /* $arg */
497 int i, j;
499 - printf("\n");
500 + printd("\n");
501 for (i = 0; i < nInstr; ++i) {
502 - printf("Prog %8p ", &inst[i]);
503 + printd("Prog %8p ", &inst[i]);
504 for (j = 0; j < N_OPS; ++j) {
505 if (inst[i].func == OpFns[j]) {
506 - printf("%22s ", opNames[j]);
507 + printd("%22s ", opNames[j]);
508 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
509 Symbol *sym = inst[i+1].sym;
510 - printf("%s", sym->name);
511 + printd("%s", sym->name);
512 if (sym->value.tag == STRING_TAG &&
513 strncmp(sym->name, "string #", 8) == 0) {
514 + printd(" ");
515 dumpVal(sym->value);
517 ++i;
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);
524 ++i;
526 else if (j == OP_CONCAT) {
527 printd("nExpr=%d", inst[i+1].value);
528 ++i;
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);
533 i += 2;
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);
538 ++i;
540 else if (j == OP_ARRAY_ITER) {
541 - printf("%s = %s++ end-loop=(%d) %p",
542 + printd("%s = %s++ end-loop=(%d) %p",
543 inst[i+1].sym->name,
544 inst[i+2].sym->name,
545 inst[i+3].value, &inst[i+3] + inst[i+3].value);
546 i += 3;
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);
552 ++i;
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);
559 i += 2;
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");
566 ++i;
569 - printf("\n");
570 + printd("\n");
571 break;
574 if (j == N_OPS) {
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);
587 + outPrintd();
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);
599 - int i, offset;
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++) {
603 - char *pos = "";
604 - DataValue *dv = &StackP[-i - 1];
605 - if (dv < TheStack) {
606 - printf("--------------Stack base--------------\n");
607 - break;
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);
612 + DataValue *dv;
613 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
614 + int nArgs = FP_GET_ARG_COUNT(fp);
616 + int nSyms;
617 + static int symLen = 0;
618 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
619 + Symbol *sym;
621 +#ifdef DEBUG_STACK_HEADFIRST
622 +#else
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) {
631 + nSyms++;
632 + if (symLen < 27) {
633 + int len = strlen(sym->name);
634 + if (len > 27)
635 + len = 27;
636 + if (len > symLen)
637 + symLen = len;
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
646 + dv = sp;
647 + while (--dv >= endDv)
648 +#else
649 + for (dv = endDv; dv < sp; dv++)
650 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
652 + const char *posFmt = "%-6s ";
653 + const char *symName = "";
655 + char *pos = "";
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);
663 switch (offset) {
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;
675 default:
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);
685 + posFmt = "%6s ";
687 + else if (offset == 0) {
688 + pos = "FrameP";
690 break;
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;
700 + break;
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);
708 + else
709 dumpVal(*dv);
710 - printf("\n");
712 + printd("\n");
715 +#ifdef DEBUG_STACK_HEADFIRST
716 + /* do caller's frame */
717 + if (oldFP || arg1 > endDv)
718 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
719 +#else
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");
733 +#else
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);
749 + if (outIsTTY)
750 + printd("\033[J\n");
752 + outPrintd();
753 + fflush(stdout);
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;
762 XtActionProc xtproc;
763 Inst* inst;
764 struct DataValueTag* dataval;
765 struct SparseArrayEntryTag *arrayPtr;
766 + struct SymbolRec *sym;
767 } val;
768 } DataValue;
770 typedef struct SparseArrayEntryTag {
771 rbTreeNode nodePtrs; /* MUST BE FIRST ENTRY */
772 @@ -104,10 +105,11 @@ typedef struct SymbolRec {
773 } Symbol;
775 typedef struct ProgramTag {
776 Symbol *localSymList;
777 Inst *code;
778 + char *name;
779 } Program;
781 /* Information needed to re-start a preempted macro */
782 typedef struct {
783 DataValue *stack;
784 diff --quilt old/source/macro.c new/source/macro.c
785 --- old/source/macro.c
786 +++ new/source/macro.c
787 @@ -902,11 +902,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");
795 if (prog == NULL) {
796 fprintf(stderr,
797 "NEdit internal error, learn/replay macro syntax error: %s\n",
798 errMsg);
799 return;
800 @@ -1036,11 +1036,11 @@ static int readCheckMacroString(Widget d
801 if (*inPtr != '{') {
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);
808 if (prog == NULL) {
809 if (errPos != NULL) *errPos = stoppedAt;
810 return ParseError(dialogParent, string, stoppedAt,
811 errIn, errMsg);
813 @@ -1064,11 +1064,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! */
818 } else {
819 - prog = ParseMacro(inPtr, &errMsg, &stoppedAt);
820 + prog = ParseMacro(inPtr, &errMsg, &stoppedAt, errIn);
821 if (prog == NULL) {
822 if (errPos != NULL) {
823 *errPos = stoppedAt;
826 @@ -1367,11 +1367,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);
834 if (prog == NULL) {
835 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
836 XtFree(tMacro);
837 return;
839 @@ -1631,11 +1631,11 @@ selEnd += $text_length - startLength\n}\
840 sprintf(loopedCmd, loopMacro, command);
841 else
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");
847 if (prog == NULL) {
848 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
849 errMsg);
850 return;
852 diff --quilt old/source/nedit.c new/source/nedit.c
853 --- old/source/nedit.c
854 +++ new/source/nedit.c
855 @@ -835,11 +835,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");
863 XtFree(tMacro);
864 if (prog == NULL) {
865 ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
866 return False;
868 diff --quilt old/source/parse.h new/source/parse.h
869 --- old/source/parse.h
870 +++ new/source/parse.h
871 @@ -28,8 +28,8 @@
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 @@ -463,13 +463,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)
893 Program *prog;
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 @@ -483,10 +484,16 @@ Program *ParseMacro(char *expr, char **m
903 /* get the newly created program */
904 prog = FinishCreatingProgram();
906 + if (!name)
907 + name = "--unknown--";
909 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
910 + strcat(strcpy(prog->name, prefix), name);
912 /* parse succeeded */
913 *msg = "";
914 *stoppedAt = InPtr;
915 return prog;
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)
929 Program *prog;
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();
942 + if (!name)
943 + name = "--unknown--";
945 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
946 + strcat(strcpy(prog->name, prefix), name);
948 /* parse succeeded */
949 *msg = "";
950 *stoppedAt = InPtr;
951 return prog;
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,
962 - &stoppedAt);
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);
968 return;
970 if (indentMacros->modMacro == NULL)
971 winData->modMacro = NULL;
972 else {
973 winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
974 - &stoppedAt);
975 + &stoppedAt, "smart indent modify macro");
976 if (winData->modMacro == NULL) {
977 ParseError(window->shell, indentMacros->modMacro, stoppedAt,
978 "smart indent modify macro", errMsg);
979 return;
981 @@ -1429,11 +1429,12 @@ static int checkSmartIndentDialogData(vo
982 "Newline macro required", "OK");
983 return False;
986 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
987 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt);
988 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt,
989 + "smart indent newline macro");
990 if (prog == NULL) {
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
996 FreeProgram(prog);
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");
1004 if (prog == NULL) {
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
1029 ** failure.
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)
1035 int i;
1037 - for (i=0; i<NMacroMenuItems; i++) {
1038 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
1039 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
1040 - return True;
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);
1050 + result = True;
1053 - return False;
1054 + if (name) {
1055 + XtFree(name);
1057 + return result;
1060 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1062 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
1063 + "macro-menu>");
1066 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
1068 - int i;
1070 - for (i=0; i<NBGMenuItems; i++) {
1071 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
1072 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
1073 - return True;
1076 - return False;
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)
1087 Program *prog;
1088 char *errMsg, *stoppedAt;
1090 - prog = ParseMacro(macro, &errMsg, &stoppedAt);
1091 + prog = ParseMacro(macro, &errMsg, &stoppedAt, "macro");
1092 if (prog == NULL) {
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 '{'");
1099 return NULL;
1102 /* Parse the input */
1103 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt);
1104 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, "macro menu item");
1105 if (prog == NULL) {
1106 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);
1107 return NULL;
1109 FreeProgram(prog);