fix macro_hooks patch
[nedit-bw.git] / runtime-loop-management.patch
blob0d2a54ce1897b9cf4d0503e1f158ef3a3c580353
1 ---
3 source/highlightData.c | 2
4 source/interpret.c | 320 ++++++++++++++++++++++++++++++++++---------------
5 source/interpret.h | 12 -
6 source/ops.h | 6
7 source/parse.y | 222 ++++++++++++++++++---------------
8 5 files changed, 353 insertions(+), 209 deletions(-)
10 diff --quilt old/source/interpret.c new/source/interpret.c
11 --- old/source/interpret.c
12 +++ new/source/interpret.c
13 @@ -72,17 +72,11 @@ static const char CVSID[] = "$Id: interp
14 allowed to execute before preempting and
15 returning to allow other things to run */
17 -/* Temporary markers placed in a branch address location to designate
18 - which loop address (break or continue) the location needs */
19 -#define NEEDS_BREAK 1
20 -#define NEEDS_CONTINUE 2
22 #define N_ARGS_ARG_VAR -1 /* special arg number meaning $n_args value */
23 #define MACRO_NAME_ARG_VAR -2 /* special arg number meaning $macro_name value */
25 enum opStatusCodes {STAT_OK=2, STAT_DONE, STAT_ERROR, STAT_PREEMPT};
27 -static int addLoopAddr(Inst *addr, char **msg);
28 static RestartData *setContext(RestartData *context);
30 #define OP(name, fn) static int fn(void);
31 @@ -170,8 +164,6 @@ static const char *StringToNumberMsg = "
32 static AccumulatorData *Accumulator;
33 #define Prog (Accumulator->prog)
34 #define ProgP (Accumulator->progP)
35 -#define LoopStack (Accumulator->loopStack)
36 -#define LoopStackPtr (Accumulator->loopStackPtr)
37 #define ProgramName (Accumulator->name)
39 /* Global data for the interpreter */
40 @@ -180,6 +172,8 @@ static RestartData *Interpreter;
41 #define TheStack (Interpreter->stack)
42 #define FrameP (Interpreter->frameP)
43 #define PC (Interpreter->pc)
44 +#define LoopStack (Interpreter->loopStack)
45 +#define LoopStackPtr (Interpreter->loopStackPtr)
46 #define InitiatingWindow (Interpreter->runWindow)
47 #define FocusWindow (Interpreter->focusWindow)
48 #define ErrMsg (Interpreter->errMsg)
49 @@ -198,10 +192,12 @@ static int (*OpFns[])() = {
50 #define FP_ARG_COUNT_INDEX (-1)
51 #define FP_FUNCTION_NAME (-2) /* !! */
52 #define FP_SYMBOL_TABLE (-3) /* !! */
53 -#define FP_OLD_FP_INDEX (-4)
54 -#define FP_RET_PC_INDEX (-5)
55 -#define FP_PROG_INDEX (-6)
56 -#define FP_ARG_ARRAY_INDEX (-7)
57 +#define FP_LOOP_CNT (-4)
58 +#define FP_OLD_LOOP_PTR (-5)
59 +#define FP_OLD_FP_INDEX (-6)
60 +#define FP_RET_PC_INDEX (-7)
61 +#define FP_PROG_INDEX (-8)
62 +#define FP_ARG_ARRAY_INDEX (-9)
64 #define FP_TO_ARGS_DIST (0 - FP_ARG_ARRAY_INDEX) /* should be 0 - (above index) */
66 @@ -216,6 +212,9 @@ static int (*OpFns[])() = {
67 #define FP_GET_ARG_N(xFrameP,xN) (FP_GET_ITEM(xFrameP, xN + FP_ARG_START_INDEX(xFrameP)))
68 #define FP_GET_SYM_TAB(xFrameP) (FP_GET_ITEM(xFrameP, FP_SYMBOL_TABLE).val.sym)
69 #define LocalSymList FP_GET_SYM_TAB(Interpreter->frameP)
70 +#define FP_GET_OLD_LOOP_PTR(xFrameP) (FP_GET_ITEM(xFrameP, FP_OLD_LOOP_PTR).val.instp)
71 +#define FP_GET_LOOP_CNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_LOOP_CNT).val.n)
72 +#define LoopStackCnt FP_GET_LOOP_CNT(Interpreter->frameP)
75 ** Initialize macro language global variables. Must be called before
76 @@ -280,7 +279,6 @@ AccumulatorData *BeginCreatingProgram(co
77 Accumulator = XtNew(AccumulatorData);
79 ProgP = Prog;
80 - LoopStackPtr = LoopStack;
81 ProgramName = name;
83 return old;
84 @@ -452,87 +450,6 @@ Inst *SwapCode(Inst *start, Inst *bounda
88 -** Maintain a stack to save addresses of branch operations for break and
89 -** continue statements, so they can be filled in once the information
90 -** on where to branch is known.
91 -**
92 -** Call StartLoopAddrList at the beginning of a loop, AddBreakAddr or
93 -** AddContinueAddr to register the address at which to store the branch
94 -** address for a break or continue statement, and FillLoopAddrs to fill
95 -** in all the addresses and return to the level of the enclosing loop.
96 -*/
97 -int StartLoopAddrList(char **msg)
99 - return addLoopAddr(NULL, msg);
102 -int AddBreakAddr(Inst *addr, char **msg)
104 - if (LoopStackPtr == LoopStack) {
105 - *msg = "break outside loop";
106 - return 0;
108 - if (addr->type != BRANCH_INST) {
109 - *msg = "not a branch instruction for break";
110 - return 0;
112 - if (!addLoopAddr(addr, msg)) {
113 - return 0;
115 - addr->val.immed = NEEDS_BREAK;
116 - return 1;
119 -int AddContinueAddr(Inst *addr, char **msg)
121 - if (LoopStackPtr == LoopStack) {
122 - *msg = "continue outside loop";
123 - return 0;
125 - if (addr->type != BRANCH_INST) {
126 - *msg = "not a branch instruction for break";
127 - return 0;
129 - if (!addLoopAddr(addr, msg)) {
130 - return 0;
132 - addr->val.immed = NEEDS_CONTINUE;
133 - return 1;
136 -static int addLoopAddr(Inst *addr, char **msg)
138 - if (LoopStackPtr >= &LoopStack[LOOP_STACK_SIZE]) {
139 - *msg = "loop stack overflow";
140 - return 0;
142 - *LoopStackPtr++ = addr;
143 - return 1;
146 -int FillLoopAddrs(Inst *breakAddr, Inst *continueAddr, char **msg)
148 - while (True) {
149 - LoopStackPtr--;
150 - if (LoopStackPtr < LoopStack) {
151 - *msg = "internal error (lsu)";
152 - return 0;
154 - if (*LoopStackPtr == NULL)
155 - break;
156 - if ((*LoopStackPtr)->val.immed == NEEDS_BREAK)
157 - (*LoopStackPtr)->val.branch = breakAddr - *LoopStackPtr;
158 - else if ((*LoopStackPtr)->val.immed == NEEDS_CONTINUE)
159 - (*LoopStackPtr)->val.branch = continueAddr - *LoopStackPtr;
160 - else {
161 - *msg = "internal error (uat)";
162 - return 0;
165 - return 1;
169 ** helper function to setup the next frame
171 static int setupFrame(RestartData *context, Program *prog,
172 @@ -587,6 +504,16 @@ static int setupFrame(RestartData *conte
173 context->stackP->val.dataval = context->frameP;
174 context->stackP++;
176 + /* remember old loop stack pointer */
177 + context->stackP->tag = NO_TAG;
178 + context->stackP->val.instp = context->loopStackPtr;
179 + context->stackP++;
181 + /* reset loop counter to zero */
182 + context->stackP->tag = NO_TAG;
183 + context->stackP->val.n = 0;
184 + context->stackP++;
186 /* start a new local symbol list */
187 context->stackP->tag = NO_TAG;
188 context->stackP->val.sym = NULL;
189 @@ -648,6 +575,9 @@ static void rewindFrame(RestartData *con
190 /* pop past arguments */
191 context->stackP -= (FP_TO_ARGS_DIST + nArgs);
193 + /* restore loop stack pointer */
194 + context->loopStackPtr = FP_GET_OLD_LOOP_PTR(context->frameP);
196 context->frameP = newFrameP;
198 PutProgram(prog);
199 @@ -697,6 +627,7 @@ int ExecuteMacro(WindowInfo *window, Pro
200 context = XtNew(RestartData);
201 *continuation = context;
202 context->stackP = context->stack;
203 + context->loopStackPtr = context->loopStack;
204 context->runWindow = window;
205 context->focusWindow = window;
207 @@ -1398,6 +1329,12 @@ static void addToGlobalSymTab(Symbol *sy
208 dataVal = *(StackP - (peekIndex) - 1); \
209 } while (0)
211 +#define SUBST(dataVal, substIndex) \
212 + do { \
213 + PEEK_CHECK(substIndex); \
214 + *(StackP - (substIndex) - 1) = dataVal; \
215 + } while (0)
217 #define TO_INT(dataVal, number) \
218 do { \
219 int __int; \
220 @@ -2068,6 +2005,37 @@ static int peekPush(void)
224 +** removes index from stack and shifts above elements down
225 +** Before: Prog-> [index], next, ...
226 +** TheStack-> val0, ... val{index-1}, valIndex, next, ...
227 +** After: Prog-> index, [next], ...
228 +** TheStack-> val0, ... val{index-1}, next, ...
230 +static int peekPop(void)
232 + DataValue value;
233 + int index, i;
235 + DISASM_RT();
237 + GET_IMMED(index);
239 + STACKDUMP(index + 1, 3);
241 + PEEK_CHECK(index);
243 + /* shift down elements */
244 + for (i = index; i > 0; i--) {
245 + PEEK(value, i - 1);
246 + SUBST(value, i);
248 + /* decr stack */
249 + POP(value);
251 + return STAT_OK;
255 ** if left and right arguments are arrays, then the result is a new array
256 ** in which all the keys from both the right and left are copied
257 ** the values from the right array are used in the result array when the
258 @@ -4110,6 +4078,141 @@ static int arrayNextNumIdx(void)
262 +** runtime loop management
265 +static int startLoop(void)
267 + Inst *addr;
269 + DISASM_RT();
270 + STACKDUMP(0, 3);
272 + GET_BRANCH(addr);
274 + if (LoopStackPtr >= &LoopStack[LOOP_STACK_SIZE]) {
275 + EXEC_ERROR("loop stack overflow", NULL);
278 + /* announce current endLoop addr */
279 + *LoopStackPtr++ = addr;
280 + LoopStackCnt++;
282 + return STAT_OK;
285 +static int endLoop(void)
287 + int count, ocount;
288 + int isCont = False;
289 + Inst *continueAddr;
291 + DISASM_RT();
292 + STACKDUMP(1, 3);
294 + GET_BRANCH(continueAddr);
296 + POP_INT(ocount);
297 + count = ocount;
298 + if (ocount < 0) {
299 + isCont = True;
300 + count = -(ocount + 1);
303 + if (count < 0 || count >= LoopStackCnt) {
304 + EXEC_ERROR("break outside loop", NULL);
307 + /* the trivial 'continue' */
308 + if (count == 0 && isCont) {
309 + JUMP(continueAddr);
310 + return STAT_OK;
313 + /* start finally */
314 + PUSH_INT(ocount);
315 + /* a finally can't break/continue surrounding loops */
316 + PUSH_INT(LoopStackCnt);
317 + LoopStackCnt = 0;
319 + return STAT_OK;
322 +static int finalizeLoop(void)
324 + Inst *addr;
325 + int count;
326 + int dec = -1;
328 + DISASM_RT();
329 + STACKDUMP(2, 3);
331 + /* restore loop count */
332 + POP_INT(LoopStackCnt);
333 + /* decrement loop */
334 + LoopStackCnt--;
335 + LoopStackPtr--;
337 + POP_INT(count);
338 + if (count < 0) {
339 + dec = 1;
342 + if (count > 0 || count < -1) {
343 + /* jump to outer loop endLoop */
344 + count += dec;
345 + PUSH_INT(count);
346 + JUMP(*(LoopStackPtr - 1));
349 + return STAT_OK;
352 +static int breakLoop(void)
354 + int count;
356 + DISASM_RT();
357 + STACKDUMP(1, 3);
359 + POP_INT(count);
361 + if (count < 0 || count >= LoopStackCnt) {
362 + EXEC_ERROR("break outside loop", NULL);
365 + /* a 'break' is indicated by a positive value */
366 + PUSH_INT(count);
368 + /* jump to current endLoop address */
369 + JUMP(*(LoopStackPtr - 1));
371 + return STAT_OK;
374 +static int continueLoop(void)
376 + int count;
378 + DISASM_RT();
379 + STACKDUMP(1, 3);
381 + POP_INT(count);
383 + if (count < 0 || count >= LoopStackCnt) {
384 + EXEC_ERROR("continue outside loop", NULL);
387 + /* a 'continue' is indicated by a negative value */
388 + PUSH_INT(-count - 1);
390 + /* jump to current endLoop address */
391 + JUMP(*(LoopStackPtr - 1));
393 + return STAT_OK;
397 ** checks errno after operations which can set it. If an error occured,
398 ** creates appropriate error messages and returns false
400 @@ -4676,6 +4779,7 @@ static void disasmInternal(Inst *inst, i
401 break;
403 case OP_PEEK_PUSH:
404 + case OP_PEEK_POP:
405 CHECK_OPERANDS(1, IMMED_INST);
406 dumpInst(&inst[i+1], "index");
407 ++i;
408 @@ -4690,6 +4794,18 @@ static void disasmInternal(Inst *inst, i
409 ++i;
410 break;
412 + case OP_START_LOOP:
413 + CHECK_OPERANDS(1, BRANCH_INST);
414 + dumpInst(&inst[i+1], "endLoopAddr");
415 + ++i;
416 + break;
418 + case OP_END_LOOP:
419 + CHECK_OPERANDS(1, BRANCH_INST);
420 + dumpInst(&inst[i+1], "continueAddr");
421 + ++i;
422 + break;
424 case OP_CONCAT:
425 CHECK_OPERANDS(1, IMMED_INST);
426 dumpInst(&inst[i+1], "nExpr");
427 @@ -4839,6 +4955,8 @@ static void stackdumpframe(DataValue *ar
428 DataValue *ofFP = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
429 DataValue *rpFP = &FP_GET_ITEM(fp, FP_RET_PC_INDEX);
430 DataValue *lsFP = &FP_GET_ITEM(fp, FP_SYMBOL_TABLE);
431 + DataValue *lcFP = &FP_GET_ITEM(fp, FP_LOOP_CNT);
432 + DataValue *olFP = &FP_GET_ITEM(fp, FP_OLD_LOOP_PTR);
433 DataValue *dv;
434 DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
435 int nArgs = FP_GET_ARG_COUNT(fp);
436 @@ -4860,7 +4978,7 @@ static void stackdumpframe(DataValue *ar
437 for (dv = endDv; dv < sp; dv++)
438 #endif /* #ifdef DEBUG_STACK_HEADFIRST */
440 - const char *posFmt = "%-6s";
441 + const char *posFmt = "%-7s";
443 char *pos = "";
444 char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
445 @@ -4873,6 +4991,8 @@ static void stackdumpframe(DataValue *ar
446 case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
447 case FP_FUNCTION_NAME: pos = "FnName"; break;
448 case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
449 + case FP_LOOP_CNT: pos = "LoopCnt";break;
450 + case FP_OLD_LOOP_PTR: pos = "OldLP"; break;
451 case FP_OLD_FP_INDEX: pos = "OldFP"; break;
452 case FP_RET_PC_INDEX: pos = "RetPC"; break;
453 case FP_PROG_INDEX: pos = "Prog"; break;
454 @@ -4921,12 +5041,20 @@ static void stackdumpframe(DataValue *ar
455 if (dv == lsFP) {
456 Symbol *s = dv->val.sym;
457 while (s) {
458 - printd("\n%*s%s", 22, s->name,
459 + printd("\n%*s%s", 23, s->name,
460 s->attr & READONLY_ATTR ? " readonly" : "");
461 dumpVal(s->value);
462 s = s->next;
465 + else
466 + if (dv == lcFP) {
467 + printd(" %d", dv->val.n);
469 + else
470 + if (dv == olFP) {
471 + printd(" %p", dv->val.instp);
473 else {
474 dumpVal(*dv);
476 diff --quilt old/source/interpret.h new/source/interpret.h
477 --- old/source/interpret.h
478 +++ new/source/interpret.h
479 @@ -37,8 +37,7 @@
480 events passed to action routines. Tells
481 them that they were called from a macro */
482 #define PROGRAM_SIZE 4096 /* Maximum program size */
483 -#define LOOP_STACK_SIZE 256 /* (Approx.) Number of break/continue stmts
484 - allowed per program */
485 +#define LOOP_STACK_SIZE 256 /* Number of nested loops allowed per program */
487 /* LOCAL_SYM -> LOCAL_SCOPE */
488 /* GLOBAL_SYM -> GLOBAL_SCOPE */
489 @@ -99,6 +98,7 @@ typedef struct DataValueTag {
490 struct ProgramTag* prog;
491 XtActionProc xtproc;
492 Inst* inst;
493 + Inst **instp;
494 struct DataValueTag* dataval;
495 struct SparseArrayEntryTag *arrayPtr;
496 struct SymbolRec *sym;
497 @@ -133,6 +133,8 @@ typedef struct {
498 DataValue *stackP;
499 DataValue *frameP;
500 Inst *pc;
501 + Inst *loopStack[LOOP_STACK_SIZE];
502 + Inst **loopStackPtr;
503 WindowInfo *runWindow;
504 WindowInfo *focusWindow;
505 char *errMsg;
506 @@ -142,8 +144,6 @@ typedef struct {
507 typedef struct AccumulatorDataTag {
508 Inst prog[PROGRAM_SIZE];
509 Inst *progP;
510 - Inst *loopStack[LOOP_STACK_SIZE];
511 - Inst **loopStackPtr;
512 const char *name;
513 } AccumulatorData;
515 @@ -175,10 +175,6 @@ Symbol *InstallSymbol(const char *name,
516 DataValue value);
517 const char *LookupString(const char *str, int create);
518 Inst *SwapCode(Inst *start, Inst *boundary, Inst *end);
519 -int StartLoopAddrList(char **msg);
520 -int AddBreakAddr(Inst *addr, char **msg);
521 -int AddContinueAddr(Inst *addr, char **msg);
522 -int FillLoopAddrs(Inst *breakAddr, Inst *continueAddr, char **msg);
524 /* create a permanently allocated static string */
525 #define PERM_ALLOC_STR(xStr) (char *)LookupString(xStr, 1)
526 diff --quilt old/source/parse.y new/source/parse.y
527 --- old/source/parse.y
528 +++ new/source/parse.y
529 @@ -65,29 +65,23 @@
530 return 1; \
532 } while (0)
533 -#define START_LOOP() \
534 +#define START_LOOP(endLoop) \
535 do { \
536 - if (!StartLoopAddrList(&ErrMsg)) { \
537 - return 1; \
538 - } \
539 + ADD_OP(OP_START_LOOP); \
540 + endLoop = GetPC(); \
541 + ADD_BR_OFF(0); \
542 } while (0)
543 -#define END_LOOP(breakAddr, continueAddr) \
544 +#define END_LOOP(startLoop, breakAddr, continueAddr) \
545 do { \
546 - if (!FillLoopAddrs(breakAddr, continueAddr, &ErrMsg)) { \
547 - return 1; \
548 - } \
549 - } while (0)
550 -#define ADD_BREAK(addr) \
551 - do { \
552 - if (!AddBreakAddr(addr, &ErrMsg)) { \
553 - return 1; \
554 - } \
555 - } while (0)
556 -#define ADD_CONTINUE(addr) \
557 - do { \
558 - if (!AddContinueAddr(addr, &ErrMsg)) { \
559 - return 1; \
560 - } \
561 + /* after body jump to continueAddr */ \
562 + ADD_OP(OP_BRANCH); ADD_BR_OFF(continueAddr); \
563 + /* cond == false => jump after body to simulated break */ \
564 + SET_BR_OFF(breakAddr, GetPC()); \
565 + /* simulated break statement */ \
566 + ADD_OP(OP_PUSH_IMMED); ADD_IMMED(0); \
567 + /* fill startLoop with endLoop addr */ \
568 + SET_BR_OFF(startLoop, GetPC()); \
569 + ADD_OP(OP_END_LOOP); ADD_BR_OFF(continueAddr); \
570 } while (0)
572 /* Max. length for a string constant (... there shouldn't be a maximum) */
573 @@ -128,8 +122,9 @@ static int nextSymIsField = 0;
574 %token <num> NUMBER
575 %token DELETE ARG_LOOKUP
576 %token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN DEFINE TYPEOF KEYVAL READONLY
577 +%token FINALLY
578 %type <num> keyargs key keyopt catlist fnarglsopt fnarglist fnarg
579 -%type <inst> cond comastmts comastmtlst for while do else and or arrayexpr mark
580 +%type <inst> cond branch for while do else and or mark
581 %type <str> evalsym
582 %type <acc> definesym
583 %type <oper> operassign incrdecr
584 @@ -143,6 +138,9 @@ static int nextSymIsField = 0;
585 %nonassoc IF_NO_ELSE
586 %nonassoc ELSE
588 +%nonassoc LOOP_NO_FINALLY
589 +%nonassoc FINALLY
591 %nonassoc ';'
592 %nonassoc SYMBOL ARG_LOOKUP
593 %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
594 @@ -245,94 +243,114 @@ stmt: ';' blank
595 | IF blank '(' cond ')' blank block else block %prec ELSE {
596 SET_BR_OFF($4, ($8+1)); SET_BR_OFF($8, GetPC());
598 - | while '(' cond ')' blank block {
599 - ADD_OP(OP_BRANCH); ADD_BR_OFF($1);
600 - SET_BR_OFF($3, GetPC());
601 - END_LOOP(GetPC(), $1);
603 - | do block WHILE blank '(' mark cond ')' stmtend blank {
604 - ADD_OP(OP_BRANCH); ADD_BR_OFF($1);
605 - SET_BR_OFF($7, GetPC());
606 - END_LOOP(GetPC(), $6);
608 - | for '(' comastmts ';' cond ';' comastmts ')' blank block {
609 - END_LOOP(GetPC()+2+($7-($5+1)), GetPC());
610 - SwapCode($5+1, $7, GetPC());
611 - ADD_OP(OP_BRANCH); ADD_BR_OFF($3); SET_BR_OFF($5, GetPC());
612 + | do mark block WHILE blank '(' mark cond ')' stmtend blank {
613 + /* after cond == true jump to body */
614 + ADD_OP(OP_BRANCH); ADD_BR_OFF($2);
615 + /* cond == false => jump after body to simulated break */
616 + SET_BR_OFF($8, GetPC());
617 + /* simulated break statement */
618 + ADD_OP(OP_PUSH_IMMED); ADD_IMMED(0);
619 + /* fill startLoop with endLoop addr */
620 + SET_BR_OFF($1, GetPC());
621 + /* continue is cond */
622 + ADD_OP(OP_END_LOOP); ADD_BR_OFF($7);
623 + /* empty finally block */
624 + ADD_OP(OP_FINALIZE_LOOP);
627 + | loops %prec LOOP_NO_FINALLY {
628 + /* empty finally block */
629 + ADD_OP(OP_FINALIZE_LOOP);
631 + | loops FINALLY blank block %prec FINALLY {
632 + ADD_OP(OP_FINALIZE_LOOP);
635 + | BREAK numexpropt stmtend blank {
636 + ADD_OP(OP_BREAK_LOOP);
638 + | CONTINUE numexpropt stmtend blank {
639 + ADD_OP(OP_CONTINUE_LOOP);
641 + | RETURN expr stmtend blank {
642 + ADD_OP(OP_RETURN);
644 + | RETURN stmtend blank {
645 + ADD_OP(OP_RETURN_NO_VAL);
649 +loops: while '(' mark cond ')' blank block {
650 + END_LOOP($1, $4, $3);
652 + | for '(' comastmts ';'
653 + mark cond branch ';'
654 + mark comastmts branch ')' blank
655 + mark block {
656 + /* cond == true => jump over 2nd comastmts to body */
657 + SET_BR_OFF($7, $14);
658 + /* after 2nd comastmts jump to cond */
659 + SET_BR_OFF($11, $5);
660 + END_LOOP($1, $6, $9);
662 - | for '(' blank SYMBOL IN blank arrayexpr blank ')' {
664 + | for '(' blank SYMBOL IN blank numexpr blank ')' mark blank block {
665 + Inst *here = GetPC();
666 ADD_OP(OP_BEGIN_ARRAY_ITER);
667 ADD_OP(OP_ARRAY_ITER);
668 ADD_IMMED(0); /* without val symbol */
669 ADD_SYM($4);
670 ADD_BR_OFF(0);
672 - blank block {
673 - ADD_OP(OP_BRANCH);
674 - ADD_BR_OFF($7+1);
675 - SET_BR_OFF($7+4, GetPC());
676 - END_LOOP(GetPC(), $7+1);
677 - ADD_OP(OP_POP); /* remove iter from stack */
679 - | for '(' blank SYMBOL KEYVAL SYMBOL IN blank arrayexpr blank ')' {
680 + SwapCode($10, here, GetPC());
681 + END_LOOP($1, $10 + 4, $10 + 1);
682 + /* remove iter from stack */
683 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
685 + | for '(' blank SYMBOL KEYVAL SYMBOL IN
686 + blank numexpr blank ')' mark blank block {
687 + Inst *here = GetPC();
688 ADD_OP(OP_BEGIN_ARRAY_ITER);
689 ADD_OP(OP_ARRAY_ITER);
690 ADD_IMMED(1); /* with val symbol */
691 ADD_SYM($4);
692 ADD_SYM($6);
693 ADD_BR_OFF(0);
694 + SwapCode($12, here, GetPC());
695 + END_LOOP($1, $12 + 5, $12 + 1);
696 + /* remove iter from stack */
697 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
699 - blank block {
700 - ADD_OP(OP_BRANCH);
701 - ADD_BR_OFF($9+1);
702 - SET_BR_OFF($9+5, GetPC());
703 - END_LOOP(GetPC(), $9+1);
704 - ADD_OP(OP_POP); /* remove iter from stack */
706 - | for '(' blank SYMBOL '[' numexpropt ']' IN blank arrayexpr blank ')' {
708 + | for '(' blank SYMBOL '[' numexpropt ']' IN
709 + blank numexpr blank ')' mark blank block {
710 + Inst *here = GetPC();
711 ADD_OP(OP_BEGIN_ARRAY_ITER_ARRAY);
712 ADD_OP(OP_ARRAY_ITER_ARRAY);
713 ADD_IMMED(0); /* without val symbol */
714 ADD_SYM($4);
715 ADD_BR_OFF(0);
717 - blank block {
718 - ADD_OP(OP_BRANCH);
719 - ADD_BR_OFF($10+1);
720 - SET_BR_OFF($10+4, GetPC());
721 - END_LOOP(GetPC(), $10+1);
722 - ADD_OP(OP_POP); /* remove iter from stack */
723 - ADD_OP(OP_POP); /* remove nDim from stack */
725 - | for '(' blank SYMBOL '[' numexpropt ']' KEYVAL SYMBOL IN blank arrayexpr blank ')' {
726 + SwapCode($13, here, GetPC());
727 + END_LOOP($1, $13 + 4, $13 + 1);
728 + /* remove iter from stack */
729 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
730 + /* remove nDim from stack */
731 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
733 + | for '(' blank SYMBOL '[' numexpropt ']' KEYVAL SYMBOL IN
734 + blank numexpr blank ')' mark blank block {
735 + Inst *here = GetPC();
736 ADD_OP(OP_BEGIN_ARRAY_ITER_ARRAY);
737 ADD_OP(OP_ARRAY_ITER_ARRAY);
738 ADD_IMMED(1); /* with val symbol */
739 ADD_SYM($4);
740 ADD_SYM($9);
741 ADD_BR_OFF(0);
743 - blank block {
744 - ADD_OP(OP_BRANCH);
745 - ADD_BR_OFF($12+1);
746 - SET_BR_OFF($12+5, GetPC());
747 - END_LOOP(GetPC(), $12+1);
748 - ADD_OP(OP_POP); /* remove iter from stack */
749 - ADD_OP(OP_POP); /* remove nDim from stack */
751 - | BREAK stmtend blank {
752 - ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
753 - ADD_BREAK(GetPC() - 1);
755 - | CONTINUE stmtend blank {
756 - ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
757 - ADD_CONTINUE(GetPC() - 1);
759 - | RETURN expr stmtend blank {
760 - ADD_OP(OP_RETURN);
762 - | RETURN stmtend blank {
763 - ADD_OP(OP_RETURN_NO_VAL);
764 + SwapCode($15, here, GetPC());
765 + END_LOOP($1, $15 + 5, $15 + 1);
766 + /* remove iter from stack */
767 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
768 + /* remove nDim from stack */
769 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
773 @@ -485,11 +503,11 @@ evalsym: SYMBOL {
777 -comastmts: blank { $$ = GetPC(); }
778 - | blank comastmtlst { $$ = $2; }
779 +comastmts: blank
780 + | blank comastmtlst
782 -comastmtlst: simpstmt blank { $$ = GetPC(); }
783 - | comastmtlst ',' blank simpstmt blank { $$ = GetPC(); }
784 +comastmtlst: simpstmt blank
785 + | comastmtlst ',' blank simpstmt blank
788 /* array key argument lists */
789 @@ -616,11 +634,6 @@ field: FIELD {
793 -arrayexpr: numexpr {
794 - $$ = GetPC();
798 /* anonymous arrays eg: array = { , "hi", .a=2, ["b"]="three" } */
799 arrconstr0: '{' {
800 /* create an empty array into which to add things */
801 @@ -717,24 +730,18 @@ numexpr: '(' blank expr blank ')'
802 | arrconstr
805 -numexpropt: blank {
806 +numexpropt: /* nothing */ {
807 ADD_OP(OP_PUSH_IMMED);
808 ADD_IMMED(0);
810 | numexpr
813 -while: WHILE blank {
814 - $$ = GetPC(); START_LOOP();
816 +while: WHILE blank { START_LOOP($$); }
818 -do: DO blank {
819 - $$ = GetPC(); START_LOOP();
821 +do: DO blank { START_LOOP($$); }
823 -for: FOR blank {
824 - START_LOOP(); $$ = GetPC();
826 +for: FOR blank { START_LOOP($$); }
828 else: ELSE blank {
829 ADD_OP(OP_BRANCH); $$ = GetPC(); ADD_BR_OFF(0);
830 @@ -785,6 +792,12 @@ dot: '.' %prec '.' {
834 +branch: /* nothing */ {
835 + ADD_OP(OP_BRANCH);
836 + $$ = GetPC();
837 + ADD_BR_OFF(0);
840 blank: /* nothing */
841 | blank '\n'
843 @@ -926,6 +939,7 @@ static int yylex(void)
844 if (!strcmp(symName, "define") && follow_non_whitespace('(', SYMBOL, DEFINE) == DEFINE) return DEFINE;
845 if (!strcmp(symName, "typeof")) return TYPEOF;
846 if (!strcmp(symName, "readonly")) return READONLY;
847 + if (!strcmp(symName, "finally")) return FINALLY;
849 yylval.str = LookupString(symName, True);
850 if (nextSymIsField) {
851 diff --quilt old/source/highlightData.c new/source/highlightData.c
852 --- old/source/highlightData.c
853 +++ new/source/highlightData.c
854 @@ -558,7 +558,7 @@ static char *DefaultPatternSets[] = {
855 Menu Actions:\"<(?:new(?:_tab|_opposite)?|open|open-dialog|open_dialog|open-selected|open_selected|close|save|save-as|save_as|save-as-dialog|save_as_dialog|revert-to-saved|revert_to_saved|revert_to_saved_dialog|include-file|include_file|include-file-dialog|include_file_dialog|load-macro-file|load_macro_file|load-macro-file-dialog|load_macro_file_dialog|load-tags-file|load_tags_file|load-tags-file-dialog|load_tags_file_dialog|unload_tags_file|load_tips_file|load_tips_file_dialog|unload_tips_file|print|print-selection|print_selection|exit|undo|redo|delete|select-all|select_all|shift-left|shift_left|shift-left-by-tab|shift_left_by_tab|shift-right|shift_right|shift-right-by-tab|shift_right_by_tab|find|find-dialog|find_dialog|find-again|find_again|find-selection|find_selection|find_incremental|start_incremental_find|replace|replace-dialog|replace_dialog|replace-all|replace_all|replace-in-selection|replace_in_selection|replace-again|replace_again|replace_find|replace_find_same|replace_find_again|goto-line-number|goto_line_number|goto-line-number-dialog|goto_line_number_dialog|goto-selected|goto_selected|mark|mark-dialog|mark_dialog|goto-mark|goto_mark|goto-mark-dialog|goto_mark_dialog|match|select_to_matching|goto_matching|find-definition|find_definition|show_tip|split-pane|split_pane|close-pane|close_pane|detach_document(?:_dialog)?|move_document_dialog|(?:next|previous|last)_document|uppercase|lowercase|fill-paragraph|fill_paragraph|control-code-dialog|control_code_dialog|filter-selection-dialog|filter_selection_dialog|filter-selection|filter_selection|execute-command|execute_command|execute-command-dialog|execute_command_dialog|execute-command-line|execute_command_line|shell-menu-command|shell_menu_command|macro-menu-command|macro_menu_command|bg_menu_command|post_window_bg_menu|post_tab_context_menu|beginning-of-selection|beginning_of_selection|end-of-selection|end_of_selection|repeat_macro|repeat_dialog|raise_window|focus_pane|set_statistics_line|set_incremental_search_line|set_show_line_numbers|set_auto_indent|set_wrap_text|set_wrap_margin|set_highlight_syntax|set_make_backup_copy|set_incremental_backup|set_show_matching|set_match_syntax_based|set_overtype_mode|set_locked|set_tab_dist|set_em_tab_dist|set_use_tabs|set_fonts|set_language_mode)(?=\\s*\\()\":::Subroutine::\n\
856 Text Actions:\"<(?:self-insert|self_insert|grab-focus|grab_focus|extend-adjust|extend_adjust|extend-start|extend_start|extend-end|extend_end|secondary-adjust|secondary_adjust|secondary-or-drag-adjust|secondary_or_drag_adjust|secondary-start|secondary_start|secondary-or-drag-start|secondary_or_drag_start|process-bdrag|process_bdrag|move-destination|move_destination|move-to|move_to|move-to-or-end-drag|move_to_or_end_drag|end_drag|copy-to|copy_to|copy-to-or-end-drag|copy_to_or_end_drag|exchange|process-cancel|process_cancel|paste-clipboard|paste_clipboard|copy-clipboard|copy_clipboard|cut-clipboard|cut_clipboard|copy-primary|copy_primary|cut-primary|cut_primary|newline|newline-and-indent|newline_and_indent|newline-no-indent|newline_no_indent|delete-selection|delete_selection|delete-previous-character|delete_previous_character|delete-next-character|delete_next_character|delete-previous-word|delete_previous_word|delete-next-word|delete_next_word|delete-to-start-of-line|delete_to_start_of_line|delete-to-end-of-line|delete_to_end_of_line|forward-character|forward_character|backward-character|backward_character|key-select|key_select|process-up|process_up|process-down|process_down|process-shift-up|process_shift_up|process-shift-down|process_shift_down|process-home|process_home|forward-word|forward_word|backward-word|backward_word|forward-paragraph|forward_paragraph|backward-paragraph|backward_paragraph|beginning-of-line|beginning_of_line|end-of-line|end_of_line|beginning-of-file|beginning_of_file|end-of-file|end_of_file|next-page|next_page|previous-page|previous_page|page-left|page_left|page-right|page_right|toggle-overstrike|toggle_overstrike|scroll-up|scroll_up|scroll-down|scroll_down|scroll_left|scroll_right|scroll-to-line|scroll_to_line|select-all|select_all|select_word|deselect-all|deselect_all|focusIn|focusOut|process-return|process_return|process-tab|process_tab|insert-string|insert_string|mouse_pan)(?=\\s*\\()\":::Subroutine::\n\
857 Macro Hooks:\"<(?:(?:pre|post)_(?:open|save)|cursor_moved|modified|(?:losing_)?focus|language_mode)_hook(?=\\s*\\()\":::Subroutine1::\n\
858 - Keyword:\"<(?:break|continue|define|delete|do|else|for|if|in|readonly|return|typeof|while)>\":::Keyword::\n\
859 + Keyword:\"<(?:break|continue|define|delete|do|else|finally|for|if|in|readonly|return|typeof|while)>\":::Keyword::\n\
860 Braces:\"[{}\\[\\]()<>,.:;~!&|^%*/?=+-]\":::Keyword::\n\
861 Global Variable:\"\\$[A-Za-z0-9_]+\":::Identifier1::\n\
862 String sq:\"'\":\"'\"::String::\n\
863 diff --quilt old/source/ops.h new/source/ops.h
864 --- old/source/ops.h
865 +++ new/source/ops.h
866 @@ -11,6 +11,7 @@ OP(PUSH_STRING, pushString)
867 OP(POP, popStack) /* pop(v) */
868 OP(DUP, dupStack) /* pop(v), push(v,v) */
869 OP(PEEK_PUSH, peekPush) /* n */ /* peek(v, n), push(v) */
870 +OP(PEEK_POP, peekPop) /* n */ /* pop(v0,..,vn), push(v0,...,v{n-1}) */
871 OP(ADD, add) /* pop(v2,v1), push(v1 + v2) */
872 OP(SUB, subtract) /* pop(v2,v1), push(v1 - v2) */
873 OP(MUL, multiply) /* pop(v2,v1), push(v1 * v2) */
874 @@ -67,3 +68,8 @@ OP(SUBR_CALL_UNPACK_ARRAY, callSubroutin
875 OP(TYPEOF_IN, typeOfIn) /* enable typeof() */
876 OP(TYPEOF_OUT, typeOfOut) /* pop(v), push(typeof(v)) */
877 OP(READONLY, readOnly) /* sym */ /* sym.attr |= READONLY_ATTR */
878 +OP(START_LOOP, startLoop)
879 +OP(END_LOOP, endLoop)
880 +OP(FINALIZE_LOOP, finalizeLoop)
881 +OP(BREAK_LOOP, breakLoop)
882 +OP(CONTINUE_LOOP, continueLoop)