Fix for SF bug #564782: Show Path in Windows Menu
[nedit.git] / source / parse.y
blob8577dffdcbc6338f7feb8fccee89d6bd5376d911
1 /* $Id: parse.y,v 1.23 2002/12/12 17:25:59 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 <string.h>
14 #include <stdio.h>
15 #include <ctype.h>
16 #include <X11/Intrinsic.h>
17 #include <Xm/Xm.h>
18 #ifdef VMS
19 #include "../util/VMSparam.h"
20 #else
21 #ifndef __MVS__
22 #include <sys/param.h>
23 #endif
24 #endif /*VMS*/
26 #ifdef HAVE_DEBUG_H
27 #include "../debug.h"
28 #endif
30 /* Macros to add error processing to AddOp and AddSym calls */
31 #define ADD_OP(op) if (!AddOp(op, &ErrMsg)) return 1
32 #define ADD_SYM(sym) if (!AddSym(sym, &ErrMsg)) return 1
33 #define ADD_IMMED(val) if (!AddImmediate(val, &ErrMsg)) return 1
34 #define ADD_BR_OFF(to) if (!AddBranchOffset(to, &ErrMsg)) return 1
35 #define SET_BR_OFF(from, to) *((int *)(from)) = ((Inst *)(to)) - ((Inst *)(from))
37 /* Max. length for a string constant (... there shouldn't be a maximum) */
38 #define MAX_STRING_CONST_LEN 5000
40 static const char CVSID[] = "$Id: parse.y,v 1.23 2002/12/12 17:25:59 slobasso Exp $";
41 static int yyerror(char *s);
42 static int yylex(void);
43 int yyparse(void);
44 static int follow(char expect, int yes, int no);
45 static int follow2(char expect1, int yes1, char expect2, int yes2, int no);
46 static int follow_non_whitespace(char expect, int yes, int no);
47 static Symbol *matchesActionRoutine(char **inPtr);
49 static char *ErrMsg;
50 static char *InPtr;
51 extern Inst *LoopStack[]; /* addresses of break, cont stmts */
52 extern Inst **LoopStackPtr; /* to fill at the end of a loop */
56 %union {
57 Symbol *sym;
58 Inst *inst;
59 int nArgs;
61 %token <sym> NUMBER STRING SYMBOL
62 %token IF WHILE ELSE FOR BREAK CONTINUE RETURN
63 %type <nArgs> arglist
64 %type <inst> cond comastmts for while else and or arrayexpr
65 %type <sym> evalsym
67 %nonassoc IF_NO_ELSE
68 %nonassoc ELSE
70 %nonassoc SYMBOL
71 %right '=' ADDEQ SUBEQ MULEQ DIVEQ MODEQ ANDEQ OREQ
72 %left CONCAT
73 %left OR
74 %left AND
75 %left '|'
76 %left '&'
77 %left GT GE LT LE EQ NE IN
78 %left '+' '-'
79 %left '*' '/' '%'
80 %nonassoc UNARY_MINUS NOT
81 %nonassoc DELETE
82 %nonassoc INCR DECR
83 %right POW
84 %nonassoc '['
85 %nonassoc '('
87 %% /* Rules */
89 program: blank stmts {
90 ADD_OP(OP_RETURN_NO_VAL); return 0;
92 | blank '{' blank stmts '}' {
93 ADD_OP(OP_RETURN_NO_VAL); return 0;
95 | blank '{' blank '}' {
96 ADD_OP(OP_RETURN_NO_VAL); return 0;
98 | error {
99 return 1;
102 block: '{' blank stmts '}' blank
103 | '{' blank '}' blank
104 | stmt
106 stmts: stmt
107 | stmts stmt
109 stmt: simpstmt '\n' blank
110 | IF '(' cond ')' blank block %prec IF_NO_ELSE {
111 SET_BR_OFF($3, GetPC());
113 | IF '(' cond ')' blank block else blank block %prec ELSE {
114 SET_BR_OFF($3, ($7+1)); SET_BR_OFF($7, GetPC());
116 | while '(' cond ')' blank block {
117 ADD_OP(OP_BRANCH); ADD_BR_OFF($1);
118 SET_BR_OFF($3, GetPC()); FillLoopAddrs(GetPC(), $1);
120 | for '(' comastmts ';' cond ';' comastmts ')' blank block {
121 FillLoopAddrs(GetPC()+2+($7-($5+1)), GetPC());
122 SwapCode($5+1, $7, GetPC());
123 ADD_OP(OP_BRANCH); ADD_BR_OFF($3); SET_BR_OFF($5, GetPC());
125 | for '(' SYMBOL IN arrayexpr ')' {
126 Symbol *iterSym = InstallIteratorSymbol();
127 ADD_OP(OP_BEGIN_ARRAY_ITER); ADD_SYM(iterSym);
128 ADD_OP(OP_ARRAY_ITER); ADD_SYM($3); ADD_SYM(iterSym); ADD_BR_OFF(0);
130 blank block {
131 ADD_OP(OP_BRANCH); ADD_BR_OFF($5+2);
132 SET_BR_OFF($5+5, GetPC());
133 FillLoopAddrs(GetPC(), $5+2);
135 | BREAK '\n' blank {
136 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
137 if (AddBreakAddr(GetPC()-1)) {
138 yyerror("break outside loop"); YYERROR;
141 | CONTINUE '\n' blank {
142 ADD_OP(OP_BRANCH); ADD_BR_OFF(0);
143 if (AddContinueAddr(GetPC()-1)) {
144 yyerror("continue outside loop"); YYERROR;
147 | RETURN expr '\n' blank {
148 ADD_OP(OP_RETURN);
150 | RETURN '\n' blank {
151 ADD_OP(OP_RETURN_NO_VAL);
154 simpstmt: SYMBOL '=' expr {
155 ADD_OP(OP_ASSIGN); ADD_SYM($1);
157 | evalsym ADDEQ expr {
158 ADD_OP(OP_ADD); ADD_OP(OP_ASSIGN); ADD_SYM($1);
160 | evalsym SUBEQ expr {
161 ADD_OP(OP_SUB); ADD_OP(OP_ASSIGN); ADD_SYM($1);
163 | evalsym MULEQ expr {
164 ADD_OP(OP_MUL); ADD_OP(OP_ASSIGN); ADD_SYM($1);
166 | evalsym DIVEQ expr {
167 ADD_OP(OP_DIV); ADD_OP(OP_ASSIGN); ADD_SYM($1);
169 | evalsym MODEQ expr {
170 ADD_OP(OP_MOD); ADD_OP(OP_ASSIGN); ADD_SYM($1);
172 | evalsym ANDEQ expr {
173 ADD_OP(OP_BIT_AND); ADD_OP(OP_ASSIGN); ADD_SYM($1);
175 | evalsym OREQ expr {
176 ADD_OP(OP_BIT_OR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
178 | DELETE arraylv '[' arglist ']' {
179 ADD_OP(OP_ARRAY_DELETE); ADD_IMMED((void *)$4);
181 | initarraylv '[' arglist ']' '=' expr {
182 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
184 | initarraylv '[' arglist ']' ADDEQ expr {
185 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
186 ADD_OP(OP_ADD);
187 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
189 | initarraylv '[' arglist ']' SUBEQ expr {
190 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
191 ADD_OP(OP_SUB);
192 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
194 | initarraylv '[' arglist ']' MULEQ expr {
195 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
196 ADD_OP(OP_MUL);
197 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
199 | initarraylv '[' arglist ']' DIVEQ expr {
200 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
201 ADD_OP(OP_DIV);
202 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
204 | initarraylv '[' arglist ']' MODEQ expr {
205 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
206 ADD_OP(OP_MOD);
207 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
209 | initarraylv '[' arglist ']' ANDEQ expr {
210 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
211 ADD_OP(OP_BIT_AND);
212 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
214 | initarraylv '[' arglist ']' OREQ expr {
215 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)1); ADD_IMMED((void *)$3);
216 ADD_OP(OP_BIT_OR);
217 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
219 | initarraylv '[' arglist ']' INCR {
220 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$3);
221 ADD_OP(OP_INCR);
222 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
224 | initarraylv '[' arglist ']' DECR {
225 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$3);
226 ADD_OP(OP_DECR);
227 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$3);
229 | INCR initarraylv '[' arglist ']' {
230 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$4);
231 ADD_OP(OP_INCR);
232 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$4);
234 | DECR initarraylv '[' arglist ']' {
235 ADD_OP(OP_ARRAY_REF_ASSIGN_SETUP); ADD_IMMED((void *)0); ADD_IMMED((void *)$4);
236 ADD_OP(OP_DECR);
237 ADD_OP(OP_ARRAY_ASSIGN); ADD_IMMED((void *)$4);
239 | SYMBOL '(' arglist ')' {
240 ADD_OP(OP_SUBR_CALL);
241 ADD_SYM(PromoteToGlobal($1)); ADD_IMMED((void *)$3);
243 | INCR SYMBOL {
244 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR);
245 ADD_OP(OP_ASSIGN); ADD_SYM($2);
247 | SYMBOL INCR {
248 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_INCR);
249 ADD_OP(OP_ASSIGN); ADD_SYM($1);
251 | DECR SYMBOL {
252 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR);
253 ADD_OP(OP_ASSIGN); ADD_SYM($2);
255 | SYMBOL DECR {
256 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DECR);
257 ADD_OP(OP_ASSIGN); ADD_SYM($1);
260 evalsym: SYMBOL {
261 $$ = $1; ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
264 comastmts: /* nothing */ {
265 $$ = GetPC();
267 | simpstmt {
268 $$ = GetPC();
270 | comastmts ',' simpstmt {
271 $$ = GetPC();
274 arglist: /* nothing */ {
275 $$ = 0;
277 | expr {
278 $$ = 1;
280 | arglist ',' expr {
281 $$ = $1 + 1;
284 expr: numexpr %prec CONCAT
285 | expr numexpr %prec CONCAT {
286 ADD_OP(OP_CONCAT);
289 initarraylv: SYMBOL {
290 ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED((void *)1);
292 | initarraylv '[' arglist ']' {
293 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
296 arraylv: SYMBOL {
297 ADD_OP(OP_PUSH_ARRAY_SYM); ADD_SYM($1); ADD_IMMED((void *)0);
299 | arraylv '[' arglist ']' {
300 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
303 arrayexpr: numexpr {
304 $$ = GetPC();
307 numexpr: NUMBER {
308 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
310 | STRING {
311 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
313 | SYMBOL {
314 ADD_OP(OP_PUSH_SYM); ADD_SYM($1);
316 | SYMBOL '(' arglist ')' {
317 ADD_OP(OP_SUBR_CALL);
318 ADD_SYM(PromoteToGlobal($1)); ADD_IMMED((void *)$3);
319 ADD_OP(OP_FETCH_RET_VAL);
321 | '(' expr ')'
322 | numexpr '[' arglist ']' {
323 ADD_OP(OP_ARRAY_REF); ADD_IMMED((void *)$3);
325 | numexpr '+' numexpr {
326 ADD_OP(OP_ADD);
328 | numexpr '-' numexpr {
329 ADD_OP(OP_SUB);
331 | numexpr '*' numexpr {
332 ADD_OP(OP_MUL);
334 | numexpr '/' numexpr {
335 ADD_OP(OP_DIV);
337 | numexpr '%' numexpr {
338 ADD_OP(OP_MOD);
340 | numexpr POW numexpr {
341 ADD_OP(OP_POWER);
343 | '-' numexpr %prec UNARY_MINUS {
344 ADD_OP(OP_NEGATE);
346 | numexpr GT numexpr {
347 ADD_OP(OP_GT);
349 | numexpr GE numexpr {
350 ADD_OP(OP_GE);
352 | numexpr LT numexpr {
353 ADD_OP(OP_LT);
355 | numexpr LE numexpr {
356 ADD_OP(OP_LE);
358 | numexpr EQ numexpr {
359 ADD_OP(OP_EQ);
361 | numexpr NE numexpr {
362 ADD_OP(OP_NE);
364 | numexpr '&' numexpr {
365 ADD_OP(OP_BIT_AND);
367 | numexpr '|' numexpr {
368 ADD_OP(OP_BIT_OR);
370 | numexpr and numexpr %prec AND {
371 ADD_OP(OP_AND); SET_BR_OFF($2, GetPC());
373 | numexpr or numexpr %prec OR {
374 ADD_OP(OP_OR); SET_BR_OFF($2, GetPC());
376 | NOT numexpr {
377 ADD_OP(OP_NOT);
379 | INCR SYMBOL {
380 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_INCR);
381 ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2);
383 | SYMBOL INCR {
384 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP);
385 ADD_OP(OP_INCR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
387 | DECR SYMBOL {
388 ADD_OP(OP_PUSH_SYM); ADD_SYM($2); ADD_OP(OP_DECR);
389 ADD_OP(OP_DUP); ADD_OP(OP_ASSIGN); ADD_SYM($2);
391 | SYMBOL DECR {
392 ADD_OP(OP_PUSH_SYM); ADD_SYM($1); ADD_OP(OP_DUP);
393 ADD_OP(OP_DECR); ADD_OP(OP_ASSIGN); ADD_SYM($1);
395 | numexpr IN numexpr {
396 ADD_OP(OP_IN_ARRAY);
399 while: WHILE {
400 $$ = GetPC(); StartLoopAddrList();
403 for: FOR {
404 StartLoopAddrList(); $$ = GetPC();
407 else: ELSE {
408 ADD_OP(OP_BRANCH); $$ = GetPC(); ADD_BR_OFF(0);
411 cond: /* nothing */ {
412 ADD_OP(OP_BRANCH_NEVER); $$ = GetPC(); ADD_BR_OFF(0);
414 | numexpr {
415 ADD_OP(OP_BRANCH_FALSE); $$ = GetPC(); ADD_BR_OFF(0);
418 and: AND {
419 ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_FALSE); $$ = GetPC();
420 ADD_BR_OFF(0);
423 or: OR {
424 ADD_OP(OP_DUP); ADD_OP(OP_BRANCH_TRUE); $$ = GetPC();
425 ADD_BR_OFF(0);
428 blank: /* nothing */
429 | blank '\n'
432 %% /* User Subroutines Section */
436 ** Parse a null terminated string and create a program from it (this is the
437 ** parser entry point). The program created by this routine can be
438 ** executed using ExecuteProgram. Returns program on success, or NULL
439 ** on failure. If the command failed, the error message is returned
440 ** as a pointer to a static string in msg, and the length of the string up
441 ** to where parsing failed in stoppedAt.
443 Program *ParseMacro(char *expr, char **msg, char **stoppedAt)
445 Program *prog;
447 BeginCreatingProgram();
449 /* call yyparse to parse the string and check for success. If the parse
450 failed, return the error message and string index (the grammar aborts
451 parsing at the first error) */
452 InPtr = expr;
453 if (yyparse()) {
454 *msg = ErrMsg;
455 *stoppedAt = InPtr;
456 FreeProgram(FinishCreatingProgram());
457 return NULL;
460 /* get the newly created program */
461 prog = FinishCreatingProgram();
463 /* parse succeeded */
464 *msg = "";
465 *stoppedAt = InPtr;
466 return prog;
470 static int yylex(void)
472 int i, len;
473 Symbol *s;
474 static DataValue value = {0, {0}};
475 static char escape[] = "\\\"ntbrfav";
476 static char replace[] = "\\\"\n\t\b\r\f\a\v";
478 /* skip whitespace and backslash-newline combinations which are
479 also considered whitespace */
480 for (;;) {
481 if (*InPtr == '\\' && *(InPtr + 1) == '\n')
482 InPtr += 2;
483 else if (*InPtr == ' ' || *InPtr == '\t')
484 InPtr++;
485 else
486 break;
489 /* skip comments */
490 if (*InPtr == '#')
491 while (*InPtr != '\n' && *InPtr != '\0') InPtr++;
493 /* return end of input at the end of the string */
494 if (*InPtr == '\0') {
495 return 0;
498 /* process number tokens */
499 if (isdigit((unsigned char)*InPtr)) { /* number */
500 char name[28];
501 sscanf(InPtr, "%d%n", &value.val.n, &len);
502 sprintf(name, "const %d", value.val.n);
503 InPtr += len;
504 value.tag = INT_TAG;
505 if ((yylval.sym=LookupSymbol(name)) == NULL)
506 yylval.sym = InstallSymbol(name, CONST_SYM, value);
507 return NUMBER;
510 /* process symbol tokens. "define" is a special case not handled
511 by this parser, considered end of input. Another special case
512 is action routine names which are allowed to contain '-' despite
513 the ambiguity, handled in matchesActionRoutine. */
514 if (isalpha((unsigned char)*InPtr) || *InPtr == '$') {
515 if ((s=matchesActionRoutine(&InPtr)) == NULL) {
516 char symName[MAX_SYM_LEN+1], *p = symName;
517 *p++ = *InPtr++;
518 while (isalnum((unsigned char)*InPtr) || *InPtr=='_') {
519 if (p >= symName + MAX_SYM_LEN)
520 InPtr++;
521 else
522 *p++ = *InPtr++;
524 *p = '\0';
525 if (!strcmp(symName, "while")) return WHILE;
526 if (!strcmp(symName, "if")) return IF;
527 if (!strcmp(symName, "else")) return ELSE;
528 if (!strcmp(symName, "for")) return FOR;
529 if (!strcmp(symName, "break")) return BREAK;
530 if (!strcmp(symName, "continue")) return CONTINUE;
531 if (!strcmp(symName, "return")) return RETURN;
532 if (!strcmp(symName, "in")) return IN;
533 if (!strcmp(symName, "delete") && follow_non_whitespace('(', SYMBOL, DELETE) == DELETE) return DELETE;
534 if (!strcmp(symName, "define")) {
535 InPtr -= 6;
536 return 0;
538 if ((s=LookupSymbol(symName)) == NULL) {
539 s = InstallSymbol(symName, symName[0]=='$' ?
540 (isdigit((unsigned char)symName[1]) ?
541 ARG_SYM : GLOBAL_SYM) : LOCAL_SYM, value);
542 s->value.tag = NO_TAG;
545 yylval.sym = s;
546 return SYMBOL;
549 /* process quoted strings w/ embedded escape sequences */
550 if (*InPtr == '\"') {
551 char string[MAX_STRING_CONST_LEN], *p = string;
552 InPtr++;
553 while (*InPtr != '\0' && *InPtr != '\"' && *InPtr != '\n') {
554 if (p >= string + MAX_STRING_CONST_LEN) {
555 InPtr++;
556 continue;
558 if (*InPtr == '\\') {
559 InPtr++;
560 if (*InPtr == '\n') {
561 InPtr++;
562 continue;
564 for (i=0; escape[i]!='\0'; i++) {
565 if (escape[i] == '\0') {
566 *p++= *InPtr++;
567 break;
568 } else if (escape[i] == *InPtr) {
569 *p++ = replace[i];
570 InPtr++;
571 break;
574 } else
575 *p++= *InPtr++;
577 *p = '\0';
578 InPtr++;
579 yylval.sym = InstallStringConstSymbol(string);
580 return STRING;
583 /* process remaining two character tokens or return single char as token */
584 switch(*InPtr++) {
585 case '>': return follow('=', GE, GT);
586 case '<': return follow('=', LE, LT);
587 case '=': return follow('=', EQ, '=');
588 case '!': return follow('=', NE, NOT);
589 case '+': return follow2('+', INCR, '=', ADDEQ, '+');
590 case '-': return follow2('-', DECR, '=', SUBEQ, '-');
591 case '|': return follow2('|', OR, '=', OREQ, '|');
592 case '&': return follow2('&', AND, '=', ANDEQ, '&');
593 case '*': return follow2('*', POW, '=', MULEQ, '*');
594 case '/': return follow('=', DIVEQ, '/');
595 case '%': return follow('=', MODEQ, '%');
596 case '^': return POW;
597 default: return *(InPtr-1);
602 ** look ahead for >=, etc.
604 static int follow(char expect, int yes, int no)
606 if (*InPtr++ == expect)
607 return yes;
608 InPtr--;
609 return no;
611 static int follow2(char expect1, int yes1, char expect2, int yes2, int no)
613 char next = *InPtr++;
614 if (next == expect1)
615 return yes1;
616 if (next == expect2)
617 return yes2;
618 InPtr--;
619 return no;
622 static int follow_non_whitespace(char expect, int yes, int no)
624 char *localInPtr = InPtr;
626 while (1) {
627 if (*localInPtr == ' ' || *localInPtr == '\t') {
628 ++localInPtr;
630 else if (*localInPtr == '\\' && *(localInPtr + 1) == '\n') {
631 localInPtr += 2;
633 else if (*localInPtr == expect) {
634 return(yes);
636 else {
637 return(no);
643 ** Look (way) ahead for hyphenated routine names which begin at inPtr. A
644 ** hyphenated name is allowed if it is pre-defined in the global symbol
645 ** table. If a matching name exists, returns the symbol, and update "inPtr".
647 ** I know this is horrible language design, but existing nedit action routine
648 ** names contain hyphens. Handling them here in the lexical analysis process
649 ** is much easier than trying to deal with it in the parser itself. (sorry)
651 static Symbol *matchesActionRoutine(char **inPtr)
653 char *c, *symPtr;
654 int hasDash = False;
655 char symbolName[MAX_SYM_LEN+1];
656 Symbol *s;
658 symPtr = symbolName;
659 for (c = *inPtr; isalnum((unsigned char)*c) || *c=='_' ||
660 ( *c=='-' && isalnum((unsigned char)(*(c+1)))); c++) {
661 if (*c == '-')
662 hasDash = True;
663 *symPtr++ = *c;
665 if (!hasDash)
666 return NULL;
667 *symPtr = '\0';
668 s = LookupSymbol(symbolName);
669 if (s != NULL)
670 *inPtr = c;
671 return s;
675 ** Called by yacc to report errors (just stores for returning when
676 ** parsing is aborted. The error token action is to immediate abort
677 ** parsing, so this message is immediately reported to the caller
678 ** of ParseExpr)
680 static int yyerror(char *s)
682 ErrMsg = s;
683 return 0;