Merged patch #734202: Warnings Removal (Thorsten).
[nedit.git] / source / parse.y
blob31083aaed83a8a96505dd9e30775e9477f889a94
1 /* $Id: parse.y,v 1.25 2003/05/07 10:51:52 edg 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.25 2003/05/07 10:51:52 edg 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 IF WHILE ELSE FOR BREAK CONTINUE RETURN
64 %type <nArgs> arglist
65 %type <inst> cond comastmts for while else and or arrayexpr
66 %type <sym> evalsym
68 %nonassoc IF_NO_ELSE
69 %nonassoc ELSE
71 %nonassoc SYMBOL
72 %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
73 %left CONCAT
74 %left OR
75 %left AND
76 %left '|'
77 %left '&'
78 %left GT GE LT LE EQ NE IN
79 %left '+' '-'
80 %left '*' '/' '%'
81 %nonassoc UNARY_MINUS NOT
82 %nonassoc DELETE
83 %nonassoc INCR DECR
84 %right POW
85 %nonassoc '['
86 %nonassoc '('
88 %% /* Rules */
90 program: blank stmts {
91 ADD_OP(OP_RETURN_NO_VAL); return 0;
93 | blank '{' blank stmts '}' {
94 ADD_OP(OP_RETURN_NO_VAL); return 0;
96 | blank '{' blank '}' {
97 ADD_OP(OP_RETURN_NO_VAL); return 0;
99 | error {
100 return 1;
103 block: '{' blank stmts '}' blank
104 | '{' blank '}' blank
105 | stmt
107 stmts: stmt
108 | stmts stmt
110 stmt: simpstmt '\n' blank
111 | IF '(' cond ')' blank block %prec IF_NO_ELSE {
112 SET_BR_OFF($3, GetPC());
114 | IF '(' cond ')' blank block else blank block %prec ELSE {
115 SET_BR_OFF($3, ($7+1)); SET_BR_OFF($7, GetPC());
117 | while '(' cond ')' blank block {
118 ADD_OP(OP_BRANCH); ADD_BR_OFF($1);
119 SET_BR_OFF($3, GetPC()); FillLoopAddrs(GetPC(), $1);
121 | for '(' comastmts ';' cond ';' comastmts ')' blank block {
122 FillLoopAddrs(GetPC()+2+($7-($5+1)), GetPC());
123 SwapCode($5+1, $7, GetPC());
124 ADD_OP(OP_BRANCH); ADD_BR_OFF($3); SET_BR_OFF($5, GetPC());
126 | for '(' SYMBOL IN arrayexpr ')' {
127 Symbol *iterSym = InstallIteratorSymbol();
128 ADD_OP(OP_BEGIN_ARRAY_ITER); ADD_SYM(iterSym);
129 ADD_OP(OP_ARRAY_ITER); ADD_SYM($3); ADD_SYM(iterSym); ADD_BR_OFF(0);
131 blank block {
132 ADD_OP(OP_BRANCH); ADD_BR_OFF($5+2);
133 SET_BR_OFF($5+5, GetPC());
134 FillLoopAddrs(GetPC(), $5+2);
136 | BREAK '\n' blank {
137 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
138 if (AddBreakAddr(GetPC()-1)) {
139 yyerror("break outside loop"); YYERROR;
142 | CONTINUE '\n' blank {
143 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
144 if (AddContinueAddr(GetPC()-1)) {
145 yyerror("continue outside loop"); YYERROR;
148 | RETURN expr '\n' blank {
149 ADD_OP(OP_RETURN);
151 | RETURN '\n' blank {
152 ADD_OP(OP_RETURN_NO_VAL);
155 simpstmt: SYMBOL '=' expr {
156 ADD_OP(OP_ASSIGN); ADD_SYM($1);
158 | evalsym ADDEQ expr {
159 ADD_OP(OP_ADD); ADD_OP(OP_ASSIGN); ADD_SYM($1);
161 | evalsym SUBEQ expr {
162 ADD_OP(OP_SUB); ADD_OP(OP_ASSIGN); ADD_SYM($1);
164 | evalsym MULEQ expr {
165 ADD_OP(OP_MUL); ADD_OP(OP_ASSIGN); ADD_SYM($1);
167 | evalsym DIVEQ expr {
168 ADD_OP(OP_DIV); ADD_OP(OP_ASSIGN); ADD_SYM($1);
170 | evalsym MODEQ expr {
171 ADD_OP(OP_MOD); ADD_OP(OP_ASSIGN); ADD_SYM($1);
173 | evalsym ANDEQ expr {
174 ADD_OP(OP_BIT_AND); ADD_OP(OP_ASSIGN); ADD_SYM($1);
176 | evalsym OREQ expr {
177 ADD_OP(OP_BIT_OR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
179 | DELETE arraylv '[' arglist ']' {
180 ADD_OP(OP_ARRAY_DELETE); ADD_IMMED((void *)$4);
182 | initarraylv '[' arglist ']' '=' expr {
183 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
185 | initarraylv '[' arglist ']' ADDEQ expr {
186 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
187 ADD_OP(OP_ADD);
188 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
190 | initarraylv '[' arglist ']' SUBEQ expr {
191 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
192 ADD_OP(OP_SUB);
193 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
195 | initarraylv '[' arglist ']' MULEQ expr {
196 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
197 ADD_OP(OP_MUL);
198 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
200 | initarraylv '[' arglist ']' DIVEQ expr {
201 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
202 ADD_OP(OP_DIV);
203 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
205 | initarraylv '[' arglist ']' MODEQ expr {
206 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
207 ADD_OP(OP_MOD);
208 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
210 | initarraylv '[' arglist ']' ANDEQ expr {
211 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
212 ADD_OP(OP_BIT_AND);
213 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
215 | initarraylv '[' arglist ']' OREQ expr {
216 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
217 ADD_OP(OP_BIT_OR);
218 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
220 | initarraylv '[' arglist ']' INCR {
221 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$3);
222 ADD_OP(OP_INCR);
223 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
225 | initarraylv '[' arglist ']' DECR {
226 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$3);
227 ADD_OP(OP_DECR);
228 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
230 | INCR initarraylv '[' arglist ']' {
231 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$4);
232 ADD_OP(OP_INCR);
233 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$4);
235 | DECR initarraylv '[' arglist ']' {
236 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$4);
237 ADD_OP(OP_DECR);
238 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$4);
240 | SYMBOL '(' arglist ')' {
241 ADD_OP(OP_SUBR_CALL);
242 ADD_SYM(PromoteToGlobal($1)); ADD_IMMED((void *)$3);
244 | INCR SYMBOL {
245 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR);
246 ADD_OP(OP_ASSIGN); ADD_SYM($2);
248 | SYMBOL INCR {
249 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_INCR);
250 ADD_OP(OP_ASSIGN); ADD_SYM($1);
252 | DECR SYMBOL {
253 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR);
254 ADD_OP(OP_ASSIGN); ADD_SYM($2);
256 | SYMBOL DECR {
257 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DECR);
258 ADD_OP(OP_ASSIGN); ADD_SYM($1);
261 evalsym: SYMBOL {
262 $$ = $1; ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
265 comastmts: /* nothing */ {
266 $$ = GetPC();
268 | simpstmt {
269 $$ = GetPC();
271 | comastmts ',' simpstmt {
272 $$ = GetPC();
275 arglist: /* nothing */ {
276 $$ = 0;
278 | expr {
279 $$ = 1;
281 | arglist ',' expr {
282 $$ = $1 + 1;
285 expr: numexpr %prec CONCAT
286 | expr numexpr %prec CONCAT {
287 ADD_OP(OP_CONCAT);
290 initarraylv: SYMBOL {
291 ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED((void *)1);
293 | initarraylv '[' arglist ']' {
294 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
297 arraylv: SYMBOL {
298 ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED((void *)0);
300 | arraylv '[' arglist ']' {
301 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
304 arrayexpr: numexpr {
305 $$ = GetPC();
308 numexpr: NUMBER {
309 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
311 | STRING {
312 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
314 | SYMBOL {
315 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
317 | SYMBOL '(' arglist ')' {
318 ADD_OP(OP_SUBR_CALL);
319 ADD_SYM(PromoteToGlobal($1)); ADD_IMMED((void *)$3);
320 ADD_OP(OP_FETCH_RET_VAL);
322 | '(' expr ')'
323 | numexpr '[' arglist ']' {
324 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
326 | numexpr '+' numexpr {
327 ADD_OP(OP_ADD);
329 | numexpr '-' numexpr {
330 ADD_OP(OP_SUB);
332 | numexpr '*' numexpr {
333 ADD_OP(OP_MUL);
335 | numexpr '/' numexpr {
336 ADD_OP(OP_DIV);
338 | numexpr '%' numexpr {
339 ADD_OP(OP_MOD);
341 | numexpr POW numexpr {
342 ADD_OP(OP_POWER);
344 | '-' numexpr %prec UNARY_MINUS {
345 ADD_OP(OP_NEGATE);
347 | numexpr GT numexpr {
348 ADD_OP(OP_GT);
350 | numexpr GE numexpr {
351 ADD_OP(OP_GE);
353 | numexpr LT numexpr {
354 ADD_OP(OP_LT);
356 | numexpr LE numexpr {
357 ADD_OP(OP_LE);
359 | numexpr EQ numexpr {
360 ADD_OP(OP_EQ);
362 | numexpr NE numexpr {
363 ADD_OP(OP_NE);
365 | numexpr '&' numexpr {
366 ADD_OP(OP_BIT_AND);
368 | numexpr '|' numexpr {
369 ADD_OP(OP_BIT_OR);
371 | numexpr and numexpr %prec AND {
372 ADD_OP(OP_AND); SET_BR_OFF($2, GetPC());
374 | numexpr or numexpr %prec OR {
375 ADD_OP(OP_OR); SET_BR_OFF($2, GetPC());
377 | NOT numexpr {
378 ADD_OP(OP_NOT);
380 | INCR SYMBOL {
381 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR);
382 ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2);
384 | SYMBOL INCR {
385 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP);
386 ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
388 | DECR SYMBOL {
389 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR);
390 ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2);
392 | SYMBOL DECR {
393 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP);
394 ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
396 | numexpr IN numexpr {
397 ADD_OP(OP_IN_ARRAY);
400 while: WHILE {
401 $$ = GetPC(); StartLoopAddrList();
404 for: FOR {
405 StartLoopAddrList(); $$ = GetPC();
408 else: ELSE {
409 ADD_OP(OP_BRANCH); $$ = GetPC(); ADD_BR_OFF(0);
412 cond: /* nothing */ {
413 ADD_OP(OP_BRANCH_NEVER); $$ = GetPC(); ADD_BR_OFF(0);
415 | numexpr {
416 ADD_OP(OP_BRANCH_FALSE); $$ = GetPC(); ADD_BR_OFF(0);
419 and: AND {
420 ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_FALSE); $$ = GetPC();
421 ADD_BR_OFF(0);
424 or: OR {
425 ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_TRUE); $$ = GetPC();
426 ADD_BR_OFF(0);
429 blank: /* nothing */
430 | blank '\n'
433 %% /* User Subroutines Section */
437 ** Parse a null terminated string and create a program from it (this is the
438 ** parser entry point). The program created by this routine can be
439 ** executed using ExecuteProgram. Returns program on success, or NULL
440 ** on failure. If the command failed, the error message is returned
441 ** as a pointer to a static string in msg, and the length of the string up
442 ** to where parsing failed in stoppedAt.
444 Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
446 Program *prog;
448 BeginCreatingProgram();
450 /* call yyparse to parse the string and check for success. If the parse
451 failed, return the error message and string index (the grammar aborts
452 parsing at the first error) */
453 InPtr = expr;
454 if (yyparse()) {
455 *msg = ErrMsg;
456 *stoppedAt = InPtr;
457 FreeProgram(FinishCreatingProgram());
458 return NULL;
461 /* get the newly created program */
462 prog = FinishCreatingProgram();
464 /* parse succeeded */
465 *msg = "";
466 *stoppedAt = InPtr;
467 return prog;
471 static int yylex(void)
473 int i, len;
474 Symbol *s;
475 static DataValue value = {NO_TAG, {0}};
476 static char escape[] = "\\\"ntbrfav";
477 static char replace[] = "\\\"\n\t\b\r\f\a\v";
479 /* skip whitespace and backslash-newline combinations which are
480 also considered whitespace */
481 for (;;) {
482 if (*InPtr == '\\' && *(InPtr + 1) == '\n')
483 InPtr += 2;
484 else if (*InPtr == ' ' || *InPtr == '\t')
485 InPtr++;
486 else
487 break;
490 /* skip comments */
491 if (*InPtr == '#')
492 while (*InPtr != '\n' && *InPtr != '\0') InPtr++;
494 /* return end of input at the end of the string */
495 if (*InPtr == '\0') {
496 return 0;
499 /* process number tokens */
500 if (isdigit((unsigned char)*InPtr)) { /* number */
501 char name[28];
502 sscanf(InPtr, "%d%n", &value.val.n, &len);
503 sprintf(name, "const %d", value.val.n);
504 InPtr += len;
505 value.tag = INT_TAG;
506 if ((yylval.sym=LookupSymbol(name)) == NULL)
507 yylval.sym = InstallSymbol(name, CONST_SYM, value);
508 return NUMBER;
511 /* process symbol tokens. "define" is a special case not handled
512 by this parser, considered end of input. Another special case
513 is action routine names which are allowed to contain '-' despite
514 the ambiguity, handled in matchesActionRoutine. */
515 if (isalpha((unsigned char)*InPtr) || *InPtr == '$') {
516 if ((s=matchesActionRoutine(&InPtr)) == NULL) {
517 char symName[MAX_SYM_LEN+1], *p = symName;
518 *p++ = *InPtr++;
519 while (isalnum((unsigned char)*InPtr) || *InPtr=='_') {
520 if (p >= symName + MAX_SYM_LEN)
521 InPtr++;
522 else
523 *p++ = *InPtr++;
525 *p = '\0';
526 if (!strcmp(symName, "while")) return WHILE;
527 if (!strcmp(symName, "if")) return IF;
528 if (!strcmp(symName, "else")) return ELSE;
529 if (!strcmp(symName, "for")) return FOR;
530 if (!strcmp(symName, "break")) return BREAK;
531 if (!strcmp(symName, "continue")) return CONTINUE;
532 if (!strcmp(symName, "return")) return RETURN;
533 if (!strcmp(symName, "in")) return IN;
534 if (!strcmp(symName, "delete") && follow_non_whitespace('(', SYMBOL, DELETE) == DELETE) return DELETE;
535 if (!strcmp(symName, "define")) {
536 InPtr -= 6;
537 return 0;
539 if ((s=LookupSymbol(symName)) == NULL) {
540 s = InstallSymbol(symName, symName[0]=='$' ?
541 (isdigit((unsigned char)symName[1]) ?
542 ARG_SYM : GLOBAL_SYM) : LOCAL_SYM, value);
543 s->value.tag = NO_TAG;
546 yylval.sym = s;
547 return SYMBOL;
550 /* process quoted strings w/ embedded escape sequences */
551 if (*InPtr == '\"') {
552 char string[MAX_STRING_CONST_LEN], *p = string;
553 InPtr++;
554 while (*InPtr != '\0' && *InPtr != '\"' && *InPtr != '\n') {
555 if (p >= string + MAX_STRING_CONST_LEN) {
556 InPtr++;
557 continue;
559 if (*InPtr == '\\') {
560 InPtr++;
561 if (*InPtr == '\n') {
562 InPtr++;
563 continue;
565 for (i=0; escape[i]!='\0'; i++) {
566 if (escape[i] == '\0') {
567 *p++= *InPtr++;
568 break;
569 } else if (escape[i] == *InPtr) {
570 *p++ = replace[i];
571 InPtr++;
572 break;
575 } else
576 *p++= *InPtr++;
578 *p = '\0';
579 InPtr++;
580 yylval.sym = InstallStringConstSymbol(string);
581 return STRING;
584 /* process remaining two character tokens or return single char as token */
585 switch(*InPtr++) {
586 case '>': return follow('=', GE, GT);
587 case '<': return follow('=', LE, LT);
588 case '=': return follow('=', EQ, '=');
589 case '!': return follow('=', NE, NOT);
590 case '+': return follow2('+', INCR, '=', ADDEQ, '+');
591 case '-': return follow2('-', DECR, '=', SUBEQ, '-');
592 case '|': return follow2('|', OR, '=', OREQ, '|');
593 case '&': return follow2('&', AND, '=', ANDEQ, '&');
594 case '*': return follow2('*', POW, '=', MULEQ, '*');
595 case '/': return follow('=', DIVEQ, '/');
596 case '%': return follow('=', MODEQ, '%');
597 case '^': return POW;
598 default: return *(InPtr-1);
603 ** look ahead for >=, etc.
605 static int follow(char expect, int yes, int no)
607 if (*InPtr++ == expect)
608 return yes;
609 InPtr--;
610 return no;
612 static int follow2(char expect1, int yes1, char expect2, int yes2, int no)
614 char next = *InPtr++;
615 if (next == expect1)
616 return yes1;
617 if (next == expect2)
618 return yes2;
619 InPtr--;
620 return no;
623 static int follow_non_whitespace(char expect, int yes, int no)
625 char *localInPtr = InPtr;
627 while (1) {
628 if (*localInPtr == ' ' || *localInPtr == '\t') {
629 ++localInPtr;
631 else if (*localInPtr == '\\' && *(localInPtr + 1) == '\n') {
632 localInPtr += 2;
634 else if (*localInPtr == expect) {
635 return(yes);
637 else {
638 return(no);
644 ** Look (way) ahead for hyphenated routine names which begin at inPtr. A
645 ** hyphenated name is allowed if it is pre-defined in the global symbol
646 ** table. If a matching name exists, returns the symbol, and update "inPtr".
648 ** I know this is horrible language design, but existing nedit action routine
649 ** names contain hyphens. Handling them here in the lexical analysis process
650 ** is much easier than trying to deal with it in the parser itself. (sorry)
652 static Symbol *matchesActionRoutine(char **inPtr)
654 char *c, *symPtr;
655 int hasDash = False;
656 char symbolName[MAX_SYM_LEN+1];
657 Symbol *s;
659 symPtr = symbolName;
660 for (c = *inPtr; isalnum((unsigned char)*c) || *c=='_' ||
661 ( *c=='-' && isalnum((unsigned char)(*(c+1)))); c++) {
662 if (*c == '-')
663 hasDash = True;
664 *symPtr++ = *c;
666 if (!hasDash)
667 return NULL;
668 *symPtr = '\0';
669 s = LookupSymbol(symbolName);
670 if (s != NULL)
671 *inPtr = c;
672 return s;
676 ** Called by yacc to report errors (just stores for returning when
677 ** parsing is aborted. The error token action is to immediate abort
678 ** parsing, so this message is immediately reported to the caller
679 ** of ParseExpr)
681 static int yyerror(char *s)
683 ErrMsg = s;
684 return 0;