ttyname: use precomputed lengths
[nedit-bw.git] / InterpretDebug5.diff
blob0a5da98fa8464044e77aa4339da155e7e39aa5f9
1 From: Tony Balinski <ajbj@free.fr>
2 Subject: Provide NEdit Macro stack traces
4 Avaliable as a patch:
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
14 lies.
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
28 favorite macros!
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.
43 ---
45 source/interpret.c | 405 ++++++++++++++++++++++++++++++++++++++++++---------
46 source/interpret.h | 2
47 source/macro.c | 9 -
48 source/nedit.c | 4
49 source/parse.h | 3
50 source/parse.y | 10 +
51 source/smartIndent.c | 20 +-
52 source/userCmds.c | 49 +++---
53 8 files changed, 396 insertions(+), 106 deletions(-)
55 diff --quilt old/source/interpret.c new/source/interpret.c
56 --- old/source/interpret.c
57 +++ new/source/interpret.c
58 @@ -38,7 +38,9 @@ static const char CVSID[] = "$Id: interp
59 #include "text.h"
60 #include "rbTree.h"
62 +#include <unistd.h>
63 #include <stdio.h>
64 +#include <stdarg.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <math.h>
68 @@ -104,7 +106,10 @@ static const char *tagToStr(enum typeTag
70 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
71 #define DEBUG_DISASSEMBLER
72 +static const char *printd(const char *f, ...);
73 +static int outPrintd();
74 static void disasm(Inst *inst, int nInstr);
75 +static void disasmInternal(Inst *inst, int nInstr);
76 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
78 #ifdef DEBUG_ASSEMBLY /* for disassembly */
79 @@ -115,6 +120,7 @@ static void disasm(Inst *inst, int nInst
81 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
82 static void stackdump(int n, int extra);
83 +static void stackdumpInternal(int n, int extra);
84 #define STACKDUMP(n, x) stackdump(n, x)
85 #define DISASM_RT(i, n) disasm(i, n)
86 #else /* #ifndef DEBUG_STACK */
87 @@ -172,14 +178,18 @@ static int (*OpFns[])() = {
90 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
91 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
92 +#define FP_ARG_ARRAY_INDEX (-1)
93 #define FP_ARG_COUNT_INDEX (-2)
94 -#define FP_OLD_FP_INDEX (-3)
95 -#define FP_RET_PC_INDEX (-4)
96 -#define FP_PROG_INDEX (-5)
97 -#define FP_TO_ARGS_DIST (5) /* should be 0 - (above index) */
98 +#define FP_FUNCTION_NAME (-3) /* !! */
99 +#define FP_SYMBOL_TABLE (-4) /* !! */
100 +#define FP_OLD_FP_INDEX (-5)
101 +#define FP_RET_PC_INDEX (-6)
102 +#define FP_PROG_INDEX (-7)
104 +#define FP_TO_ARGS_DIST (0 - FP_PROG_INDEX) /* should be 0 - (above index) */
106 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
107 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
108 +#define FP_GET_ARG_ARRAY(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
109 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
110 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
111 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
112 @@ -267,6 +277,7 @@ Program *FinishCreatingProgram(Accumulat
113 newProg->code = (Inst *)XtMalloc(progLen);
114 memcpy(newProg->code, Prog, progLen);
115 newProg->localSymList = LocalSymList;
116 + newProg->name = NULL;
117 newProg->refcount = 1;
119 /* Local variables' values are stored on the stack. Here we assign
120 @@ -291,6 +302,7 @@ void FreeProgram(Program *prog)
121 if (--prog->refcount == 0) {
122 freeSymbolTable(prog->localSymList);
123 XtFree((char *)prog->code);
124 + XtFree((char *)prog->name);
125 XtFree((char *)prog);
128 @@ -441,7 +453,8 @@ void FillLoopAddrs(Inst *breakAddr, Inst
129 ** helper function to setup the next frame
131 static void setupFrame(DataValue **frameP, DataValue **stackP,
132 - Inst **pc, Program *prog, int nArgs, DataValue *args)
133 + Inst **pc, Program *prog, int nArgs, DataValue *args,
134 + const char *name)
136 static DataValue noValue = {NO_TAG, {0}};
137 int i;
138 @@ -475,6 +488,17 @@ static void setupFrame(DataValue **frame
139 (*stackP)->val.dataval = *frameP;
140 (*stackP)++;
142 + /* symbol table */
143 + (*stackP)->tag = NO_TAG;
144 + (*stackP)->val.sym = prog->localSymList;
145 + (*stackP)++;
147 + /* macro name */
148 + (*stackP)->tag = STRING_TAG;
149 + (*stackP)->val.str.rep = (char *)name;
150 + (*stackP)->val.str.len = strlen(name);
151 + (*stackP)++;
153 /* nArgs */
154 (*stackP)->tag = NO_TAG;
155 (*stackP)->val.n = nArgs;
156 @@ -551,7 +575,7 @@ int ExecuteMacro(WindowInfo *window, Pro
157 /* prog will be freed by cller, but by stack also, so inc refcount */
158 prog->refcount++;
159 setupFrame(&context->frameP, &context->stackP, &context->pc,
160 - prog, nArgs, args);
161 + prog, nArgs, args, prog->name ? prog->name : "<exec-macro>");
163 /* Begin execution, return on error or preemption */
164 return ContinueMacro(context, result, msg);
165 @@ -627,7 +651,8 @@ int ContinueMacro(RestartData *continuat
167 void RunMacroAsSubrCall(Program *prog)
169 - setupFrame(&FrameP, &StackP, &PC, prog, 0, NULL);
170 + setupFrame(&FrameP, &StackP, &PC, prog, 0, NULL,
171 + prog->name ? prog->name : "<run-macro>");
174 void FreeRestartData(RestartData *context)
175 @@ -1419,7 +1444,7 @@ static int pushArgArray(void)
176 STACKDUMP(0, 3);
178 nArgs = FP_GET_ARG_COUNT(FrameP);
179 - resultArray = &FP_GET_ARG_ARRAY_CACHE(FrameP);
180 + resultArray = &FP_GET_ARG_ARRAY(FrameP);
181 if (resultArray->tag != ARRAY_TAG) {
182 resultArray->tag = ARRAY_TAG;
183 resultArray->val.arrayPtr = ArrayNew();
184 @@ -2187,7 +2212,7 @@ static int callSubroutine(void)
185 prog = sym->value.val.prog;
186 prog->refcount++;
187 /* -nArgs means 'arguments are on stack' */
188 - setupFrame(&FrameP, &StackP, &PC, prog, -nArgs, NULL);
189 + setupFrame(&FrameP, &StackP, &PC, prog, -nArgs, NULL, sym->name);
190 return STAT_OK;
193 @@ -2713,7 +2738,7 @@ static int arrayRef(void)
194 PC++;
196 DISASM_RT(PC-2, 2);
197 - STACKDUMP(nDim, 3);
198 + STACKDUMP(nDim+1, 3);
200 if (nDim > 0) {
201 errNum = makeArrayKeyFromArgs(nDim, &keyString, 0);
202 @@ -2764,7 +2789,7 @@ static int arrayAssign(void)
203 PC++;
205 DISASM_RT(PC-2, 1);
206 - STACKDUMP(nDim, 3);
207 + STACKDUMP(nDim+2, 3);
209 if (nDim > 0) {
210 POP(srcValue);
211 @@ -2802,9 +2827,9 @@ static int arrayAssign(void)
212 ** for use with assign-op operators (eg a[i,j] += k
214 ** Before: Prog-> [binOp], nDim, next, ...
215 -** TheStack-> [rhs], indnDim, ... ind1, next, ...
216 +** TheStack-> [rhs], indnDim, ... ind1, ArraySym, next, ...
217 ** After: Prog-> binOp, nDim, [next], ...
218 -** TheStack-> [rhs], arrayValue, next, ...
219 +** TheStack-> [rhs], arrayValue, ArraySym, next, ...
221 static int arrayRefAndAssignSetup(void)
223 @@ -2819,7 +2844,7 @@ static int arrayRefAndAssignSetup(void)
224 PC++;
226 DISASM_RT(PC-3, 3);
227 - STACKDUMP(nDim + 1, 3);
228 + STACKDUMP(nDim + (binaryOp ? 2 : 1), 3);
230 if (binaryOp) {
231 POP(moveExpr);
232 @@ -3073,6 +3098,59 @@ static int errCheck(const char *s)
236 +** build a stack dump string, reallocating s as necessary.
238 +static char *stackDumpStr(DataValue *fp, const char *msg, char **s, int *pLen)
240 + int len;
241 + const char *op;
242 + char *np;
243 + DataValue *nfp = fp;
245 +#ifdef DEBUG_STACK
246 + const char *dump;
247 + printd("\n\n");
248 + disasmInternal(PC - 1, 1);
249 + stackdumpInternal(0, 50);
250 + dump = printd(NULL);
251 +#endif
253 + /* first measure the lengths */
254 + len = strlen(msg) + 1;
255 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
256 + len = len + FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.len + 1;
258 +#ifdef DEBUG_STACK
259 + len += strlen(dump);
260 +#endif
261 + if (*pLen < len)
263 + *s = *s ? XtRealloc(*s, len) : XtMalloc(len);
264 + *pLen = len;
266 + /* now copy */
267 + np = *s;
268 + op = msg;
269 + while (*op)
270 + *np++ = *op++;
272 + for (nfp = fp; nfp; nfp = FP_GET_OLD_FP(nfp)) {
273 + *np++ = '\n';
274 + op = FP_GET_ITEM(nfp, FP_FUNCTION_NAME).val.str.rep;
275 + while (*op)
276 + *np++ = *op++;
278 +#ifdef DEBUG_STACK
279 + op = dump;
280 + while (*op)
281 + *np++ = *op++;
282 +#endif
284 + *np = 0;
285 + return *s;
289 ** combine two strings in a static area and set ErrMsg to point to the
290 ** result. Returns false so a single return execError() statement can
291 ** be used to both process the message and return.
292 @@ -3080,9 +3158,11 @@ static int errCheck(const char *s)
293 static int execError(const char *s1, const char *s2)
295 static char msg[MAX_ERR_MSG_LEN];
296 + static char *err = NULL;
297 + static int errlen = 0;
299 sprintf(msg, s1, s2);
300 - ErrMsg = msg;
301 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
302 return STAT_ERROR;
305 @@ -3136,11 +3216,83 @@ static const char *tagToStr(enum typeTag
308 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
309 +static char *printdBuffer = NULL;
310 +static int printdPos = 0;
311 +static int printdSize = 0;
313 +static const char *printd(const char *f, ...)
315 + char buffer[4096];
316 + int len;
317 + va_list args;
319 + if (!f)
321 + printdPos = 0; /* reset for next time */
322 + return printdBuffer;
325 + va_start(args, f);
326 + vsprintf(buffer, f, args);
327 + va_end(args);
329 + len = strlen(buffer);
330 + if (!printdBuffer)
332 + printdSize = 4096;
333 + printdBuffer = XtMalloc(printdSize);
334 + printdPos = 0;
336 + else
338 + int needSize = printdPos + len + 1;
339 + if (needSize > printdSize)
341 + int newSize = printdSize;
342 + while (newSize < needSize)
343 + newSize *= 2;
344 + printdBuffer = XtRealloc(printdBuffer, newSize);
345 + printdSize = newSize;
348 + strcpy(&printdBuffer[printdPos], buffer);
349 + printdPos += len;
351 + return printdBuffer;
354 +int outPrintd()
356 + const char *s = printd(NULL);
357 + const char *cp;
359 + static int outIsTTY = -1;
360 + if (outIsTTY == -1)
361 + outIsTTY = isatty(fileno(stdout));
363 + if (outIsTTY)
365 + for (cp = s; *cp; cp++)
366 + if (*cp == '\n')
367 + printf("\033[K\n");
368 + else
369 + putchar(*cp);
371 + else
373 + for (cp = s; *cp; cp++)
374 + putchar(*cp);
376 + return cp - s;
378 +#endif /* #ifdef DEBUG_DISASSEMBLER */
380 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
381 static void dumpVal(DataValue dv)
383 switch (dv.tag) {
384 case INT_TAG:
385 - printf("i=%d", dv.val.n);
386 + printd("i=%d", dv.val.n);
387 break;
388 case STRING_TAG:
390 @@ -3148,38 +3300,39 @@ static void dumpVal(DataValue dv)
391 char s[21];
392 char *src = dv.val.str.rep;
393 if (!src) {
394 - printf("s=<NULL>");
395 + printd("s=<NULL>");
397 else {
398 for (k = 0; src[k] && k < sizeof s - 1; k++) {
399 s[k] = isprint(src[k]) ? src[k] : '?';
401 s[k] = 0;
402 - printf("s=\"%s\"%s[%d]", s,
403 + printd("s=\"%s\"%s[%d]", s,
404 src[k] ? "..." : "", strlen(src));
407 break;
408 case ARRAY_TAG:
409 - printf("<%s>", tagToStr(ARRAY_TAG));
410 + printd("%08p <%s>[%d]", dv.val.arrayPtr, tagToStr(ARRAY_TAG),
411 + ArraySize(&dv));
412 break;
413 case NO_TAG:
414 if (!dv.val.inst) {
415 - printf("<%s>", tagToStr(NO_TAG));
416 + printd("<%s>", tagToStr(NO_TAG));
418 else {
419 - printf("?%8p", dv.val.inst);
420 + printd("?%8p", dv.val.inst);
422 break;
423 default:
424 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
425 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
426 break;
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 @@ -3188,15 +3341,15 @@ static void disasm(Inst *inst, int nInst
439 int i, j;
441 - printf("\n");
442 + printd("\n");
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) {
456 dumpVal(sym->value);
457 @@ -3204,29 +3357,29 @@ static void disasm(Inst *inst, int nInst
458 ++i;
460 else if (j == OP_PUSH_IMMED) {
461 - printf("i=%d", inst[i+1].value);
462 + printd("i=%d", inst[i+1].value);
463 ++i;
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);
470 ++i;
472 else if (j == OP_CONCAT) {
473 - printf("nExpr=%d", inst[i+1].value);
474 + printd("nExpr=%d", inst[i+1].value);
475 ++i;
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);
480 i += 2;
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);
485 ++i;
487 else if (j == OP_ARRAY_ITER) {
488 - printf("%s = %s++ end-loop=(%d) %p",
489 + printd("%s = %s++ end-loop=(%d) %p",
490 inst[i+1].sym->name,
491 inst[i+2].sym->name,
492 inst[i+3].value, &inst[i+3] + inst[i+3].value);
493 @@ -3234,68 +3387,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);
499 ++i;
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);
506 i += 2;
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");
513 ++i;
516 - printf("\n");
517 + printd("\n");
518 break;
521 if (j == N_OPS) {
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"); }
535 + outPrintd();
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);
545 - int i, offset;
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++) {
549 - char *pos = "";
550 - DataValue *dv = &StackP[-i - 1];
551 - if (dv < TheStack) {
552 - printf("--------------Stack base--------------\n");
553 - break;
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);
562 + DataValue *dv;
563 + DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
564 + int nArgs = FP_GET_ARG_COUNT(fp);
566 + int nSyms;
567 + static int symLen = 0;
568 + Symbol *syms = FP_GET_ITEM(fp, FP_SYMBOL_TABLE).val.sym;
569 + Symbol *sym;
571 +#ifdef DEBUG_STACK_HEADFIRST
572 +#else
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) {
581 + nSyms++;
582 + if (symLen < 27) {
583 + int len = strlen(sym->name);
584 + if (len > 27)
585 + len = 27;
586 + if (len > symLen)
587 + symLen = len;
589 - offset = dv - FrameP;
592 + /* output instructions between endDv and sp - 1 inclusive */
593 +#ifdef DEBUG_STACK_HEADFIRST
594 + dv = sp;
595 + while (--dv >= endDv)
596 +#else
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);
605 + char *pos = "";
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);
613 switch (offset) {
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;
627 default:
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);
637 + posFmt = "%6s ";
639 + else if (offset == 0) {
640 + pos = "FrameP";
642 break;
644 - printf("%-6s ", pos);
645 - dumpVal(*dv);
646 - printf("\n");
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;
654 + break;
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);
662 + else
663 + dumpVal(*dv);
665 + printd("\n");
668 +#ifdef DEBUG_STACK_HEADFIRST
669 + /* do caller's frame */
670 + if (oldFP || arg1 > endDv)
671 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
672 +#else
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");
686 +#else
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);
702 + if (outIsTTY)
703 + printd("\033[J\n");
705 + outPrintd();
706 + fflush(stdout);
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 {
714 Inst* inst;
715 struct DataValueTag* dataval;
716 struct SparseArrayEntryTag *arrayPtr;
717 + struct SymbolRec *sym;
718 } val;
719 } DataValue;
721 @@ -107,6 +108,7 @@ typedef struct ProgramTag {
722 Symbol *localSymList;
723 Inst *code;
724 unsigned refcount;
725 + char *name;
726 } Program;
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 @@ -546,7 +546,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,
738 + "replay macro");
739 if (prog == NULL) {
740 fprintf(stderr,
741 "NEdit internal error, learn/replay macro syntax error: %s\n",
742 @@ -644,7 +645,7 @@ static int readCheckMacroString(Widget d
743 char *stoppedAt, *errMsg;
744 Program *prog;
746 - prog = ParseMacro(string, &errMsg, &stoppedAt, True);
747 + prog = ParseMacro(string, &errMsg, &stoppedAt, True, errIn);
748 if (prog == NULL) {
749 if (errPos != NULL) {
750 *errPos = stoppedAt;
751 @@ -926,7 +927,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);
757 if (prog == NULL) {
758 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
759 XtFree(tMacro);
760 @@ -1190,7 +1191,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");
766 if (prog == NULL) {
767 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
768 errMsg);
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");
778 XtFree(tMacro);
779 if (prog == NULL) {
780 - ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
781 + ParseError(NULL, tMacro, stoppedAt, "-do macro", errMsg);
782 return False;
784 FreeProgram(prog);
785 diff --quilt old/source/parse.h new/source/parse.h
786 --- old/source/parse.h
787 +++ new/source/parse.h
788 @@ -30,6 +30,7 @@
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,
794 + const char *name);
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 @@ -632,10 +632,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,
806 + const char *name)
808 Program *prog;
809 AccumulatorData *acc = XtNew(AccumulatorData);
810 + static const char *prefix = ">> ";
812 #if YYDEBUG
813 int oldyydebug = yydebug;
814 @@ -670,6 +672,12 @@ Program *ParseMacro(char *expr, char **m
815 prog = FinishCreatingProgram(acc);
816 XtFree((char *)acc);
818 + if (!name)
819 + name = "--unknown--";
821 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
822 + strcat(strcpy(prog->name, prefix), name);
824 /* parse succeeded */
825 *msg = "";
826 *stoppedAt = InPtr;
827 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
828 --- old/source/smartIndent.c
829 +++ new/source/smartIndent.c
830 @@ -747,18 +747,18 @@ void BeginSmartIndent(WindowInfo *window
831 winData->inNewLineMacro = 0;
832 winData->inModMacro = 0;
833 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
834 - &stoppedAt, False);
835 + &stoppedAt, False, "smart indent newline macro");
836 if (winData->newlineMacro == NULL) {
837 XtFree((char *)winData);
838 - ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
839 - "newline macro", errMsg);
840 + ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
841 + "smart indent newline macro", errMsg);
842 return;
844 if (indentMacros->modMacro == NULL)
845 winData->modMacro = NULL;
846 else {
847 winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
848 - &stoppedAt, False);
849 + &stoppedAt, False, "smart indent modify macro");
850 if (winData->modMacro == NULL) {
851 FreeProgram(winData->newlineMacro);
852 XtFree((char *)winData);
853 @@ -1415,7 +1415,7 @@ static int checkSmartIndentDialogData(vo
854 if (!TextWidgetIsBlank(SmartIndentDialog.initMacro)) {
855 widgetText =ensureNewline(XmTextGetString(SmartIndentDialog.initMacro));
856 if (!CheckMacroString(SmartIndentDialog.shell, widgetText,
857 - "initialization macro", &stoppedAt)) {
858 + "smart indent initialization macro", &stoppedAt)) {
859 XmTextSetInsertionPosition(SmartIndentDialog.initMacro,
860 stoppedAt - widgetText);
861 XmProcessTraversal(SmartIndentDialog.initMacro, XmTRAVERSE_CURRENT);
862 @@ -1434,10 +1434,11 @@ static int checkSmartIndentDialogData(vo
865 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
866 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
867 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
868 + "smart indent newline macro");
869 if (prog == NULL) {
870 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
871 - "newline macro", errMsg);
872 + "smart indent newline macro", errMsg);
873 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
874 stoppedAt - widgetText);
875 XmProcessTraversal(SmartIndentDialog.newlineMacro, XmTRAVERSE_CURRENT);
876 @@ -1450,10 +1451,11 @@ static int checkSmartIndentDialogData(vo
877 /* Test compile the modify macro */
878 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
879 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
880 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
881 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
882 + "smart indent modify macro");
883 if (prog == NULL) {
884 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
885 - "modify macro", errMsg);
886 + "smart indent modify macro", errMsg);
887 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
888 stoppedAt - widgetText);
889 XmProcessTraversal(SmartIndentDialog.modMacro, XmTRAVERSE_CURRENT);
890 diff --quilt old/source/userCmds.c new/source/userCmds.c
891 --- old/source/userCmds.c
892 +++ new/source/userCmds.c
893 @@ -241,6 +241,8 @@ static Widget BGMenuPasteReplayBtn = NUL
894 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
895 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
896 int nMenuItems, int sensitive);
897 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
898 + menuItemRec **menu, int nMenu, const char *menuName);
899 static void rebuildMenuOfAllWindows(int menuType);
900 static void rebuildMenu(WindowInfo *window, int menuType);
901 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
902 @@ -1260,30 +1262,37 @@ int DoNamedShellMenuCmd(WindowInfo *wind
903 ** with menu item name "itemName". Returns True on successs and False on
904 ** failure.
906 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
907 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
908 + menuItemRec **menu, int nMenu, const char *menuName)
910 int i;
912 - for (i=0; i<NMacroMenuItems; i++) {
913 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
914 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
915 - return True;
917 + char *name = NULL;
918 + Boolean result = False;
920 + for (i = 0; i < nMenu; i++) {
921 + if (!strcmp(menu[i]->name, itemName)) {
922 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
923 + strcat(strcpy(name, menuName), itemName);
924 + DoMacro(window, menu[i]->cmd, name);
925 + result = True;
928 - return False;
929 + if (name) {
930 + XtFree(name);
932 + return result;
935 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
937 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
938 + "macro-menu>");
941 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
943 - int i;
945 - for (i=0; i<NBGMenuItems; i++) {
946 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
947 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
948 - return True;
951 - return False;
952 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
953 + "background-menu>");
957 @@ -2080,7 +2089,7 @@ static int checkMacroText(char *macro, W
958 Program *prog;
959 char *errMsg, *stoppedAt;
961 - prog = ParseMacro(macro, &errMsg, &stoppedAt, False);
962 + prog = ParseMacro(macro, &errMsg, &stoppedAt, False, "macro");
963 if (prog == NULL) {
964 if (errorParent != NULL) {
965 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
966 @@ -2092,7 +2101,7 @@ static int checkMacroText(char *macro, W
967 FreeProgram(prog);
968 if (*stoppedAt != '\0') {
969 if (errorParent != NULL) {
970 - ParseError(errorParent, macro, stoppedAt,"macro","syntax error");
971 + ParseError(errorParent, macro, stoppedAt, "macro", "syntax error");
972 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
973 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
975 @@ -3021,7 +3030,7 @@ static char *copyMacroToEnd(char **inPtr
978 /* Parse the input */
979 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False);
980 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False, "macro menu item");
981 if (prog == NULL) {
982 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);
983 return NULL;