Added OpenMotif 2.2.3 and Lesstif 0.93.94 to the "known good" lists.
[nedit.git] / source / parse.y
blob119a0550e4c3a30138b414a5ca94bb3513f09ae5
1 /* $Id: parse.y,v 1.27 2003/12/19 23:23:31 slobasso Exp $ */
2 %{
3 #ifdef HAVE_CONFIG_H
4 #include "../config.h"
5 #endif
7 #include "parse.h"
8 #include "textBuf.h"
9 #include "nedit.h"
10 #include "rbTree.h"
11 #include "interpret.h"
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <ctype.h>
17 #include <X11/Intrinsic.h>
18 #include <Xm/Xm.h>
19 #ifdef VMS
20 #include "../util/VMSparam.h"
21 #else
22 #ifndef __MVS__
23 #include <sys/param.h>
24 #endif
25 #endif /*VMS*/
27 #ifdef HAVE_DEBUG_H
28 #include "../debug.h"
29 #endif
31 /* Macros to add error processing to AddOp and AddSym calls */
32 #define ADD_OP(op) if (!AddOp(op, &ErrMsg)) return 1
33 #define ADD_SYM(sym) if (!AddSym(sym, &ErrMsg)) return 1
34 #define ADD_IMMED(val) if (!AddImmediate(val, &ErrMsg)) return 1
35 #define ADD_BR_OFF(to) if (!AddBranchOffset(to, &ErrMsg)) return 1
36 #define SET_BR_OFF(from, to) *((int *)(from)) = ((Inst *)(to)) - ((Inst *)(from))
38 /* Max. length for a string constant (... there shouldn't be a maximum) */
39 #define MAX_STRING_CONST_LEN 5000
41 static const char CVSID[] = "$Id: parse.y,v 1.27 2003/12/19 23:23:31 slobasso Exp $";
42 static int yyerror(char *s);
43 static int yylex(void);
44 int yyparse(void);
45 static int follow(char expect, int yes, int no);
46 static int follow2(char expect1, int yes1, char expect2, int yes2, int no);
47 static int follow_non_whitespace(char expect, int yes, int no);
48 static Symbol *matchesActionRoutine(char **inPtr);
50 static char *ErrMsg;
51 static char *InPtr;
52 extern Inst *LoopStack[]; /* addresses of break, cont stmts */
53 extern Inst **LoopStackPtr; /* to fill at the end of a loop */
57 %union {
58 Symbol *sym;
59 Inst *inst;
60 int nArgs;
62 %token <sym> NUMBER STRING SYMBOL
63 %token DELETE ARG_LOOKUP
64 %token IF WHILE ELSE FOR BREAK CONTINUE RETURN
65 %type <nArgs> arglist
66 %type <inst> cond comastmts for while else and or arrayexpr
67 %type <sym> evalsym
69 %nonassoc IF_NO_ELSE
70 %nonassoc ELSE
72 %nonassoc SYMBOL ARG_LOOKUP
73 %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
74 %left CONCAT
75 %left OR
76 %left AND
77 %left '|'
78 %left '&'
79 %left GT GE LT LE EQ NE IN
80 %left '+' '-'
81 %left '*' '/' '%'
82 %nonassoc UNARY_MINUS NOT
83 %nonassoc DELETE
84 %nonassoc INCR DECR
85 %right POW
86 %nonassoc '['
87 %nonassoc '('
89 %% /* Rules */
91 program: blank stmts {
92 ADD_OP(OP_RETURN_NO_VAL); return 0;
94 | blank '{' blank stmts '}' {
95 ADD_OP(OP_RETURN_NO_VAL); return 0;
97 | blank '{' blank '}' {
98 ADD_OP(OP_RETURN_NO_VAL); return 0;
100 | error {
101 return 1;
104 block: '{' blank stmts '}' blank
105 | '{' blank '}' blank
106 | stmt
108 stmts: stmt
109 | stmts stmt
111 stmt: simpstmt '\n' blank
112 | IF '(' cond ')' blank block %prec IF_NO_ELSE {
113 SET_BR_OFF($3, GetPC());
115 | IF '(' cond ')' blank block else blank block %prec ELSE {
116 SET_BR_OFF($3, ($7+1)); SET_BR_OFF($7, GetPC());
118 | while '(' cond ')' blank block {
119 ADD_OP(OP_BRANCH); ADD_BR_OFF($1);
120 SET_BR_OFF($3, GetPC()); FillLoopAddrs(GetPC(), $1);
122 | for '(' comastmts ';' cond ';' comastmts ')' blank block {
123 FillLoopAddrs(GetPC()+2+($7-($5+1)), GetPC());
124 SwapCode($5+1, $7, GetPC());
125 ADD_OP(OP_BRANCH); ADD_BR_OFF($3); SET_BR_OFF($5, GetPC());
127 | for '(' SYMBOL IN arrayexpr ')' {
128 Symbol *iterSym = InstallIteratorSymbol();
129 ADD_OP(OP_BEGIN_ARRAY_ITER); ADD_SYM(iterSym);
130 ADD_OP(OP_ARRAY_ITER); ADD_SYM($3); ADD_SYM(iterSym); ADD_BR_OFF(0);
132 blank block {
133 ADD_OP(OP_BRANCH); ADD_BR_OFF($5+2);
134 SET_BR_OFF($5+5, GetPC());
135 FillLoopAddrs(GetPC(), $5+2);
137 | BREAK '\n' blank {
138 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
139 if (AddBreakAddr(GetPC()-1)) {
140 yyerror("break outside loop"); YYERROR;
143 | CONTINUE '\n' blank {
144 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
145 if (AddContinueAddr(GetPC()-1)) {
146 yyerror("continue outside loop"); YYERROR;
149 | RETURN expr '\n' blank {
150 ADD_OP(OP_RETURN);
152 | RETURN '\n' blank {
153 ADD_OP(OP_RETURN_NO_VAL);
156 simpstmt: SYMBOL '=' expr {
157 ADD_OP(OP_ASSIGN); ADD_SYM($1);
159 | evalsym ADDEQ expr {
160 ADD_OP(OP_ADD); ADD_OP(OP_ASSIGN); ADD_SYM($1);
162 | evalsym SUBEQ expr {
163 ADD_OP(OP_SUB); ADD_OP(OP_ASSIGN); ADD_SYM($1);
165 | evalsym MULEQ expr {
166 ADD_OP(OP_MUL); ADD_OP(OP_ASSIGN); ADD_SYM($1);
168 | evalsym DIVEQ expr {
169 ADD_OP(OP_DIV); ADD_OP(OP_ASSIGN); ADD_SYM($1);
171 | evalsym MODEQ expr {
172 ADD_OP(OP_MOD); ADD_OP(OP_ASSIGN); ADD_SYM($1);
174 | evalsym ANDEQ expr {
175 ADD_OP(OP_BIT_AND); ADD_OP(OP_ASSIGN); ADD_SYM($1);
177 | evalsym OREQ expr {
178 ADD_OP(OP_BIT_OR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
180 | DELETE arraylv '[' arglist ']' {
181 ADD_OP(OP_ARRAY_DELETE); ADD_IMMED((void *)$4);
183 | initarraylv '[' arglist ']' '=' expr {
184 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
186 | initarraylv '[' arglist ']' ADDEQ expr {
187 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
188 ADD_OP(OP_ADD);
189 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
191 | initarraylv '[' arglist ']' SUBEQ expr {
192 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
193 ADD_OP(OP_SUB);
194 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
196 | initarraylv '[' arglist ']' MULEQ expr {
197 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
198 ADD_OP(OP_MUL);
199 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
201 | initarraylv '[' arglist ']' DIVEQ expr {
202 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
203 ADD_OP(OP_DIV);
204 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
206 | initarraylv '[' arglist ']' MODEQ expr {
207 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
208 ADD_OP(OP_MOD);
209 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
211 | initarraylv '[' arglist ']' ANDEQ expr {
212 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
213 ADD_OP(OP_BIT_AND);
214 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
216 | initarraylv '[' arglist ']' OREQ expr {
217 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
218 ADD_OP(OP_BIT_OR);
219 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
221 | initarraylv '[' arglist ']' INCR {
222 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$3);
223 ADD_OP(OP_INCR);
224 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
226 | initarraylv '[' arglist ']' DECR {
227 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$3);
228 ADD_OP(OP_DECR);
229 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
231 | INCR initarraylv '[' arglist ']' {
232 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$4);
233 ADD_OP(OP_INCR);
234 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$4);
236 | DECR initarraylv '[' arglist ']' {
237 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$4);
238 ADD_OP(OP_DECR);
239 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$4);
241 | SYMBOL '(' arglist ')' {
242 ADD_OP(OP_SUBR_CALL);
243 ADD_SYM(PromoteToGlobal($1)); ADD_IMMED((void *)$3);
245 | INCR SYMBOL {
246 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR);
247 ADD_OP(OP_ASSIGN); ADD_SYM($2);
249 | SYMBOL INCR {
250 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_INCR);
251 ADD_OP(OP_ASSIGN); ADD_SYM($1);
253 | DECR SYMBOL {
254 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR);
255 ADD_OP(OP_ASSIGN); ADD_SYM($2);
257 | SYMBOL DECR {
258 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DECR);
259 ADD_OP(OP_ASSIGN); ADD_SYM($1);
262 evalsym: SYMBOL {
263 $$ = $1; ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
266 comastmts: /* nothing */ {
267 $$ = GetPC();
269 | simpstmt {
270 $$ = GetPC();
272 | comastmts ',' simpstmt {
273 $$ = GetPC();
276 arglist: /* nothing */ {
277 $$ = 0;
279 | expr {
280 $$ = 1;
282 | arglist ',' expr {
283 $$ = $1 + 1;
286 expr: numexpr %prec CONCAT
287 | expr numexpr %prec CONCAT {
288 ADD_OP(OP_CONCAT);
291 initarraylv: SYMBOL {
292 ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED((void *)1);
294 | initarraylv '[' arglist ']' {
295 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
298 arraylv: SYMBOL {
299 ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED((void *)0);
301 | arraylv '[' arglist ']' {
302 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
305 arrayexpr: numexpr {
306 $$ = GetPC();
309 numexpr: NUMBER {
310 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
312 | STRING {
313 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
315 | SYMBOL {
316 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
318 | SYMBOL '(' arglist ')' {
319 ADD_OP(OP_SUBR_CALL);
320 ADD_SYM(PromoteToGlobal($1)); ADD_IMMED((void *)$3);
321 ADD_OP(OP_FETCH_RET_VAL);
323 | '(' expr ')'
324 | ARG_LOOKUP '[' numexpr ']' {
325 ADD_OP(OP_PUSH_ARG);
327 | ARG_LOOKUP '[' ']' {
328 ADD_OP(OP_PUSH_ARG_COUNT);
330 | ARG_LOOKUP {
331 ADD_OP(OP_PUSH_ARG_ARRAY);
333 | numexpr '[' arglist ']' {
334 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
336 | numexpr '+' numexpr {
337 ADD_OP(OP_ADD);
339 | numexpr '-' numexpr {
340 ADD_OP(OP_SUB);
342 | numexpr '*' numexpr {
343 ADD_OP(OP_MUL);
345 | numexpr '/' numexpr {
346 ADD_OP(OP_DIV);
348 | numexpr '%' numexpr {
349 ADD_OP(OP_MOD);
351 | numexpr POW numexpr {
352 ADD_OP(OP_POWER);
354 | '-' numexpr %prec UNARY_MINUS {
355 ADD_OP(OP_NEGATE);
357 | numexpr GT numexpr {
358 ADD_OP(OP_GT);
360 | numexpr GE numexpr {
361 ADD_OP(OP_GE);
363 | numexpr LT numexpr {
364 ADD_OP(OP_LT);
366 | numexpr LE numexpr {
367 ADD_OP(OP_LE);
369 | numexpr EQ numexpr {
370 ADD_OP(OP_EQ);
372 | numexpr NE numexpr {
373 ADD_OP(OP_NE);
375 | numexpr '&' numexpr {
376 ADD_OP(OP_BIT_AND);
378 | numexpr '|' numexpr {
379 ADD_OP(OP_BIT_OR);
381 | numexpr and numexpr %prec AND {
382 ADD_OP(OP_AND); SET_BR_OFF($2, GetPC());
384 | numexpr or numexpr %prec OR {
385 ADD_OP(OP_OR); SET_BR_OFF($2, GetPC());
387 | NOT numexpr {
388 ADD_OP(OP_NOT);
390 | INCR SYMBOL {
391 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR);
392 ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2);
394 | SYMBOL INCR {
395 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP);
396 ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
398 | DECR SYMBOL {
399 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR);
400 ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2);
402 | SYMBOL DECR {
403 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP);
404 ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
406 | numexpr IN numexpr {
407 ADD_OP(OP_IN_ARRAY);
410 while: WHILE {
411 $$ = GetPC(); StartLoopAddrList();
414 for: FOR {
415 StartLoopAddrList(); $$ = GetPC();
418 else: ELSE {
419 ADD_OP(OP_BRANCH); $$ = GetPC(); ADD_BR_OFF(0);
422 cond: /* nothing */ {
423 ADD_OP(OP_BRANCH_NEVER); $$ = GetPC(); ADD_BR_OFF(0);
425 | numexpr {
426 ADD_OP(OP_BRANCH_FALSE); $$ = GetPC(); ADD_BR_OFF(0);
429 and: AND {
430 ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_FALSE); $$ = GetPC();
431 ADD_BR_OFF(0);
434 or: OR {
435 ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_TRUE); $$ = GetPC();
436 ADD_BR_OFF(0);
439 blank: /* nothing */
440 | blank '\n'
443 %% /* User Subroutines Section */
447 ** Parse a null terminated string and create a program from it (this is the
448 ** parser entry point). The program created by this routine can be
449 ** executed using ExecuteProgram. Returns program on success, or NULL
450 ** on failure. If the command failed, the error message is returned
451 ** as a pointer to a static string in msg, and the length of the string up
452 ** to where parsing failed in stoppedAt.
454 Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
456 Program *prog;
458 BeginCreatingProgram();
460 /* call yyparse to parse the string and check for success. If the parse
461 failed, return the error message and string index (the grammar aborts
462 parsing at the first error) */
463 InPtr = expr;
464 if (yyparse()) {
465 *msg = ErrMsg;
466 *stoppedAt = InPtr;
467 FreeProgram(FinishCreatingProgram());
468 return NULL;
471 /* get the newly created program */
472 prog = FinishCreatingProgram();
474 /* parse succeeded */
475 *msg = "";
476 *stoppedAt = InPtr;
477 return prog;
481 static int yylex(void)
483 int i, len;
484 Symbol *s;
485 static DataValue value = {NO_TAG, {0}};
486 static char escape[] = "\\\"ntbrfav";
487 static char replace[] = "\\\"\n\t\b\r\f\a\v";
489 /* skip whitespace, backslash-newline combinations, and comments, which are
490 all considered whitespace */
491 for (;;) {
492 if (*InPtr == '\\' && *(InPtr + 1) == '\n')
493 InPtr += 2;
494 else if (*InPtr == ' ' || *InPtr == '\t')
495 InPtr++;
496 else if (*InPtr == '#')
497 while (*InPtr != '\n' && *InPtr != '\0') {
498 /* Comments stop at escaped newlines */
499 if (*InPtr == '\\' && *(InPtr + 1) == '\n') {
500 InPtr += 2;
501 break;
503 InPtr++;
504 } else
505 break;
509 /* return end of input at the end of the string */
510 if (*InPtr == '\0') {
511 return 0;
514 /* process number tokens */
515 if (isdigit((unsigned char)*InPtr)) { /* number */
516 char name[28];
517 sscanf(InPtr, "%d%n", &value.val.n, &len);
518 sprintf(name, "const %d", value.val.n);
519 InPtr += len;
520 value.tag = INT_TAG;
521 if ((yylval.sym=LookupSymbol(name)) == NULL)
522 yylval.sym = InstallSymbol(name, CONST_SYM, value);
523 return NUMBER;
526 /* process symbol tokens. "define" is a special case not handled
527 by this parser, considered end of input. Another special case
528 is action routine names which are allowed to contain '-' despite
529 the ambiguity, handled in matchesActionRoutine. */
530 if (isalpha((unsigned char)*InPtr) || *InPtr == '$') {
531 if ((s=matchesActionRoutine(&InPtr)) == NULL) {
532 char symName[MAX_SYM_LEN+1], *p = symName;
533 *p++ = *InPtr++;
534 while (isalnum((unsigned char)*InPtr) || *InPtr=='_') {
535 if (p >= symName + MAX_SYM_LEN)
536 InPtr++;
537 else
538 *p++ = *InPtr++;
540 *p = '\0';
541 if (!strcmp(symName, "while")) return WHILE;
542 if (!strcmp(symName, "if")) return IF;
543 if (!strcmp(symName, "else")) return ELSE;
544 if (!strcmp(symName, "for")) return FOR;
545 if (!strcmp(symName, "break")) return BREAK;
546 if (!strcmp(symName, "continue")) return CONTINUE;
547 if (!strcmp(symName, "return")) return RETURN;
548 if (!strcmp(symName, "in")) return IN;
549 if (!strcmp(symName, "$args")) return ARG_LOOKUP;
550 if (!strcmp(symName, "delete") && follow_non_whitespace('(', SYMBOL, DELETE) == DELETE) return DELETE;
551 if (!strcmp(symName, "define")) {
552 InPtr -= 6;
553 return 0;
555 if ((s=LookupSymbol(symName)) == NULL) {
556 s = InstallSymbol(symName, symName[0]=='$' ?
557 (((symName[1] > '0' && symName[1] <= '9') && symName[2] == 0) ?
558 ARG_SYM : GLOBAL_SYM) : LOCAL_SYM, value);
559 s->value.tag = NO_TAG;
562 yylval.sym = s;
563 return SYMBOL;
566 /* process quoted strings w/ embedded escape sequences */
567 if (*InPtr == '\"') {
568 char string[MAX_STRING_CONST_LEN], *p = string;
569 InPtr++;
570 while (*InPtr != '\0' && *InPtr != '\"' && *InPtr != '\n') {
571 if (p >= string + MAX_STRING_CONST_LEN) {
572 InPtr++;
573 continue;
575 if (*InPtr == '\\') {
576 InPtr++;
577 if (*InPtr == '\n') {
578 InPtr++;
579 continue;
581 for (i=0; escape[i]!='\0'; i++) {
582 if (escape[i] == '\0') {
583 *p++= *InPtr++;
584 break;
585 } else if (escape[i] == *InPtr) {
586 *p++ = replace[i];
587 InPtr++;
588 break;
591 } else
592 *p++= *InPtr++;
594 *p = '\0';
595 InPtr++;
596 yylval.sym = InstallStringConstSymbol(string);
597 return STRING;
600 /* process remaining two character tokens or return single char as token */
601 switch(*InPtr++) {
602 case '>': return follow('=', GE, GT);
603 case '<': return follow('=', LE, LT);
604 case '=': return follow('=', EQ, '=');
605 case '!': return follow('=', NE, NOT);
606 case '+': return follow2('+', INCR, '=', ADDEQ, '+');
607 case '-': return follow2('-', DECR, '=', SUBEQ, '-');
608 case '|': return follow2('|', OR, '=', OREQ, '|');
609 case '&': return follow2('&', AND, '=', ANDEQ, '&');
610 case '*': return follow2('*', POW, '=', MULEQ, '*');
611 case '/': return follow('=', DIVEQ, '/');
612 case '%': return follow('=', MODEQ, '%');
613 case '^': return POW;
614 default: return *(InPtr-1);
619 ** look ahead for >=, etc.
621 static int follow(char expect, int yes, int no)
623 if (*InPtr++ == expect)
624 return yes;
625 InPtr--;
626 return no;
628 static int follow2(char expect1, int yes1, char expect2, int yes2, int no)
630 char next = *InPtr++;
631 if (next == expect1)
632 return yes1;
633 if (next == expect2)
634 return yes2;
635 InPtr--;
636 return no;
639 static int follow_non_whitespace(char expect, int yes, int no)
641 char *localInPtr = InPtr;
643 while (1) {
644 if (*localInPtr == ' ' || *localInPtr == '\t') {
645 ++localInPtr;
647 else if (*localInPtr == '\\' && *(localInPtr + 1) == '\n') {
648 localInPtr += 2;
650 else if (*localInPtr == expect) {
651 return(yes);
653 else {
654 return(no);
660 ** Look (way) ahead for hyphenated routine names which begin at inPtr. A
661 ** hyphenated name is allowed if it is pre-defined in the global symbol
662 ** table. If a matching name exists, returns the symbol, and update "inPtr".
664 ** I know this is horrible language design, but existing nedit action routine
665 ** names contain hyphens. Handling them here in the lexical analysis process
666 ** is much easier than trying to deal with it in the parser itself. (sorry)
668 static Symbol *matchesActionRoutine(char **inPtr)
670 char *c, *symPtr;
671 int hasDash = False;
672 char symbolName[MAX_SYM_LEN+1];
673 Symbol *s;
675 symPtr = symbolName;
676 for (c = *inPtr; isalnum((unsigned char)*c) || *c=='_' ||
677 ( *c=='-' && isalnum((unsigned char)(*(c+1)))); c++) {
678 if (*c == '-')
679 hasDash = True;
680 *symPtr++ = *c;
682 if (!hasDash)
683 return NULL;
684 *symPtr = '\0';
685 s = LookupSymbol(symbolName);
686 if (s != NULL)
687 *inPtr = c;
688 return s;
692 ** Called by yacc to report errors (just stores for returning when
693 ** parsing is aborted. The error token action is to immediate abort
694 ** parsing, so this message is immediately reported to the caller
695 ** of ParseExpr)
697 static int yyerror(char *s)
699 ErrMsg = s;
700 return 0;