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