refcount for Program
[nedit-bw.git] / InterpretDebug4.diff
blob774357828ac907d644cda01678e2294000e1984e
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 | 403 ++++++++++++++++++++++++++++++++++++++++++--------
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/parse_noyacc.c | 9 -
52 source/smartIndent.c | 22 +-
53 source/userCmds.c | 49 +++---
54 9 files changed, 410 insertions(+), 101 deletions(-)
56 diff --quilt old/source/interpret.c new/source/interpret.c
57 --- old/source/interpret.c
58 +++ new/source/interpret.c
59 @@ -36,11 +36,13 @@ static const char CVSID[] = "$Id: interp
60 #include "nedit.h"
61 #include "menu.h"
62 #include "text.h"
63 #include "rbTree.h"
65 +#include <unistd.h>
66 #include <stdio.h>
67 +#include <stdarg.h>
68 #include <stdlib.h>
69 #include <string.h>
70 #include <math.h>
71 #include <limits.h>
72 #include <ctype.h>
73 @@ -102,21 +104,25 @@ static const char *tagToStr(enum typeTag
74 /*#define DEBUG_ASSEMBLY*/
75 /*#define DEBUG_STACK*/
77 #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)
78 #define DEBUG_DISASSEMBLER
79 +static const char *printd(const char *f, ...);
80 +static int outPrintd();
81 static void disasm(Inst *inst, int nInstr);
82 +static void disasmInternal(Inst *inst, int nInstr);
83 #endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */
85 #ifdef DEBUG_ASSEMBLY /* for disassembly */
86 #define DISASM(i, n) disasm(i, n)
87 #else /* #ifndef DEBUG_ASSEMBLY */
88 #define DISASM(i, n)
89 #endif /* #ifndef DEBUG_ASSEMBLY */
91 #ifdef DEBUG_STACK /* for run-time instruction and stack trace */
92 static void stackdump(int n, int extra);
93 +static void stackdumpInternal(int n, int extra);
94 #define STACKDUMP(n, x) stackdump(n, x)
95 #define DISASM_RT(i, n) disasm(i, n)
96 #else /* #ifndef DEBUG_STACK */
97 #define STACKDUMP(n, x)
98 #define DISASM_RT(i, n)
99 @@ -170,18 +176,22 @@ static int (*OpFns[])() = {
100 #include "ops.h"
101 #undef OP
104 /* Stack-> symN-sym0(FP), argArray, nArgs, oldFP, retPC, argN-arg1, next, ... */
105 -#define FP_ARG_ARRAY_CACHE_INDEX (-1)
106 +#define FP_ARG_ARRAY_INDEX (-1)
107 #define FP_ARG_COUNT_INDEX (-2)
108 -#define FP_OLD_FP_INDEX (-3)
109 -#define FP_RET_PC_INDEX (-4)
110 -#define FP_PROG_INDEX (-5)
111 -#define FP_TO_ARGS_DIST (5) /* should be 0 - (above index) */
112 +#define FP_FUNCTION_NAME (-3) /* !! */
113 +#define FP_SYMBOL_TABLE (-4) /* !! */
114 +#define FP_OLD_FP_INDEX (-5)
115 +#define FP_RET_PC_INDEX (-6)
116 +#define FP_PROG_INDEX (-7)
118 +#define FP_TO_ARGS_DIST (0 - FP_RET_PC_INDEX) /* should be 0 - (above index) */
120 #define FP_GET_ITEM(xFrameP,xIndex) (*(xFrameP + xIndex))
121 -#define FP_GET_ARG_ARRAY_CACHE(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_CACHE_INDEX))
122 +#define FP_GET_ARG_ARRAY(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_ARRAY_INDEX))
123 #define FP_GET_ARG_COUNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_ARG_COUNT_INDEX).val.n)
124 #define FP_GET_OLD_FP(xFrameP) ((FP_GET_ITEM(xFrameP, FP_OLD_FP_INDEX)).val.dataval)
125 #define FP_GET_RET_PC(xFrameP) ((FP_GET_ITEM(xFrameP, FP_RET_PC_INDEX)).val.inst)
126 #define FP_GET_PROG(xFrameP) ((FP_GET_ITEM(xFrameP, FP_PROG_INDEX)).val.prog)
127 #define FP_ARG_START_INDEX(xFrameP) (-(FP_GET_ARG_COUNT(xFrameP) + FP_TO_ARGS_DIST))
128 @@ -265,10 +275,11 @@ Program *FinishCreatingProgram(Accumulat
129 newProg = (Program *)XtMalloc(sizeof(Program));
130 progLen = ((char *)ProgP) - ((char *)Prog);
131 newProg->code = (Inst *)XtMalloc(progLen);
132 memcpy(newProg->code, Prog, progLen);
133 newProg->localSymList = LocalSymList;
134 + newProg->name = NULL;
135 newProg->refcount = 1;
137 /* Local variables' values are stored on the stack. Here we assign
138 frame pointer offsets to them. */
139 for (s = newProg->localSymList; s != NULL; s = s->next)
140 @@ -289,10 +300,11 @@ Program *FinishCreatingProgram(Accumulat
141 void FreeProgram(Program *prog)
143 if (--prog->refcount == 0) {
144 freeSymbolTable(prog->localSymList);
145 XtFree((char *)prog->code);
146 + XtFree((char *)prog->name);
147 XtFree((char *)prog);
152 @@ -475,10 +487,19 @@ int ExecuteMacro(WindowInfo *window, Pro
153 context->stackP->tag = NO_TAG;
154 context->stackP++;
156 *(context->stackP++) = noValue; /* old FrameP */
158 + context->stackP->tag = NO_TAG;
159 + context->stackP->val.sym = prog->localSymList; /* symbol table */
160 + context->stackP++;
162 + context->stackP->tag = STRING_TAG;
163 + context->stackP->val.str.rep = prog->name ? prog->name : "<exec-macro>";
164 + context->stackP->val.str.len = strlen(context->stackP->val.str.rep);
165 + context->stackP++;
167 context->stackP->tag = NO_TAG; /* nArgs */
168 context->stackP->val.n = nArgs;
169 context->stackP++;
171 *(context->stackP++) = noValue; /* cached arg array */
172 @@ -578,10 +599,19 @@ void RunMacroAsSubrCall(Program *prog)
174 StackP->tag = NO_TAG;
175 StackP->val.dataval = FrameP; /* old FrameP */
176 StackP++;
178 + StackP->tag = NO_TAG;
179 + StackP->val.sym = prog->localSymList; /* symbol table */
180 + StackP++;
182 + StackP->tag = STRING_TAG;
183 + StackP->val.str.rep = prog->name ? prog->name : "<run-macro>";
184 + StackP->val.str.len = strlen(StackP->val.str.rep);
185 + StackP++;
187 StackP->tag = NO_TAG; /* nArgs */
188 StackP->val.n = 0;
189 StackP++;
191 *(StackP++) = noValue; /* cached arg array */
192 @@ -1380,11 +1410,11 @@ static int pushArgArray(void)
194 DISASM_RT(PC-1, 1);
195 STACKDUMP(0, 3);
197 nArgs = FP_GET_ARG_COUNT(FrameP);
198 - resultArray = &FP_GET_ARG_ARRAY_CACHE(FrameP);
199 + resultArray = &FP_GET_ARG_ARRAY(FrameP);
200 if (resultArray->tag != ARRAY_TAG) {
201 resultArray->tag = ARRAY_TAG;
202 resultArray->val.arrayPtr = ArrayNew();
204 for (argNum = 0; argNum < nArgs; ++argNum) {
205 @@ -2157,10 +2187,19 @@ static int callSubroutine(void)
207 StackP->tag = NO_TAG; /* old FrameP */
208 StackP->val.dataval = FrameP;
209 StackP++;
211 + StackP->tag = NO_TAG;
212 + StackP->val.sym = prog->localSymList; /* symbol table */
213 + StackP++;
215 + StackP->tag = STRING_TAG;
216 + StackP->val.str.rep = sym->name; /* function name */
217 + StackP->val.str.len = strlen(sym->name);
218 + StackP++;
220 StackP->tag = NO_TAG; /* nArgs */
221 StackP->val.n = nArgs;
222 StackP++;
224 *(StackP++) = noValue; /* cached arg array */
225 @@ -2704,11 +2743,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 @@ -2755,11 +2794,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 @@ -2793,13 +2832,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 @@ -2810,11 +2849,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 @@ -3064,20 +3103,75 @@ 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 - ErrMsg = msg;
351 + ErrMsg = stackDumpStr(FrameP, msg, &err, &errlen);
352 return STAT_ERROR;
355 int StringToNum(const char *string, int *number)
357 @@ -3123,168 +3217,353 @@ static const char *tagToStr(enum typeTag
358 return "<no value>";
362 #ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
363 +static char *printdBuffer = NULL;
364 +static int printdPos = 0;
365 +static int printdSize = 0;
367 +static const char *printd(const char *f, ...)
369 + char buffer[4096];
370 + int len;
371 + va_list args;
373 + if (!f)
375 + printdPos = 0; /* reset for next time */
376 + return printdBuffer;
379 + va_start(args, f);
380 + vsprintf(buffer, f, args);
381 + va_end(args);
383 + len = strlen(buffer);
384 + if (!printdBuffer)
386 + printdSize = 4096;
387 + printdBuffer = XtMalloc(printdSize);
388 + printdPos = 0;
390 + else
392 + int needSize = printdPos + len + 1;
393 + if (needSize > printdSize)
395 + int newSize = printdSize;
396 + while (newSize < needSize)
397 + newSize *= 2;
398 + printdBuffer = XtRealloc(printdBuffer, newSize);
399 + printdSize = newSize;
402 + strcpy(&printdBuffer[printdPos], buffer);
403 + printdPos += len;
405 + return printdBuffer;
408 +int outPrintd()
410 + const char *s = printd(NULL);
411 + const char *cp;
413 + static int outIsTTY = -1;
414 + if (outIsTTY == -1)
415 + outIsTTY = isatty(fileno(stdout));
417 + if (outIsTTY)
419 + for (cp = s; *cp; cp++)
420 + if (*cp == '\n')
421 + printf("\033[K\n");
422 + else
423 + putchar(*cp);
425 + else
427 + for (cp = s; *cp; cp++)
428 + putchar(*cp);
430 + return cp - s;
432 +#endif /* #ifdef DEBUG_DISASSEMBLER */
434 +#ifdef DEBUG_DISASSEMBLER /* dumping values in disassembly or stack dump */
435 static void dumpVal(DataValue dv)
437 switch (dv.tag) {
438 case INT_TAG:
439 - printf("i=%d", dv.val.n);
440 + printd("i=%d", dv.val.n);
441 break;
442 case STRING_TAG:
444 int k;
445 char s[21];
446 char *src = dv.val.str.rep;
447 if (!src) {
448 - printf("s=<NULL>");
449 + printd("s=<NULL>");
451 else {
452 for (k = 0; src[k] && k < sizeof s - 1; k++) {
453 s[k] = isprint(src[k]) ? src[k] : '?';
455 s[k] = 0;
456 - printf("s=\"%s\"%s[%d]", s,
457 + printd("s=\"%s\"%s[%d]", s,
458 src[k] ? "..." : "", strlen(src));
461 break;
462 case ARRAY_TAG:
463 - printf("<array>");
464 + printd("%08p <array>[%d]", dv.val.arrayPtr, ArraySize(&dv));
465 break;
466 case NO_TAG:
467 if (!dv.val.inst) {
468 - printf("<no value>");
469 + printd("<no value>");
471 else {
472 - printf("?%8p", dv.val.inst);
473 + printd("?%8p", dv.val.inst);
475 break;
476 default:
477 - printf("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
478 + printd("UNKNOWN DATA TAG %d ?%8p", dv.tag, dv.val.inst);
479 break;
482 #endif /* #ifdef DEBUG_DISASSEMBLER */
484 #ifdef DEBUG_DISASSEMBLER /* For debugging code generation */
485 -static void disasm(Inst *inst, int nInstr)
486 +static void disasmInternal(Inst *inst, int nInstr)
488 static const char *opNames[] = {
489 #define OP(name, fn) #name,
490 #include "ops.h"
491 #undef OP
493 int i, j;
495 - printf("\n");
496 + printd("\n");
497 for (i = 0; i < nInstr; ++i) {
498 - printf("Prog %8p ", &inst[i]);
499 + printd("Prog %8p ", &inst[i]);
500 for (j = 0; j < N_OPS; ++j) {
501 if (inst[i].func == OpFns[j]) {
502 - printf("%22s ", opNames[j]);
503 + printd("%22s ", opNames[j]);
504 if (j == OP_PUSH_SYM || j == OP_ASSIGN) {
505 Symbol *sym = inst[i+1].sym;
506 - printf("%s", sym->name);
507 + printd("%s", sym->name);
508 if (sym->value.tag == STRING_TAG &&
509 strncmp(sym->name, "string #", 8) == 0) {
510 dumpVal(sym->value);
512 ++i;
514 else if (j == OP_PUSH_IMMED) {
515 - printf("%d", inst[i+1].value);
516 + printd("%d", inst[i+1].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;
639 - offset = dv - FrameP;
642 + /* output instructions between endDv and sp - 1 inclusive */
643 +#ifdef DEBUG_STACK_HEADFIRST
644 + dv = sp;
645 + while (--dv >= endDv)
646 +#else
647 + for (dv = endDv; dv < sp; dv++)
648 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
650 + const char *posFmt = "%-6s ";
651 + const char *symName = "";
653 - printf("%4.4s", i < n ? ">>>>" : "");
654 - printf("%8p ", dv);
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_PROG_INDEX: pos = "Prog"; break;
670 + case FP_ARG_ARRAY_INDEX: pos = "args[]"; break; /* argument array */
671 + case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
672 + case FP_FUNCTION_NAME: pos = "FnName"; break;
673 + case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
674 + case FP_OLD_FP_INDEX: pos = "OldFP"; break;
675 + case FP_RET_PC_INDEX: pos = "RetPC"; break;
676 + case FP_PROG_INDEX: pos = "Prog"; break;
677 default:
678 - if (offset < -FP_TO_ARGS_DIST && offset >= -FP_TO_ARGS_DIST - nArgs) {
679 + if (offset < -FP_TO_ARGS_DIST &&
680 + offset >= -FP_TO_ARGS_DIST - nArgs)
682 sprintf(pos = buffer, STACK_DUMP_ARG_PREFIX "%d",
683 offset + FP_TO_ARGS_DIST + nArgs + 1);
685 + else if (0 <= offset && offset < nSyms) {
686 + sprintf(pos = buffer, offset ? "[%d]" : "FP[%d]", offset);
687 + posFmt = "%6s ";
689 + else if (offset == 0) {
690 + pos = "FrameP";
692 break;
694 - printf("%-6s ", pos);
695 - dumpVal(*dv);
696 - printf("\n");
697 + printd(posFmt, pos);
699 + /* local symbol names? */
700 + if (offset < nSyms) {
701 + for (sym = syms; sym != NULL; sym = sym->next) {
702 + if (sym->value.val.n == offset) {
703 + symName = sym->name;
704 + break;
708 + printd("%-*.*s ", symLen, symLen, symName);
710 + if (dv == fnNm && dv->tag == STRING_TAG && dv->val.str.rep)
711 + printd("%s", dv->val.str.rep);
712 + else
713 + dumpVal(*dv);
715 + printd("\n");
718 +#ifdef DEBUG_STACK_HEADFIRST
719 + /* do caller's frame */
720 + if (oldFP || arg1 > endDv)
721 + stackdumpframe(arrow, outpt, oldFP, arg1, ' ');
722 +#else
723 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
726 +static void stackdumpInternal(int n, int extra)
728 + DataValue *arrow = StackP - n;
729 + DataValue *outpt = StackP - n - extra;
731 +#ifdef DEBUG_STACK_HEADFIRST
732 + printd("Stack ----->\n");
733 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
734 + if (outpt < TheStack)
735 + printd("--------------Stack base--------------\n");
736 +#else
737 + if (outpt < TheStack)
738 + printd("--------------Stack base--------------\n");
739 + stackdumpframe(arrow, outpt, FrameP, StackP, '*');
740 + printd("Stack ----->\n");
741 +#endif /* #ifdef DEBUG_STACK_HEADFIRST */
744 +static void stackdump(int n, int extra)
746 + static int outIsTTY = -1;
747 + if (outIsTTY == -1)
748 + outIsTTY = isatty(fileno(stdout));
750 + stackdumpInternal(n, extra);
752 + if (outIsTTY)
753 + printd("\033[J\n");
755 + outPrintd();
756 + fflush(stdout);
759 #endif /* ifdef DEBUG_STACK */
760 diff --quilt old/source/interpret.h new/source/interpret.h
761 --- old/source/interpret.h
762 +++ new/source/interpret.h
763 @@ -84,10 +84,11 @@ typedef struct DataValueTag {
764 struct ProgramTag* prog;
765 XtActionProc xtproc;
766 Inst* inst;
767 struct DataValueTag* dataval;
768 struct SparseArrayEntryTag *arrayPtr;
769 + struct SymbolRec *sym;
770 } val;
771 } DataValue;
773 typedef struct SparseArrayEntryTag {
774 rbTreeNode nodePtrs; /* MUST BE FIRST ENTRY */
775 @@ -105,10 +106,11 @@ typedef struct SymbolRec {
777 typedef struct ProgramTag {
778 Symbol *localSymList;
779 Inst *code;
780 unsigned refcount;
781 + char *name;
782 } Program;
784 /* Information needed to re-start a preempted macro */
785 typedef struct {
786 DataValue *stack;
787 diff --quilt old/source/macro.c new/source/macro.c
788 --- old/source/macro.c
789 +++ new/source/macro.c
790 @@ -840,11 +840,12 @@ void Replay(WindowInfo *window)
791 if (ReplayMacro != NULL &&
792 ReplayMacro[0] != 0 &&
793 window->macroCmdData == NULL) {
794 /* Parse the replay macro (it's stored in text form) and compile it into
795 an executable program "prog" */
796 - prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False);
797 + prog = ParseMacro(ReplayMacro, &errMsg, &stoppedAt, False,
798 + "replay macro");
799 if (prog == NULL) {
800 fprintf(stderr,
801 "NEdit internal error, learn/replay macro syntax error: %s\n",
802 errMsg);
803 return;
804 @@ -938,11 +939,11 @@ static int readCheckMacroString(Widget d
805 WindowInfo *runWindow, const char *errIn, char **errPos)
807 char *stoppedAt, *errMsg;
808 Program *prog;
810 - prog = ParseMacro(string, &errMsg, &stoppedAt, True);
811 + prog = ParseMacro(string, &errMsg, &stoppedAt, True, errIn);
812 if (prog == NULL) {
813 if (errPos != NULL) {
814 *errPos = stoppedAt;
816 return ParseError(dialogParent, string, stoppedAt, errIn, errMsg);
817 @@ -1224,11 +1225,11 @@ void DoMacro(WindowInfo *window, const c
818 strncpy(tMacro, macro, macroLen);
819 tMacro[macroLen] = '\n';
820 tMacro[macroLen+1] = '\0';
822 /* Parse the macro and report errors if it fails */
823 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
824 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, errInName);
825 if (prog == NULL) {
826 ParseError(window->shell, tMacro, stoppedAt, errInName, errMsg);
827 XtFree(tMacro);
828 return;
830 @@ -1488,11 +1489,11 @@ selEnd += $text_length - startLength\n}\
831 sprintf(loopedCmd, loopMacro, command);
832 else
833 sprintf(loopedCmd, loopMacro, how, command);
835 /* Parse the resulting macro into an executable program "prog" */
836 - prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False);
837 + prog = ParseMacro(loopedCmd, &errMsg, &stoppedAt, False, "repeat macro");
838 if (prog == NULL) {
839 fprintf(stderr, "NEdit internal error, repeat macro syntax wrong: %s\n",
840 errMsg);
841 return;
843 diff --quilt old/source/nedit.c new/source/nedit.c
844 --- old/source/nedit.c
845 +++ new/source/nedit.c
846 @@ -830,14 +830,14 @@ static int checkDoMacroArg(const char *m
847 strncpy(tMacro, macro, macroLen);
848 tMacro[macroLen] = '\n';
849 tMacro[macroLen+1] = '\0';
851 /* Do a test parse */
852 - prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False);
853 + prog = ParseMacro(tMacro, &errMsg, &stoppedAt, False, "-do macro");
854 XtFree(tMacro);
855 if (prog == NULL) {
856 - ParseError(NULL, tMacro, stoppedAt, "argument to -do", errMsg);
857 + ParseError(NULL, tMacro, stoppedAt, "-do macro", errMsg);
858 return False;
860 FreeProgram(prog);
861 return True;
863 diff --quilt old/source/parse.h new/source/parse.h
864 --- old/source/parse.h
865 +++ new/source/parse.h
866 @@ -28,8 +28,9 @@
867 #ifndef NEDIT_PARSE_H_INCLUDED
868 #define NEDIT_PARSE_H_INCLUDED
870 #include "interpret.h"
872 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine);
873 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
874 + const char *name);
876 #endif /* NEDIT_PARSE_H_INCLUDED */
877 diff --quilt old/source/parse.y new/source/parse.y
878 --- old/source/parse.y
879 +++ new/source/parse.y
880 @@ -617,14 +617,16 @@ blank: /* nothing */
881 ** executed using ExecuteProgram. Returns program on success, or NULL
882 ** on failure. If the command failed, the error message is returned
883 ** as a pointer to a static string in msg, and the length of the string up
884 ** to where parsing failed in stoppedAt.
886 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine)
887 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, int allowDefine,
888 + const char *name)
890 Program *prog;
891 AccumulatorData *acc = (AccumulatorData *)XtMalloc(sizeof(*acc));
892 + static const char *prefix = ">> ";
894 BeginCreatingProgram(acc);
896 /* whether we allow the "define" keyword */
897 AllowDefine = allowDefine;
898 @@ -643,10 +645,16 @@ Program *ParseMacro(char *expr, char **m
900 /* get the newly created program */
901 prog = FinishCreatingProgram(acc);
902 XtFree((char *)acc);
904 + if (!name)
905 + name = "--unknown--";
907 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
908 + strcat(strcpy(prog->name, prefix), name);
910 /* parse succeeded */
911 *msg = "";
912 *stoppedAt = InPtr;
913 return prog;
915 diff --quilt old/source/parse_noyacc.c new/source/parse_noyacc.c
916 --- old/source/parse_noyacc.c
917 +++ new/source/parse_noyacc.c
918 @@ -744,13 +744,14 @@ int yystacksize;
919 ** executed using ExecuteProgram. Returns program on success, or NULL
920 ** on failure. If the command failed, the error message is returned
921 ** as a pointer to a static string in msg, and the length of the string up
922 ** to where parsing failed in stoppedAt.
924 -Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
925 +Program *ParseMacro(char *expr, char **msg, char **stoppedAt, const char *name)
927 Program *prog;
928 + static const char *prefix = ">> ";
930 BeginCreatingProgram();
932 /* call yyparse to parse the string and check for success. If the parse
933 failed, return the error message and string index (the grammar aborts
934 @@ -764,10 +765,16 @@ Program *ParseMacro(char *expr, char **m
937 /* get the newly created program */
938 prog = FinishCreatingProgram();
940 + if (!name)
941 + name = "--unknown--";
943 + prog->name = XtMalloc(strlen(name) + strlen(prefix) + 1);
944 + strcat(strcpy(prog->name, prefix), name);
946 /* parse succeeded */
947 *msg = "";
948 *stoppedAt = InPtr;
949 return prog;
951 diff --quilt old/source/smartIndent.c new/source/smartIndent.c
952 --- old/source/smartIndent.c
953 +++ new/source/smartIndent.c
954 @@ -745,21 +745,21 @@ void BeginSmartIndent(WindowInfo *window
955 /* Compile the newline and modify macros and attach them to the window */
956 winData = (windowSmartIndentData *)XtMalloc(sizeof(windowSmartIndentData));
957 winData->inNewLineMacro = 0;
958 winData->inModMacro = 0;
959 winData->newlineMacro = ParseMacro(indentMacros->newlineMacro, &errMsg,
960 - &stoppedAt, False);
961 + &stoppedAt, False, "smart indent newline macro");
962 if (winData->newlineMacro == NULL) {
963 - ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
964 - "newline macro", errMsg);
965 + ParseError(window->shell, indentMacros->newlineMacro, stoppedAt,
966 + "smart indent newline macro", errMsg);
967 return;
969 if (indentMacros->modMacro == NULL)
970 winData->modMacro = NULL;
971 else {
972 - winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
973 - &stoppedAt, False);
974 + winData->modMacro = ParseMacro(indentMacros->modMacro, &errMsg,
975 + &stoppedAt, False, "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 @@ -1410,11 +1410,11 @@ static int checkSmartIndentDialogData(vo
983 /* Check the initialization macro */
984 if (!TextWidgetIsBlank(SmartIndentDialog.initMacro)) {
985 widgetText =ensureNewline(XmTextGetString(SmartIndentDialog.initMacro));
986 if (!CheckMacroString(SmartIndentDialog.shell, widgetText,
987 - "initialization macro", &stoppedAt)) {
988 + "smart indent initialization macro", &stoppedAt)) {
989 XmTextSetInsertionPosition(SmartIndentDialog.initMacro,
990 stoppedAt - widgetText);
991 XmProcessTraversal(SmartIndentDialog.initMacro, XmTRAVERSE_CURRENT);
992 XtFree(widgetText);
993 return False;
994 @@ -1429,14 +1429,15 @@ static int checkSmartIndentDialogData(vo
995 "Newline macro required", "OK");
996 return False;
999 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.newlineMacro));
1000 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
1001 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
1002 + "smart indent newline macro");
1003 if (prog == NULL) {
1004 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1005 - "newline macro", errMsg);
1006 + "smart indent newline macro", errMsg);
1007 XmTextSetInsertionPosition(SmartIndentDialog.newlineMacro,
1008 stoppedAt - widgetText);
1009 XmProcessTraversal(SmartIndentDialog.newlineMacro, XmTRAVERSE_CURRENT);
1010 XtFree(widgetText);
1011 return False;
1012 @@ -1445,14 +1446,15 @@ static int checkSmartIndentDialogData(vo
1013 FreeProgram(prog);
1015 /* Test compile the modify macro */
1016 if (!TextWidgetIsBlank(SmartIndentDialog.modMacro)) {
1017 widgetText = ensureNewline(XmTextGetString(SmartIndentDialog.modMacro));
1018 - prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False);
1019 + prog = ParseMacro(widgetText, &errMsg, &stoppedAt, False,
1020 + "smart indent modify macro");
1021 if (prog == NULL) {
1022 ParseError(SmartIndentDialog.shell, widgetText, stoppedAt,
1023 - "modify macro", errMsg);
1024 + "smart indent modify macro", errMsg);
1025 XmTextSetInsertionPosition(SmartIndentDialog.modMacro,
1026 stoppedAt - widgetText);
1027 XmProcessTraversal(SmartIndentDialog.modMacro, XmTRAVERSE_CURRENT);
1028 XtFree(widgetText);
1029 return False;
1030 diff --quilt old/source/userCmds.c new/source/userCmds.c
1031 --- old/source/userCmds.c
1032 +++ new/source/userCmds.c
1033 @@ -239,10 +239,12 @@ static Widget MacroPasteReplayBtn = NULL
1034 static Widget BGMenuPasteReplayBtn = NULL;
1036 static void editMacroOrBGMenu(WindowInfo *window, int dialogType);
1037 static void dimSelDepItemsInMenu(Widget menuPane, menuItemRec **menuList,
1038 int nMenuItems, int sensitive);
1039 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1040 + menuItemRec **menu, int nMenu, const char *menuName);
1041 static void rebuildMenuOfAllWindows(int menuType);
1042 static void rebuildMenu(WindowInfo *window, int menuType);
1043 static Widget findInMenuTree(menuTreeItem *menuTree, int nTreeEntries,
1044 const char *hierName);
1045 static char *copySubstring(const char *string, int length);
1046 @@ -1258,34 +1260,41 @@ int DoNamedShellMenuCmd(WindowInfo *wind
1048 ** Search through the Macro or background menu and execute the first command
1049 ** with menu item name "itemName". Returns True on successs and False on
1050 ** failure.
1052 -int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1053 +static int doMacroMenuCmd(WindowInfo *window, const char *itemName,
1054 + menuItemRec **menu, int nMenu, const char *menuName)
1056 int i;
1058 - for (i=0; i<NMacroMenuItems; i++) {
1059 - if (!strcmp(MacroMenuItems[i]->name, itemName)) {
1060 - DoMacro(window, MacroMenuItems[i]->cmd, "macro menu command");
1061 - return True;
1063 + char *name = NULL;
1064 + Boolean result = False;
1066 + for (i = 0; i < nMenu; i++) {
1067 + if (!strcmp(menu[i]->name, itemName)) {
1068 + name = XtMalloc(strlen(menuName) + strlen(itemName) + 1);
1069 + strcat(strcpy(name, menuName), itemName);
1070 + DoMacro(window, menu[i]->cmd, name);
1071 + result = True;
1074 - return False;
1075 + if (name) {
1076 + XtFree(name);
1078 + return result;
1081 +int DoNamedMacroMenuCmd(WindowInfo *window, const char *itemName)
1083 + return doMacroMenuCmd(window, itemName, MacroMenuItems, NMacroMenuItems,
1084 + "macro-menu>");
1087 int DoNamedBGMenuCmd(WindowInfo *window, const char *itemName)
1089 - int i;
1091 - for (i=0; i<NBGMenuItems; i++) {
1092 - if (!strcmp(BGMenuItems[i]->name, itemName)) {
1093 - DoMacro(window, BGMenuItems[i]->cmd, "background menu macro");
1094 - return True;
1097 - return False;
1098 + return doMacroMenuCmd(window, itemName, BGMenuItems, NBGMenuItems,
1099 + "background-menu>");
1103 ** Cache user menus:
1104 ** Rebuild all of the Shell, Macro, Background menus of given editor window.
1105 @@ -2078,11 +2087,11 @@ static int checkMacro(userCmdDialog *ucd
1106 static int checkMacroText(char *macro, Widget errorParent, Widget errFocus)
1108 Program *prog;
1109 char *errMsg, *stoppedAt;
1111 - prog = ParseMacro(macro, &errMsg, &stoppedAt, False);
1112 + prog = ParseMacro(macro, &errMsg, &stoppedAt, False, "macro");
1113 if (prog == NULL) {
1114 if (errorParent != NULL) {
1115 ParseError(errorParent, macro, stoppedAt, "macro", errMsg);
1116 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1117 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1118 @@ -2090,11 +2099,11 @@ static int checkMacroText(char *macro, W
1119 return False;
1121 FreeProgram(prog);
1122 if (*stoppedAt != '\0') {
1123 if (errorParent != NULL) {
1124 - ParseError(errorParent, macro, stoppedAt,"macro","syntax error");
1125 + ParseError(errorParent, macro, stoppedAt, "macro", "syntax error");
1126 XmTextSetInsertionPosition(errFocus, stoppedAt - macro);
1127 XmProcessTraversal(errFocus, XmTRAVERSE_CURRENT);
1129 return False;
1131 @@ -3017,11 +3026,11 @@ static char *copyMacroToEnd(char **inPtr
1132 ParseError(NULL, *inPtr, *inPtr-1, "macro menu item", "expecting '{'");
1133 return NULL;
1136 /* Parse the input */
1137 - prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False);
1138 + prog = ParseMacro(*inPtr, &errMsg, &stoppedAt, False, "macro menu item");
1139 if (prog == NULL) {
1140 ParseError(NULL, *inPtr, stoppedAt, "macro menu item", errMsg);
1141 return NULL;
1143 FreeProgram(prog);