2 /* This file is part of the Project Athena Zephyr Notification System.
3 * It is one of the source files comprising zwgc, the Zephyr WindowGram
6 * Created by: Marc Horowitz <marc@athena.mit.edu>
8 * $Id: parser.y 2133 2008-01-21 03:11:44Z kcr $
10 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, see the file
17 #if (!defined(lint) && !defined(SABER))
18 static const char rcsid_parser_y[] = "$Id: parser.y 2133 2008-01-21 03:11:44Z kcr $";
21 #include <zephyr/mit-copyright.h>
23 /* Saber-C suppressions because yacc loses */
34 static void yyerror(char *);
37 * the_program - local variable used to communicate the program's node
38 * representation from the program action to the parse_file
42 static Node *the_program;
53 %token <text> VARNAME VARREF STRING SHOW
55 %token APPENDPORT BUFFER BREAK CLOSEINPUT CLOSEOUTPUT
56 %token CLOSEPORT CASE CLEARBUF DEFAULT DISPLAY DO DOWNCASE
57 %token ELSE ELSEIF ENDCASE ENDIF ENDWHILE EXEC EXECPORT EXIT
58 %token FIELDS GET GETENV IF INPUTPORT LANY LBREAK LSPAN
59 %token MATCH NOOP NOT OUTPUTPORT PRINT PROTECT VERBATIM PUT RANY RBREAK
60 %token RSPAN SET SUBSTITUTE THEN UPCASE WHILE ZVAR STYLESTRIP
62 %type <node> expr varname string
63 %type <node> exprlist comma_exprlist varnamelist
64 %type <node> statement statements program elseparts elseifparts
65 %type <node> match matchlist
69 %left EQ NEQ REGEQ REGNEQ
76 * A program is simply a list of statements: (may be NULL if no statements...)
79 { the_program = reverse_list_of_nodes($1);
84 { $$ = node_create_string_constant(VARNAME_OPCODE, $1); }
88 { $$ = node_create_string_constant(STRING_CONSTANT_OPCODE, $1); }
97 { $$ = node_create_string_constant(VARREF_OPCODE, $1); }
100 { $$ = node_create_unary(NOT_OPCODE, $2); }
103 { $$ = node_create_binary(PLUS_OPCODE, $1, $3); }
104 | expr '|' expr /* note "or" == '|' */
105 { $$ = node_create_binary(OR_OPCODE, $1, $3); }
106 | expr '&' expr /* note "and" == '&' */
107 { $$ = node_create_binary(AND_OPCODE, $1, $3); }
109 { $$ = node_create_binary(EQ_OPCODE, $1, $3); }
111 { $$ = node_create_binary(NEQ_OPCODE, $1, $3); }
113 { $$ = node_create_binary(REGEQ_OPCODE, $1, $3); }
115 { $$ = node_create_binary(REGNEQ_OPCODE, $1, $3); }
118 { $$ = node_create_noary(BUFFER_OPCODE); }
120 | SUBSTITUTE '(' expr ')'
121 { $$ = node_create_unary(SUBSTITUTE_OPCODE, $3); }
122 | PROTECT '(' expr ')'
123 { $$ = node_create_unary(PROTECT_OPCODE, $3); }
124 | VERBATIM '(' expr ')'
125 { $$ = node_create_unary(VERBATIM_OPCODE, $3); }
126 | GETENV '(' expr ')'
127 { $$ = node_create_unary(GETENV_OPCODE, $3); }
128 | UPCASE '(' expr ')'
129 { $$ = node_create_unary(UPCASE_OPCODE, $3); }
130 | DOWNCASE '(' expr ')'
131 { $$ = node_create_unary(DOWNCASE_OPCODE, $3); }
133 { $$ = node_create_unary(ZVAR_OPCODE, $3); }
135 { $$ = node_create_unary(GET_OPCODE, $3); }
136 | STYLESTRIP '(' expr ')'
137 { $$ = node_create_unary(STYLESTRIP_OPCODE, $3); }
139 | LANY '(' expr ',' expr ')'
140 { $$ = node_create_binary(LANY_OPCODE, $3, $5 ); }
141 | RANY '(' expr ',' expr ')'
142 { $$ = node_create_binary(RANY_OPCODE, $3, $5 ); }
143 | LBREAK '(' expr ',' expr ')'
144 { $$ = node_create_binary(LBREAK_OPCODE, $3, $5 ); }
145 | RBREAK '(' expr ',' expr ')'
146 { $$ = node_create_binary(RBREAK_OPCODE, $3, $5 ); }
147 | LSPAN '(' expr ',' expr ')'
148 { $$ = node_create_binary(LSPAN_OPCODE, $3, $5 ); }
149 | RSPAN '(' expr ',' expr ')'
150 { $$ = node_create_binary(RSPAN_OPCODE, $3, $5 ); }
154 { $$ = node_create_noary(NOOP_OPCODE); }
155 | SET varname '=' expr
156 { $$ = node_create_binary(SET_OPCODE, $2, $4); }
158 { $$ = node_create_unary(FIELDS_OPCODE,
159 reverse_list_of_nodes($2)); }
162 * Output to & control of output buffer statements:
165 { $$ = node_create_unary(PRINT_OPCODE,
166 reverse_list_of_nodes($2)); }
168 { $$ = node_create_unary(PRINT_OPCODE,
169 node_create_unary(SUBSTITUTE_OPCODE,
170 node_create_string_constant(STRING_CONSTANT_OPCODE,
173 { $$ = node_create_noary(CLEARBUF_OPCODE); }
176 * Statements to manage ports:
178 | APPENDPORT expr expr
179 { $$ = node_create_binary(APPENDPORT_OPCODE, $2, $3); }
180 | EXECPORT expr expr exprlist
181 { $3->next = reverse_list_of_nodes($4);
182 $$ = node_create_binary(EXECPORT_OPCODE, $2, $3); }
183 | INPUTPORT expr expr
184 { $$ = node_create_binary(INPUTPORT_OPCODE, $2, $3); }
185 | OUTPUTPORT expr expr
186 { $$ = node_create_binary(OUTPUTPORT_OPCODE, $2, $3); }
188 { $$ = node_create_binary(PUT_OPCODE, $2,
189 reverse_list_of_nodes($3)); }
191 { $$ = node_create_binary(PUT_OPCODE, 0, 0); }
193 { $$ = node_create_unary(CLOSEINPUT_OPCODE, $2); }
195 { $$ = node_create_unary(CLOSEOUTPUT_OPCODE, $2); }
197 { $$ = node_create_unary(CLOSEPORT_OPCODE, $2); }
200 * Statements to run subprocesses without I/O to them:
203 { $2->next = reverse_list_of_nodes($3);
204 $$ = node_create_unary(EXEC_OPCODE, $2); }
207 * Control statements:
209 | IF expr THEN statements elseparts ENDIF
210 { Node *n = node_create_binary(IF_OPCODE, $2,
211 reverse_list_of_nodes($4));
213 $$ = node_create_unary(IF_STMT_OPCODE, n); }
214 | CASE expr matchlist ENDCASE
215 { $$ = node_create_binary(CASE_OPCODE, $2,
216 reverse_list_of_nodes($3)); }
217 | WHILE expr DO statements ENDWHILE
218 { $$ = node_create_binary(WHILE_OPCODE, $2,
219 reverse_list_of_nodes($4)); }
221 { $$ = node_create_noary(BREAK_OPCODE); }
223 { $$ = node_create_noary(EXIT_OPCODE); }
226 elseparts : elseifparts
227 { $$ = reverse_list_of_nodes($1); }
228 | elseifparts ELSE statements
229 { $$ = node_create_binary(ELSE_OPCODE, 0,
230 reverse_list_of_nodes($3));
232 $$ = reverse_list_of_nodes($$); }
235 /* elseifparts needs to be reversed before using... */
236 elseifparts : /* empty */
238 | elseifparts ELSEIF expr THEN statements
239 { $$ = node_create_binary(ELSEIF_OPCODE, $3,
240 reverse_list_of_nodes($5));
244 match : MATCH comma_exprlist statements
245 { $$ = node_create_binary(MATCHLIST_OPCODE,
246 reverse_list_of_nodes($2),
247 reverse_list_of_nodes($3)); }
249 { $$ = node_create_binary(DEFAULT_OPCODE, 0,
250 reverse_list_of_nodes($2)); }
254 * Various lists of non-terminals like expr's and varname's. Each is
255 * built up as a linked list using the nodes' next fields. To prevent
256 * Yacc stack overflow on long lists, these are put on the linked list
257 * BACKWARDS. The user of these must first call reverse_list_of_nodes
258 * on one of these before using it. All except comma_exprlist
259 * allow 0 elements on the list in which case their value is NULL.
260 * (comma_exprlist requires at least one element)
263 exprlist : /* empty */
270 comma_exprlist : expr
272 | comma_exprlist ',' expr
277 varnamelist : /* empty */
279 | varnamelist varname
284 matchlist : /* empty */
291 statements : /* empty */
293 | statements statement
301 * error_occured - Set to true when a parse error is reported. If it is false
302 * at the time a parse error is reported, a message is
303 * printed on stderr. See report_parse_error for more
307 static int error_occured = 0;
310 * Parser-Lexer Internal Routine:
312 * void report_parse_error(char *error_message, int line_number)
313 * Modifies: error_occured, stderr
314 * Effects: This routine is called to report a parser or lexer
315 * error. Error_message is the error message and line_number
316 * the line number it occured on. The reported error message
317 * is of the form "....<error_message> on line <line #>.\n".
318 * This routine sets error_occured (local to parser.y) to
319 * true. If it was previously false, the error message
320 * is reported to the user via stderr.
324 report_parse_error(char *error_message,
331 fprintf(stderr, "zwgc: error in description file: %s on line %d.\n",
332 error_message, line_number);
337 * yyerror - internal routine - used by yacc to report syntax errors and
338 * stack overflow errors.
341 static void yyerror(char *message)
343 report_parse_error(message, yylineno);
347 * struct _Node *parse_file(FILE *input_file)
348 * Requires: input_file is opened for reading, no pointers to
349 * existing nodes will ever be dereferened.
350 * Modifies: *input_file, stderr, all existing nodes
351 * Effects: First this routine destroys all nodes. Then it parses
352 * input_file as a zwgc description langauge file. If
353 * an error is encountered, an error message is printed
354 * on stderr and NULL is returned. If no error is
355 * encountered, a pointer to the node representation of
356 * the parsed program is returned, suitable for passing to
357 * exec.c. Note that NULL will also be returned for a
358 * empty file & is a valid program. Either way, input_file
359 * is closed before this routine returns.
363 parse_file(FILE *input_file)
367 node_DestroyAllNodes();
369 lex_open(input_file);
374 node_DestroyAllNodes();
380 printf("****************************************************************************\n");
381 node_display(the_program);
382 printf("****************************************************************************\n");