|
|
1.1 root 1: /* $Header: gram.y,v 10.4 86/11/30 17:04:55 jg Rel $ */
2: /*
3: * COPYRIGHT 1985, 1986
4: * DIGITAL EQUIPMENT CORPORATION
5: * MAYNARD, MASSACHUSETTS
6: * ALL RIGHTS RESERVED.
7: *
8: * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
9: * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
10: * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITIBILITY OF THIS SOFTWARE FOR
11: * ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
12: *
13: * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
14: * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
15: * SET FORTH ABOVE.
16: *
17: *
18: * Permission to use, copy, modify, and distribute this software and its
19: * documentation for any purpose and without fee is hereby granted, provided
20: * that the above copyright notice appear in all copies and that both that
21: * copyright notice and this permission notice appear in supporting documentation,
22: * and that the name of Digital Equipment Corporation not be used in advertising
23: * or publicity pertaining to distribution of the software without specific,
24: * written prior permission.
25: *
26: */
27:
28: /*
29: * MODIFICATION HISTORY
30: *
31: * 000 -- M. Gancarz, DEC Ultrix Engineering Group
32: */
33:
34: %{
35: #ifndef lint
36: static char *sccsid = "@(#)gram.y 3.8 1/24/86";
37: #endif
38:
39: #include "uwm.h"
40:
41: /*
42: * Values returned by complex expression parser.
43: */
44: #define C_STRING 1 /* IsString. */
45: #define C_MENU 2 /* IsMenu. */
46: #define C_MAP 3 /* IsMap. */
47: #define C_MENUMAP 4 /* IsMenuMap. */
48:
49: static int ki; /* Keyword index. */
50: static short bkmask; /* Button/key mask. */
51: static int cmask; /* Context mask. */
52: static char msg[BUFSIZ]; /* Error message buffer. */
53: static char *menu_name; /* Menu name. */
54: static MenuInfo *menu_info; /* Menu info. */
55: static MenuLine *ml_ptr; /* Temporary menu line pointer. */
56: static char *hcolors[4]; /* Color values used in menu hdrs. */
57: static char *mcolors[2]; /* Color values used in menus. */
58: MenuLink *menu_link; /* Temporary menu link pointer. */
59:
60: char *calloc();
61:
62: %}
63:
64: %union {
65: char *sval;
66: int ival;
67: short shval;
68: struct _menuline *mlval;
69: struct _menuinfo *mival;
70: char **cval;
71: }
72:
73: %token NL
74: %token <sval> STRING
75: %token <ival> COMMENT
76: %type <ival> keyword
77: %type <ival> compexpr
78: %type <shval> keyexpr
79: %type <shval> kmask
80: %type <ival> contexpr
81: %type <ival> contmask
82: %type <shval> buttmodexpr
83: %type <shval> buttmodifier
84: %type <shval> buttexpr
85: %type <sval> menuname
86: %type <sval> strings
87: %type <sval> color
88: %type <cval> color2
89: %type <cval> color4
90: %type <mlval> menuexpr
91: %type <mlval> menulist
92: %type <mlval> menuline
93: %type <mlval> menuaction
94:
95: %% /* beginning of rules section */
96:
97: input: | input command
98: | input error command { yyerrok; }
99: ;
100:
101: command: boolvar term
102: | expr term
103: | COMMENT { Lineno++; }
104: | term
105: ;
106:
107: term: NL { Lineno++; }
108: | ';'
109: ;
110:
111: expr: keyword '=' compexpr
112: {
113: switch (KeywordTable[$1].type) {
114: case IsString:
115: if ($3 == C_STRING) {
116: strcpy(KeywordTable[$1].sptr,
117: yylval.sval);
118: } else {
119: yyerror("illegal construct");
120: }
121: free(yylval.sval);
122: break;
123: case IsNumeric:
124: if ($3 == C_STRING) {
125: *(KeywordTable[$1].nptr) =
126: y_atoi(yylval.sval);
127: } else yyerror("illegal construct");
128: free(yylval.sval);
129: break;
130: case IsBoolTrue:
131: case IsBoolFalse:
132: yyerror("illegal value assignment");
133: break;
134: case IsQuitFunction:
135: case IsFunction:
136: if ($3 == C_MAP) {
137: bind($1, bkmask, cmask, NULL);
138: } else yyerror("illegal construct");
139: break;
140: case IsDownFunction:
141: if (bkmask & ButtonUp) {
142: sprintf(msg,
143: "cannot bind %s to button up",
144: KeywordTable[$1].name);
145: yyerror(msg);
146: }
147: if ($3 == C_MAP) {
148: bind($1, bkmask, cmask, NULL);
149: } else yyerror("illegal construct");
150: break;
151: case IsMenuMap:
152: if (bkmask & ButtonUp) {
153: sprintf(msg,
154: "cannot bind %s to button up",
155: KeywordTable[$1].name);
156: yyerror(msg);
157: }
158: if ($3 == C_MENUMAP) {
159: bind($1, bkmask, cmask, menu_name);
160: } else yyerror("illegal construct");
161: break;
162: case IsMenu:
163: if ($3 == C_MENU) {
164: menu_info = stashmenuinfo(menu_name, ml_ptr, hcolors);
165: menu_link = stashmenulink(menu_info);
166: Menus = appendmenulink(Menus, menu_link);
167: } else yyerror("illegal menu construct");
168: break;
169: default:
170: yyerror("internal binding error");
171: break;
172: }
173: }
174: ;
175:
176: compexpr: keyexpr ':' contexpr ':' buttexpr
177: {
178: $$ = C_MAP;
179: bkmask = $1 | $5;
180: cmask = $3;
181: }
182: | keyexpr ':' contexpr ':' buttexpr ':' menuname
183: {
184: $$ = C_MENUMAP;
185: bkmask = $1 | $5;
186: cmask = $3;
187: menu_name = $7;
188: }
189: | STRING color4 menuexpr
190: {
191: $$ = C_MENU;
192: menu_name = $1;
193: ml_ptr = $3;
194: }
195: | STRING
196: { $$ = C_STRING; }
197: ;
198:
199: boolvar: STRING
200: {
201: ki = keywordlookup(yylval.sval);
202: switch (KeywordTable[ki].type) {
203: case IsBoolTrue:
204: *(KeywordTable[ki].bptr) = TRUE;
205: break;
206: case IsBoolFalse:
207: *(KeywordTable[ki].bptr) = FALSE;
208: break;
209: case IsParser:
210: (*KeywordTable[ki].fptr)();
211: break;
212: default:
213: yyerror("keyword error");
214: }
215: }
216: ;
217:
218: keyword: STRING {
219: $$ = keywordlookup(yylval.sval);
220: }
221: ;
222:
223: keyexpr: /* empty */
224: { $$ = 0; }
225: | kmask
226: { $$ = $1; }
227: | kmask '|' kmask
228: { $$ = $1 | $3; }
229: ;
230:
231: contexpr: /* empty */
232: { $$ = ROOT | WINDOW | ICON; }
233: | contmask
234: { $$ = $1; }
235: | contmask '|' contmask
236: { $$ = $1 | $3; }
237: | contmask '|' contmask '|' contmask
238: { $$ = $1 | $3 | $5; }
239: ;
240:
241: buttexpr: buttmodexpr
242: { $$ = CheckButtonState($1); }
243: ;
244:
245: kmask: STRING { $$ = keyexprlookup(yylval.sval); }
246:
247: contmask: STRING { $$ = contexprlookup(yylval.sval); }
248:
249: buttmodexpr: buttmodifier
250: { $$ = $1; }
251: | buttmodexpr buttmodifier
252: { $$ = $1 | $2; }
253: ;
254:
255: buttmodifier: STRING
256: { $$ = buttexprlookup(yylval.sval); }
257: ;
258:
259: menuname: STRING
260: { $$ = $1; }
261: ;
262:
263: menuexpr: '{' menulist '}'
264: { $$ = $2; }
265: ;
266:
267: menulist: menuline
268: { $$ = $1; }
269: | menulist menuline
270: { $$ = appendmenuline($1, $2); }
271: | menulist COMMENT
272: {
273: Lineno++;
274: $$ = $1;
275: }
276: | COMMENT
277: {
278: Lineno++;
279: $$ = NULL;
280: }
281: | term
282: { $$ = NULL; }
283: | menulist term
284: { $$ = $1; }
285: | error term
286: {
287: $$ = NULL;
288: yyerrok;
289: }
290: ;
291:
292: menuline: strings ':' color2 menuaction term
293: {
294: $4->name = $1;
295: $4->foreground = mcolors[0];
296: $4->background = mcolors[1];
297: $$ = $4;
298: }
299: ;
300:
301: menuaction: STRING
302: {
303: ki = keywordlookup(yylval.sval);
304: if ((ki != -1) &&
305: (KeywordTable[ki].type != IsFunction) &&
306: (KeywordTable[ki].type != IsQuitFunction) &&
307: (KeywordTable[ki].type != IsDownFunction)) {
308: sprintf(msg,
309: "menu action \"%s\" not a function",
310: KeywordTable[ki].name);
311: yyerror(msg);
312: }
313: ml_ptr = AllocMenuLine();
314: if (KeywordTable[ki].type == IsQuitFunction)
315: ml_ptr->type = IsImmFunction;
316: else ml_ptr->type = IsUwmFunction;
317: ml_ptr->func = KeywordTable[ki].fptr;
318: $$ = ml_ptr;
319: }
320: | STRING ':' menuname
321: {
322: ki = keywordlookup($1);
323: if (ki != -1 &&
324: KeywordTable[ki].type != IsMenuMap) {
325: sprintf(msg,
326: "menu action \"%s\" not a menu function",
327: KeywordTable[ki].name);
328: yyerror(msg);
329: }
330: ml_ptr = AllocMenuLine();
331: ml_ptr->type = IsMenuFunction;
332: ml_ptr->text = $3;
333: $$ = ml_ptr;
334: }
335: | '!' strings
336: {
337: $$ = StashMenuLine(IsShellCommand, $2);
338: }
339: | '^' strings
340: {
341: $$ = StashMenuLine(IsTextNL, $2);
342: }
343: | '|' strings
344: {
345: $$ = StashMenuLine(IsText, $2);
346: }
347: ;
348:
349: strings: STRING { $$ = yylval.sval; }
350: | strings STRING
351: { $$ = strconcat($1, $2); }
352: ;
353:
354: color4: '(' color ':' color ':' color ':' color ')'
355: {
356: hcolors[0] = $2;
357: hcolors[1] = $4;
358: hcolors[2] = $6;
359: hcolors[3] = $8;
360: $$ = hcolors;
361: }
362: | /* empty */
363: {
364: hcolors[0] = NULL;
365: hcolors[1] = NULL;
366: hcolors[2] = NULL;
367: hcolors[3] = NULL;
368: $$ = hcolors;
369: }
370: ;
371:
372: color2: '(' color ':' color ')' ':'
373: {
374: mcolors[0] = $2;
375: mcolors[1] = $4;
376: $$ = mcolors;
377: }
378: | /* empty */
379: {
380: mcolors[0] = NULL;
381: mcolors[1] = NULL;
382: $$ = mcolors;
383: }
384: ;
385:
386: color: STRING { $$ = yylval.sval; }
387: | /* empty */ { $$ = NULL; }
388: ;
389: %%
390:
391: /*
392: * Look up a string in the keyword table and return its index, else
393: * return -1.
394: */
395: keywordlookup(string)
396: char *string;
397: {
398: int i;
399:
400: for (i = 0; KeywordTable[i].name; i++) {
401: if (!strcmp(KeywordTable[i].name, string)) {
402: free(string);
403: return(i);
404: }
405: }
406: sprintf(msg,"keyword error: \"%s\"", string);
407: yyerror(msg);
408: free(string);
409: return(-1);
410: }
411:
412: /*
413: * Look up a string in the key expression table and return its mask, else
414: * return -1.
415: */
416: short keyexprlookup(string)
417: char *string;
418: {
419: int i;
420:
421: for (i = 0; KeyExprTbl[i].name; i++) {
422: if (!strcmp(KeyExprTbl[i].name, string)) {
423: free(string);
424: return(KeyExprTbl[i].mask);
425: }
426: }
427: sprintf(msg,"key expression error: \"%s\"", string);
428: yyerror(msg);
429: free(string);
430: return(-1);
431: }
432:
433: /*
434: * Look up a string in the context expression table and return its mask, else
435: * return -1.
436: */
437: contexprlookup(string)
438: char *string;
439: {
440: int i;
441:
442: for (i = 0; ContExprTbl[i].name; i++) {
443: if (!strcmp(ContExprTbl[i].name, string)) {
444: free(string);
445: return(ContExprTbl[i].mask);
446: }
447: }
448: sprintf(msg,"context expression error: \"%s\"", string);
449: yyerror(msg);
450: free(string);
451: return(-1);
452: }
453: /*
454: * Look up a string in the button expression table and return its mask, else
455: * return -1.
456: */
457: buttexprlookup(string)
458: char *string;
459: {
460: int i;
461:
462: for (i = 0; ButtModTbl[i].name; i++) {
463: if (!strcmp(ButtModTbl[i].name, string)) {
464: free(string);
465: return(ButtModTbl[i].mask);
466: }
467: }
468: sprintf(msg,"button modifier error: \"%s\"", string);
469: yyerror(msg);
470: free(string);
471: return(-1);
472: }
473:
474: /*
475: * Scan a string and return an integer. Report an error if any
476: * non-numeric characters are found.
477: */
478: y_atoi(s)
479: char *s;
480: {
481: int n = 0;
482:
483: while (*s) {
484: if (*s >= '0' && *s <= '9')
485: n = 10 * n + *s - '0';
486: else {
487: yyerror("non-numeric argument");
488: return(-1);
489: }
490: s++;
491: }
492: return(n);
493: }
494:
495: /*
496: * Append s2 to s1, extending s1 as necessary.
497: */
498: char *
499: strconcat(s1, s2)
500: char *s1, *s2;
501: {
502: char *malloc();
503: char *p;
504:
505: p = malloc(strlen(s1) + strlen(s2) + 2);
506: sprintf(p, "%s %s", s1, s2);
507: free(s1);
508: free(s2);
509: s1 = p;
510: return(s1);
511: }
512:
513: /*
514: * Check a button expression for errors.
515: */
516: short
517: CheckButtonState(expr)
518: short expr;
519: {
520: /*
521: * Check for one (and only one) button.
522: */
523: switch (expr & (LeftMask | MiddleMask | RightMask)) {
524: case 0:
525: yyerror("no button specified");
526: break;
527: case LeftMask:
528: break;
529: case MiddleMask:
530: break;
531: case RightMask:
532: break;
533: default:
534: yyerror("more than one button specified");
535: }
536:
537: /*
538: * Check for one (and only one) up/down/motion modifier.
539: */
540: switch (expr & (ButtonUp | ButtonDown | DeltaMotion)) {
541: case 0:
542: yyerror("no button action specified");
543: break;
544: case ButtonUp:
545: break;
546: case ButtonDown:
547: break;
548: case DeltaMotion:
549: break;
550: default:
551: yyerror("only one of up/down/motion may be specified");
552: }
553: return(expr);
554: }
555:
556: /*
557: * Bind button/key/context to a function.
558: */
559: bind(index, mask, context, name)
560: int index; /* Index into keyword table. */
561: short mask; /* Button/key/modifier mask. */
562: int context; /* ROOT, WINDOW, or ICON. */
563: char *name; /* Menu, if needed. */
564: {
565: if (context & ROOT)
566: setbinding(ROOT, index, mask, name);
567: if (context & ICON)
568: setbinding(ICON, index, mask, name);
569: if (context & WINDOW)
570: setbinding(WINDOW, index, mask, name);
571: }
572:
573: /*
574: * Allocate a Binding type and return a pointer.
575: */
576: Binding *
577: AllocBinding()
578: {
579: Binding *ptr;
580:
581: if (!(ptr = (Binding *)calloc(1, sizeof(Binding)))) {
582: fprintf(stderr, "Can't allocate binding--out of space\n");
583: exit(1);
584: }
585: return(ptr);
586: }
587:
588: /*
589: * Stash the data in a Binding.
590: */
591: setbinding(cont, i, m, mname)
592: int cont; /* Context: ROOT, WINDOW, or ICON. */
593: int i; /* Keyword table index. */
594: short m; /* Key/button/modifier mask. */
595: char *mname; /* Pointer to menu name, if needed. */
596: {
597: Binding *ptr;
598:
599: ptr = AllocBinding();
600: ptr->context = cont;
601: ptr->mask = m;
602: ptr->func = KeywordTable[i].fptr;
603: ptr->menuname = mname;
604:
605: switch (m & (LeftMask | MiddleMask | RightMask)) {
606: case LeftMask:
607: ptr->button = LeftButton;
608: break;
609: case MiddleMask:
610: ptr->button = MiddleButton;
611: break;
612: case RightMask:
613: ptr->button = RightButton;
614: break;
615: }
616: appendbinding(ptr);
617: }
618:
619: /*
620: * Append a Binding to the Bindings list.
621: */
622: appendbinding(binding)
623: Binding *binding;
624: {
625: Binding *ptr;
626:
627: if (Blist == NULL)
628: Blist = binding;
629: else {
630: for(ptr = Blist; ptr->next; ptr = ptr->next) /* NULL */;
631: ptr->next = binding;
632: ptr = ptr->next;
633: ptr->next = NULL;
634: }
635: }
636:
637: /*
638: * Allocate a menu line and return a pointer.
639: */
640: MenuLine *
641: AllocMenuLine()
642: {
643: MenuLine *ptr;
644:
645: if (!(ptr = (MenuLine *)calloc(1, sizeof(MenuLine)))) {
646: fprintf(stderr, "Can't allocate menu line--out of space\n");
647: exit(1);
648: }
649: return(ptr);
650: }
651:
652: /*
653: * Allocate a MenuInfo structure and return a pointer.
654: */
655: MenuInfo *
656: AllocMenuInfo()
657: {
658: MenuInfo *ptr;
659:
660: if (!(ptr = (MenuInfo *)calloc(1, sizeof(MenuInfo)))) {
661: fprintf(stderr, "Can't allocate menu storage--out of space\n");
662: exit(1);
663: }
664: return(ptr);
665: }
666:
667: /*
668: * Allocate a MenuLink structure and return a pointer.
669: */
670: MenuLink *
671: AllocMenuLink()
672: {
673: MenuLink *ptr;
674:
675: if (!(ptr = (MenuLink *)calloc(1, sizeof(MenuLink)))) {
676: fprintf(stderr, "Can't allocate menu linked list storage--out of space\n");
677: exit(1);
678: }
679: return(ptr);
680: }
681:
682: /*
683: * Stash the data in a menu line.
684: */
685: MenuLine *
686: StashMenuLine(type, string)
687: int type;
688: char *string;
689: {
690: MenuLine *ptr;
691:
692: ptr = AllocMenuLine();
693: ptr->type = type;
694: ptr->text = string;
695: return(ptr);
696: }
697:
698: /*
699: * Stash menu data in a MenuInfo structure;
700: */
701: MenuInfo *
702: stashmenuinfo(name, line, colors)
703: char *name;
704: MenuLine *line;
705: char *colors[];
706: {
707: MenuInfo *ptr;
708:
709: ptr = AllocMenuInfo();
710: ptr->name = name;
711: ptr->line = line;
712: ptr->foreground = colors[1];
713: ptr->background = colors[0];
714: ptr->fghighlight = colors[2];
715: ptr->bghighlight = colors[3];
716: return(ptr);
717: }
718:
719: /*
720: * Stash menu info data in a MenuLink structure;
721: */
722: MenuLink *
723: stashmenulink(menuinfo)
724: MenuInfo *menuinfo;
725: {
726: MenuLink *ptr;
727:
728: ptr = AllocMenuLink();
729: ptr->next = NULL;
730: ptr->menu = menuinfo;
731: return(ptr);
732: }
733:
734: /*
735: * Append a menu line to a linked list of menu lines.
736: */
737: MenuLine *
738: appendmenuline(list, line)
739: MenuLine *list;
740: MenuLine *line;
741: {
742: MenuLine *ptr;
743:
744: if (list == NULL)
745: list = line;
746: else {
747: for(ptr = list; ptr->next; ptr = ptr->next) /* NULL */;
748: ptr->next = line;
749: ptr = ptr->next;
750: ptr->next = NULL;
751: }
752: return(list);
753: }
754:
755: /*
756: * Append a menu to a linked list of menus.
757: */
758: MenuLink *
759: appendmenulink(list, link)
760: MenuLink *list;
761: MenuLink *link;
762: {
763: MenuLink *ptr;
764:
765: if (list == NULL)
766: list = link;
767: else {
768: for(ptr = list; ptr->next; ptr = ptr->next) /* NULL */;
769: ptr->next = link;
770: ptr = ptr->next;
771: ptr->next = NULL;
772: }
773: return(list);
774: }
775:
776: /*
777: * Reset all previous bindings and free the space allocated to them.
778: */
779: Bool ResetBindings()
780: {
781: Binding *ptr, *nextptr;
782:
783: for(ptr = Blist; ptr; ptr = nextptr) {
784: if(ptr->menuname) free(ptr->menuname);
785: nextptr = ptr->next;
786: free(ptr);
787: }
788: Blist = NULL;
789: }
790:
791: /*
792: * De-allocate all menus.
793: */
794: Bool ResetMenus()
795: {
796: MenuLink *mptr, *next_mptr;
797: register MenuLine *lptr, *next_lptr;
798:
799: for(mptr = Menus; mptr; mptr = next_mptr) {
800: free(mptr->menu->name);
801: for(lptr = mptr->menu->line; lptr; lptr = next_lptr) {
802: free(lptr->name);
803: if (lptr->text) free(lptr->text);
804: next_lptr = lptr->next;
805: free(lptr);
806: }
807: next_mptr = mptr->next;
808: free(mptr);
809: }
810: Menus = NULL;
811: }
812:
813: /*
814: * Set all numeric variables to zero and all boolean variables to FALSE.
815: */
816: Bool ResetVariables()
817: {
818: register int i;
819:
820: for (i = 0; KeywordTable[i].name; i++) {
821: switch (KeywordTable[i].type) {
822: case IsBoolTrue:
823: case IsBoolFalse:
824: *(KeywordTable[i].bptr) = FALSE;
825: break;
826: case IsNumeric:
827: *(KeywordTable[i].nptr) = 0;
828: break;
829: default:
830: break;
831: }
832: }
833: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.