3 source/highlightData.c | 2
4 source/interpret.c | 304 +++++++++++++++++++++++++++++++++----------------
5 source/interpret.h | 11 -
7 source/parse.y | 222 +++++++++++++++++++----------------
8 5 files changed, 336 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,11 @@ 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_FP_INDEX (-5)
59 +#define FP_RET_PC_INDEX (-6)
60 +#define FP_PROG_INDEX (-7)
61 +#define FP_ARG_ARRAY_INDEX (-8)
63 #define FP_TO_ARGS_DIST (0 - FP_ARG_ARRAY_INDEX) /* should be 0 - (above index) */
65 @@ -216,6 +211,8 @@ static int (*OpFns[])() = {
66 #define FP_GET_ARG_N(xFrameP,xN) (FP_GET_ITEM(xFrameP, xN + FP_ARG_START_INDEX(xFrameP)))
67 #define FP_GET_SYM_TAB(xFrameP) (FP_GET_ITEM(xFrameP, FP_SYMBOL_TABLE).val.sym)
68 #define LocalSymList FP_GET_SYM_TAB(Interpreter->frameP)
69 +#define FP_GET_LOOP_CNT(xFrameP) (FP_GET_ITEM(xFrameP, FP_LOOP_CNT).val.n)
70 +#define LoopStackCnt FP_GET_LOOP_CNT(Interpreter->frameP)
73 ** Initialize macro language global variables. Must be called before
74 @@ -280,7 +277,6 @@ AccumulatorData *BeginCreatingProgram(co
75 Accumulator = XtNew(AccumulatorData);
78 - LoopStackPtr = LoopStack;
82 @@ -452,87 +448,6 @@ Inst *SwapCode(Inst *start, Inst *bounda
86 -** Maintain a stack to save addresses of branch operations for break and
87 -** continue statements, so they can be filled in once the information
88 -** on where to branch is known.
90 -** Call StartLoopAddrList at the beginning of a loop, AddBreakAddr or
91 -** AddContinueAddr to register the address at which to store the branch
92 -** address for a break or continue statement, and FillLoopAddrs to fill
93 -** in all the addresses and return to the level of the enclosing loop.
95 -int StartLoopAddrList(char **msg)
97 - return addLoopAddr(NULL, msg);
100 -int AddBreakAddr(Inst *addr, char **msg)
102 - if (LoopStackPtr == LoopStack) {
103 - *msg = "break outside loop";
106 - if (addr->type != BRANCH_INST) {
107 - *msg = "not a branch instruction for break";
110 - if (!addLoopAddr(addr, msg)) {
113 - addr->val.immed = NEEDS_BREAK;
117 -int AddContinueAddr(Inst *addr, char **msg)
119 - if (LoopStackPtr == LoopStack) {
120 - *msg = "continue outside loop";
123 - if (addr->type != BRANCH_INST) {
124 - *msg = "not a branch instruction for break";
127 - if (!addLoopAddr(addr, msg)) {
130 - addr->val.immed = NEEDS_CONTINUE;
134 -static int addLoopAddr(Inst *addr, char **msg)
136 - if (LoopStackPtr >= &LoopStack[LOOP_STACK_SIZE]) {
137 - *msg = "loop stack overflow";
140 - *LoopStackPtr++ = addr;
144 -int FillLoopAddrs(Inst *breakAddr, Inst *continueAddr, char **msg)
148 - if (LoopStackPtr < LoopStack) {
149 - *msg = "internal error (lsu)";
152 - if (*LoopStackPtr == NULL)
154 - if ((*LoopStackPtr)->val.immed == NEEDS_BREAK)
155 - (*LoopStackPtr)->val.branch = breakAddr - *LoopStackPtr;
156 - else if ((*LoopStackPtr)->val.immed == NEEDS_CONTINUE)
157 - (*LoopStackPtr)->val.branch = continueAddr - *LoopStackPtr;
159 - *msg = "internal error (uat)";
167 ** helper function to setup the next frame
169 static int setupFrame(RestartData *context, Program *prog,
170 @@ -587,6 +502,11 @@ static int setupFrame(RestartData *conte
171 context->stackP->val.dataval = context->frameP;
174 + /* reset loop counter to zero */
175 + context->stackP->tag = NO_TAG;
176 + context->stackP->val.n = 0;
179 /* start a new local symbol list */
180 context->stackP->tag = NO_TAG;
181 context->stackP->val.sym = NULL;
182 @@ -697,6 +617,7 @@ int ExecuteMacro(WindowInfo *window, Pro
183 context = XtNew(RestartData);
184 *continuation = context;
185 context->stackP = context->stack;
186 + context->loopStackPtr = context->loopStack;
187 context->runWindow = window;
188 context->focusWindow = window;
190 @@ -1398,6 +1319,12 @@ static void addToGlobalSymTab(Symbol *sy
191 dataVal = *(StackP - (peekIndex) - 1); \
194 +#define SUBST(dataVal, substIndex) \
196 + PEEK_CHECK(substIndex); \
197 + *(StackP - (substIndex) - 1) = dataVal; \
200 #define TO_INT(dataVal, number) \
203 @@ -2068,6 +1995,37 @@ static int peekPush(void)
207 +** removes index from stack and shifts above elements down
208 +** Before: Prog-> [index], next, ...
209 +** TheStack-> val0, ... val{index-1}, valIndex, next, ...
210 +** After: Prog-> index, [next], ...
211 +** TheStack-> val0, ... val{index-1}, next, ...
213 +static int peekPop(void)
222 + STACKDUMP(index + 1, 3);
226 + /* shift down elements */
227 + for (i = index; i > 0; i--) {
228 + PEEK(value, i - 1);
238 ** if left and right arguments are arrays, then the result is a new array
239 ** in which all the keys from both the right and left are copied
240 ** the values from the right array are used in the result array when the
241 @@ -4110,6 +4068,141 @@ static int arrayNextNumIdx(void)
245 +** runtime loop management
248 +static int startLoop(void)
257 + if (LoopStackPtr >= &LoopStack[LOOP_STACK_SIZE]) {
258 + EXEC_ERROR("loop stack overflow", NULL);
261 + /* announce current endLoop addr */
262 + *LoopStackPtr++ = addr;
268 +static int endLoop(void)
271 + int isCont = False;
272 + Inst *continueAddr;
277 + GET_BRANCH(continueAddr);
283 + count = -(ocount + 1);
286 + if (count < 0 || count >= LoopStackCnt) {
287 + EXEC_ERROR("break outside loop", NULL);
290 + /* the trivial 'continue' */
291 + if (count == 0 && isCont) {
292 + JUMP(continueAddr);
296 + /* start finally */
298 + /* a finally can't break/continue surrounding loops */
299 + PUSH_INT(LoopStackCnt);
305 +static int finalizeLoop(void)
314 + /* restore loop count */
315 + POP_INT(LoopStackCnt);
316 + /* decrement loop */
325 + if (count > 0 || count < -1) {
326 + /* jump to outer loop endLoop */
329 + JUMP(*(LoopStackPtr - 1));
335 +static int breakLoop(void)
344 + if (count < 0 || count >= LoopStackCnt) {
345 + EXEC_ERROR("break outside loop", NULL);
348 + /* a 'break' is indicated by a positive value */
351 + /* jump to current endLoop address */
352 + JUMP(*(LoopStackPtr - 1));
357 +static int continueLoop(void)
366 + if (count < 0 || count >= LoopStackCnt) {
367 + EXEC_ERROR("continue outside loop", NULL);
370 + /* a 'continue' is indicated by a negative value */
371 + PUSH_INT(-count - 1);
373 + /* jump to current endLoop address */
374 + JUMP(*(LoopStackPtr - 1));
380 ** checks errno after operations which can set it. If an error occured,
381 ** creates appropriate error messages and returns false
383 @@ -4676,6 +4769,7 @@ static void disasmInternal(Inst *inst, i
388 CHECK_OPERANDS(1, IMMED_INST);
389 dumpInst(&inst[i+1], "index");
391 @@ -4690,6 +4784,18 @@ static void disasmInternal(Inst *inst, i
395 + case OP_START_LOOP:
396 + CHECK_OPERANDS(1, BRANCH_INST);
397 + dumpInst(&inst[i+1], "endLoopAddr");
402 + CHECK_OPERANDS(1, BRANCH_INST);
403 + dumpInst(&inst[i+1], "continueAddr");
408 CHECK_OPERANDS(1, IMMED_INST);
409 dumpInst(&inst[i+1], "nExpr");
410 @@ -4838,6 +4944,7 @@ static void stackdumpframe(DataValue *ar
411 DataValue *ofFP = &FP_GET_ITEM(fp, FP_OLD_FP_INDEX);
412 DataValue *rpFP = &FP_GET_ITEM(fp, FP_RET_PC_INDEX);
413 DataValue *lsFP = &FP_GET_ITEM(fp, FP_SYMBOL_TABLE);
414 + DataValue *lcFP = &FP_GET_ITEM(fp, FP_LOOP_CNT);
416 DataValue *endDv = (arg1 > outpt) ? arg1 : outpt;
417 int nArgs = FP_GET_ARG_COUNT(fp);
418 @@ -4859,7 +4966,7 @@ static void stackdumpframe(DataValue *ar
419 for (dv = endDv; dv < sp; dv++)
420 #endif /* #ifdef DEBUG_STACK_HEADFIRST */
422 - const char *posFmt = "%-6s";
423 + const char *posFmt = "%-7s";
426 char buffer[sizeof(STACK_DUMP_ARG_PREFIX) + TYPE_INT_STR_SIZE(int)];
427 @@ -4872,6 +4979,7 @@ static void stackdumpframe(DataValue *ar
428 case FP_ARG_COUNT_INDEX: pos = "NArgs"; break; /* num. arguments */
429 case FP_FUNCTION_NAME: pos = "FnName"; break;
430 case FP_SYMBOL_TABLE: pos = "FnSyms"; break;
431 + case FP_LOOP_CNT: pos = "LoopCnt";break;
432 case FP_OLD_FP_INDEX: pos = "OldFP"; break;
433 case FP_RET_PC_INDEX: pos = "RetPC"; break;
434 case FP_PROG_INDEX: pos = "Prog"; break;
435 @@ -4924,12 +5032,16 @@ static void stackdumpframe(DataValue *ar
437 Symbol *s = dv->val.sym;
439 - printd("\n%*s%s", 22, s->name,
440 + printd("\n%*s%s", 23, s->name,
441 s->attr & READONLY_ATTR ? " readonly" : "");
448 + printd(" %d", dv->val.n);
453 diff --quilt old/source/interpret.h new/source/interpret.h
454 --- old/source/interpret.h
455 +++ new/source/interpret.h
457 events passed to action routines. Tells
458 them that they were called from a macro */
459 #define PROGRAM_SIZE 4096 /* Maximum program size */
460 -#define LOOP_STACK_SIZE 256 /* (Approx.) Number of break/continue stmts
461 - allowed per program */
462 +#define LOOP_STACK_SIZE 256 /* Number of nested loops allowed per program */
464 /* LOCAL_SYM -> LOCAL_SCOPE */
465 /* GLOBAL_SYM -> GLOBAL_SCOPE */
466 @@ -133,6 +132,8 @@ typedef struct {
470 + Inst *loopStack[LOOP_STACK_SIZE];
471 + Inst **loopStackPtr;
472 WindowInfo *runWindow;
473 WindowInfo *focusWindow;
475 @@ -142,8 +143,6 @@ typedef struct {
476 typedef struct AccumulatorDataTag {
477 Inst prog[PROGRAM_SIZE];
479 - Inst *loopStack[LOOP_STACK_SIZE];
480 - Inst **loopStackPtr;
484 @@ -175,10 +174,6 @@ Symbol *InstallSymbol(const char *name,
486 const char *LookupString(const char *str, int create);
487 Inst *SwapCode(Inst *start, Inst *boundary, Inst *end);
488 -int StartLoopAddrList(char **msg);
489 -int AddBreakAddr(Inst *addr, char **msg);
490 -int AddContinueAddr(Inst *addr, char **msg);
491 -int FillLoopAddrs(Inst *breakAddr, Inst *continueAddr, char **msg);
493 /* create a permanently allocated static string */
494 #define PERM_ALLOC_STR(xStr) (char *)LookupString(xStr, 1)
495 diff --quilt old/source/parse.y new/source/parse.y
496 --- old/source/parse.y
497 +++ new/source/parse.y
502 -#define START_LOOP() \
503 +#define START_LOOP(endLoop) \
505 - if (!StartLoopAddrList(&ErrMsg)) { \
508 + ADD_OP(OP_START_LOOP); \
509 + endLoop = GetPC(); \
512 -#define END_LOOP(breakAddr, continueAddr) \
513 +#define END_LOOP(startLoop, breakAddr, continueAddr) \
515 - if (!FillLoopAddrs(breakAddr, continueAddr, &ErrMsg)) { \
519 -#define ADD_BREAK(addr) \
521 - if (!AddBreakAddr(addr, &ErrMsg)) { \
525 -#define ADD_CONTINUE(addr) \
527 - if (!AddContinueAddr(addr, &ErrMsg)) { \
530 + /* after body jump to continueAddr */ \
531 + ADD_OP(OP_BRANCH); ADD_BR_OFF(continueAddr); \
532 + /* cond == false => jump after body to simulated break */ \
533 + SET_BR_OFF(breakAddr, GetPC()); \
534 + /* simulated break statement */ \
535 + ADD_OP(OP_PUSH_IMMED); ADD_IMMED(0); \
536 + /* fill startLoop with endLoop addr */ \
537 + SET_BR_OFF(startLoop, GetPC()); \
538 + ADD_OP(OP_END_LOOP); ADD_BR_OFF(continueAddr); \
541 /* Max. length for a string constant (... there shouldn't be a maximum) */
542 @@ -128,8 +122,9 @@ static int nextSymIsField = 0;
544 %token DELETE ARG_LOOKUP
545 %token IF WHILE DO ELSE FOR BREAK CONTINUE RETURN DEFINE TYPEOF KEYVAL READONLY
547 %type <num> keyargs key keyopt catlist fnarglsopt fnarglist fnarg
548 -%type <inst> cond comastmts comastmtlst for while do else and or arrayexpr mark
549 +%type <inst> cond branch for while do else and or mark
551 %type <acc> definesym
552 %type <oper> operassign incrdecr
553 @@ -143,6 +138,9 @@ static int nextSymIsField = 0;
557 +%nonassoc LOOP_NO_FINALLY
561 %nonassoc SYMBOL ARG_LOOKUP
562 %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
563 @@ -245,94 +243,114 @@ stmt: ';' blank
564 | IF blank '(' cond ')' blank block else block %prec ELSE {
565 SET_BR_OFF($4, ($8+1)); SET_BR_OFF($8, GetPC());
567 - | while '(' cond ')' blank block {
568 - ADD_OP(OP_BRANCH); ADD_BR_OFF($1);
569 - SET_BR_OFF($3, GetPC());
570 - END_LOOP(GetPC(), $1);
572 - | do block WHILE blank '(' mark cond ')' stmtend blank {
573 - ADD_OP(OP_BRANCH); ADD_BR_OFF($1);
574 - SET_BR_OFF($7, GetPC());
575 - END_LOOP(GetPC(), $6);
577 - | for '(' comastmts ';' cond ';' comastmts ')' blank block {
578 - END_LOOP(GetPC()+2+($7-($5+1)), GetPC());
579 - SwapCode($5+1, $7, GetPC());
580 - ADD_OP(OP_BRANCH); ADD_BR_OFF($3); SET_BR_OFF($5, GetPC());
581 + | do mark block WHILE blank '(' mark cond ')' stmtend blank {
582 + /* after cond == true jump to body */
583 + ADD_OP(OP_BRANCH); ADD_BR_OFF($2);
584 + /* cond == false => jump after body to simulated break */
585 + SET_BR_OFF($8, GetPC());
586 + /* simulated break statement */
587 + ADD_OP(OP_PUSH_IMMED); ADD_IMMED(0);
588 + /* fill startLoop with endLoop addr */
589 + SET_BR_OFF($1, GetPC());
590 + /* continue is cond */
591 + ADD_OP(OP_END_LOOP); ADD_BR_OFF($7);
592 + /* empty finally block */
593 + ADD_OP(OP_FINALIZE_LOOP);
596 + | loops %prec LOOP_NO_FINALLY {
597 + /* empty finally block */
598 + ADD_OP(OP_FINALIZE_LOOP);
600 + | loops FINALLY blank block %prec FINALLY {
601 + ADD_OP(OP_FINALIZE_LOOP);
604 + | BREAK numexpropt stmtend blank {
605 + ADD_OP(OP_BREAK_LOOP);
607 + | CONTINUE numexpropt stmtend blank {
608 + ADD_OP(OP_CONTINUE_LOOP);
610 + | RETURN expr stmtend blank {
613 + | RETURN stmtend blank {
614 + ADD_OP(OP_RETURN_NO_VAL);
618 +loops: while '(' mark cond ')' blank block {
619 + END_LOOP($1, $4, $3);
621 + | for '(' comastmts ';'
622 + mark cond branch ';'
623 + mark comastmts branch ')' blank
625 + /* cond == true => jump over 2nd comastmts to body */
626 + SET_BR_OFF($7, $14);
627 + /* after 2nd comastmts jump to cond */
628 + SET_BR_OFF($11, $5);
629 + END_LOOP($1, $6, $9);
631 - | for '(' blank SYMBOL IN blank arrayexpr blank ')' {
633 + | for '(' blank SYMBOL IN blank numexpr blank ')' mark blank block {
634 + Inst *here = GetPC();
635 ADD_OP(OP_BEGIN_ARRAY_ITER);
636 ADD_OP(OP_ARRAY_ITER);
637 ADD_IMMED(0); /* without val symbol */
644 - SET_BR_OFF($7+4, GetPC());
645 - END_LOOP(GetPC(), $7+1);
646 - ADD_OP(OP_POP); /* remove iter from stack */
648 - | for '(' blank SYMBOL KEYVAL SYMBOL IN blank arrayexpr blank ')' {
649 + SwapCode($10, here, GetPC());
650 + END_LOOP($1, $10 + 4, $10 + 1);
651 + /* remove iter from stack */
652 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
654 + | for '(' blank SYMBOL KEYVAL SYMBOL IN
655 + blank numexpr blank ')' mark blank block {
656 + Inst *here = GetPC();
657 ADD_OP(OP_BEGIN_ARRAY_ITER);
658 ADD_OP(OP_ARRAY_ITER);
659 ADD_IMMED(1); /* with val symbol */
663 + SwapCode($12, here, GetPC());
664 + END_LOOP($1, $12 + 5, $12 + 1);
665 + /* remove iter from stack */
666 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
671 - SET_BR_OFF($9+5, GetPC());
672 - END_LOOP(GetPC(), $9+1);
673 - ADD_OP(OP_POP); /* remove iter from stack */
675 - | for '(' blank SYMBOL '[' numexpropt ']' IN blank arrayexpr blank ')' {
677 + | for '(' blank SYMBOL '[' numexpropt ']' IN
678 + blank numexpr blank ')' mark blank block {
679 + Inst *here = GetPC();
680 ADD_OP(OP_BEGIN_ARRAY_ITER_ARRAY);
681 ADD_OP(OP_ARRAY_ITER_ARRAY);
682 ADD_IMMED(0); /* without val symbol */
689 - SET_BR_OFF($10+4, GetPC());
690 - END_LOOP(GetPC(), $10+1);
691 - ADD_OP(OP_POP); /* remove iter from stack */
692 - ADD_OP(OP_POP); /* remove nDim from stack */
694 - | for '(' blank SYMBOL '[' numexpropt ']' KEYVAL SYMBOL IN blank arrayexpr blank ')' {
695 + SwapCode($13, here, GetPC());
696 + END_LOOP($1, $13 + 4, $13 + 1);
697 + /* remove iter from stack */
698 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
699 + /* remove nDim from stack */
700 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
702 + | for '(' blank SYMBOL '[' numexpropt ']' KEYVAL SYMBOL IN
703 + blank numexpr blank ')' mark blank block {
704 + Inst *here = GetPC();
705 ADD_OP(OP_BEGIN_ARRAY_ITER_ARRAY);
706 ADD_OP(OP_ARRAY_ITER_ARRAY);
707 ADD_IMMED(1); /* with val symbol */
715 - SET_BR_OFF($12+5, GetPC());
716 - END_LOOP(GetPC(), $12+1);
717 - ADD_OP(OP_POP); /* remove iter from stack */
718 - ADD_OP(OP_POP); /* remove nDim from stack */
720 - | BREAK stmtend blank {
721 - ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
722 - ADD_BREAK(GetPC() - 1);
724 - | CONTINUE stmtend blank {
725 - ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
726 - ADD_CONTINUE(GetPC() - 1);
728 - | RETURN expr stmtend blank {
731 - | RETURN stmtend blank {
732 - ADD_OP(OP_RETURN_NO_VAL);
733 + SwapCode($15, here, GetPC());
734 + END_LOOP($1, $15 + 5, $15 + 1);
735 + /* remove iter from stack */
736 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
737 + /* remove nDim from stack */
738 + ADD_OP(OP_PEEK_POP); ADD_IMMED(2);
742 @@ -485,11 +503,11 @@ evalsym: SYMBOL {
746 -comastmts: blank { $$ = GetPC(); }
747 - | blank comastmtlst { $$ = $2; }
749 + | blank comastmtlst
751 -comastmtlst: simpstmt blank { $$ = GetPC(); }
752 - | comastmtlst ',' blank simpstmt blank { $$ = GetPC(); }
753 +comastmtlst: simpstmt blank
754 + | comastmtlst ',' blank simpstmt blank
757 /* array key argument lists */
758 @@ -616,11 +634,6 @@ field: FIELD {
762 -arrayexpr: numexpr {
767 /* anonymous arrays eg: array = { , "hi", .a=2, ["b"]="three" } */
769 /* create an empty array into which to add things */
770 @@ -717,24 +730,18 @@ numexpr: '(' blank expr blank ')'
775 +numexpropt: /* nothing */ {
776 ADD_OP(OP_PUSH_IMMED);
782 -while: WHILE blank {
783 - $$ = GetPC(); START_LOOP();
785 +while: WHILE blank { START_LOOP($$); }
788 - $$ = GetPC(); START_LOOP();
790 +do: DO blank { START_LOOP($$); }
793 - START_LOOP(); $$ = GetPC();
795 +for: FOR blank { START_LOOP($$); }
798 ADD_OP(OP_BRANCH); $$ = GetPC(); ADD_BR_OFF(0);
799 @@ -785,6 +792,12 @@ dot: '.' %prec '.' {
803 +branch: /* nothing */ {
812 @@ -926,6 +939,7 @@ static int yylex(void)
813 if (!strcmp(symName, "define") && follow_non_whitespace('(', SYMBOL, DEFINE) == DEFINE) return DEFINE;
814 if (!strcmp(symName, "typeof")) return TYPEOF;
815 if (!strcmp(symName, "readonly")) return READONLY;
816 + if (!strcmp(symName, "finally")) return FINALLY;
818 yylval.str = LookupString(symName, True);
819 if (nextSymIsField) {
820 diff --quilt old/source/highlightData.c new/source/highlightData.c
821 --- old/source/highlightData.c
822 +++ new/source/highlightData.c
823 @@ -558,7 +558,7 @@ static char *DefaultPatternSets[] = {
824 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\
825 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\
826 Macro Hooks:\"<(?:(?:pre|post)_(?:open|save)|cursor_moved|modified|(?:losing_)?focus)_hook(?=\\s*\\()\":::Subroutine1::\n\
827 - Keyword:\"<(?:break|continue|define|delete|do|else|for|if|in|readonly|return|typeof|while)>\":::Keyword::\n\
828 + Keyword:\"<(?:break|continue|define|delete|do|else|finally|for|if|in|readonly|return|typeof|while)>\":::Keyword::\n\
829 Braces:\"[{}\\[\\]]\":::Keyword::\n\
830 Global Variable:\"\\$[A-Za-z0-9_]+\":::Identifier1::\n\
831 String sq:\"'\":\"'\"::String::\n\
832 diff --quilt old/source/ops.h new/source/ops.h
835 @@ -11,6 +11,7 @@ OP(PUSH_STRING, pushString)
836 OP(POP, popStack) /* pop(v) */
837 OP(DUP, dupStack) /* pop(v), push(v,v) */
838 OP(PEEK_PUSH, peekPush) /* n */ /* peek(v, n), push(v) */
839 +OP(PEEK_POP, peekPop) /* n */ /* pop(v0,..,vn), push(v0,...,v{n-1}) */
840 OP(ADD, add) /* pop(v2,v1), push(v1 + v2) */
841 OP(SUB, subtract) /* pop(v2,v1), push(v1 - v2) */
842 OP(MUL, multiply) /* pop(v2,v1), push(v1 * v2) */
843 @@ -67,3 +68,8 @@ OP(SUBR_CALL_UNPACK_ARRAY, callSubroutin
844 OP(TYPEOF_IN, typeOfIn) /* enable typeof() */
845 OP(TYPEOF_OUT, typeOfOut) /* pop(v), push(typeof(v)) */
846 OP(READONLY, readOnly) /* sym */ /* sym.attr |= READONLY_ATTR */
847 +OP(START_LOOP, startLoop)
848 +OP(END_LOOP, endLoop)
849 +OP(FINALIZE_LOOP, finalizeLoop)
850 +OP(BREAK_LOOP, breakLoop)
851 +OP(CONTINUE_LOOP, continueLoop)