~ubuntu-branches/ubuntu/maverick/bc/maverick

« back to all changes in this revision

Viewing changes to bc/bc.y

  • Committer: Bazaar Package Importer
  • Author(s): Dirk Eddelbuettel
  • Date: 2002-04-13 11:33:49 UTC
  • Revision ID: james.westby@ubuntu.com-20020413113349-hl2r1t730b91ov68
Tags: upstream-1.06
ImportĀ upstreamĀ versionĀ 1.06

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
%{
 
2
/* bc.y: The grammar for a POSIX compatable bc processor with some
 
3
         extensions to the language. */
 
4
 
 
5
/*  This file is part of GNU bc.
 
6
    Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
 
7
 
 
8
    This program is free software; you can redistribute it and/or modify
 
9
    it under the terms of the GNU General Public License as published by
 
10
    the Free Software Foundation; either version 2 of the License , or
 
11
    (at your option) any later version.
 
12
 
 
13
    This program is distributed in the hope that it will be useful,
 
14
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
    GNU General Public License for more details.
 
17
 
 
18
    You should have received a copy of the GNU General Public License
 
19
    along with this program; see the file COPYING.  If not, write to:
 
20
      The Free Software Foundation, Inc.
 
21
      59 Temple Place, Suite 330
 
22
      Boston, MA 02111 USA
 
23
 
 
24
    You may contact the author by:
 
25
       e-mail:  philnelson@acm.org
 
26
      us-mail:  Philip A. Nelson
 
27
                Computer Science Department, 9062
 
28
                Western Washington University
 
29
                Bellingham, WA 98226-9062
 
30
       
 
31
*************************************************************************/
 
32
 
 
33
#include "bcdefs.h"
 
34
#include "global.h"
 
35
#include "proto.h"
 
36
%}
 
37
 
 
38
%start program
 
39
 
 
40
%union {
 
41
        char     *s_value;
 
42
        char      c_value;
 
43
        int       i_value;
 
44
        arg_list *a_value;
 
45
       }
 
46
 
 
47
/* Extensions over POSIX bc.
 
48
   a) NAME was LETTER.  This grammar allows longer names.
 
49
      Single letter names will still work.
 
50
   b) Relational_expression allowed only one comparison.
 
51
      This grammar has added boolean expressions with
 
52
      && (and) || (or) and ! (not) and allowed all of them in
 
53
      full expressions.
 
54
   c) Added an else to the if.
 
55
   d) Call by variable array parameters
 
56
   e) read() procedure that reads a number under program control from stdin.
 
57
   f) halt statement that halts the the program under program control.  It
 
58
      is an executed statement.
 
59
   g) continue statement for for loops.
 
60
   h) optional expressions in the for loop.
 
61
   i) print statement to print multiple numbers per line.
 
62
   j) warranty statement to print an extended warranty notice.
 
63
   j) limits statement to print the processor's limits.
 
64
*/
 
65
 
 
66
%token <i_value> ENDOFLINE AND OR NOT
 
67
%token <s_value> STRING NAME NUMBER
 
68
/*     '-', '+' are tokens themselves           */
 
69
/*     '=', '+=',  '-=', '*=', '/=', '%=', '^=' */
 
70
%token <c_value> ASSIGN_OP
 
71
/*     '==', '<=', '>=', '!=', '<', '>'         */
 
72
%token <s_value> REL_OP
 
73
/*     '++', '--'                               */
 
74
%token <c_value> INCR_DECR
 
75
/*     'define', 'break', 'quit', 'length'      */
 
76
%token <i_value> Define    Break    Quit    Length
 
77
/*     'return', 'for', 'if', 'while', 'sqrt', 'else'   */
 
78
%token <i_value> Return    For    If    While    Sqrt   Else
 
79
/*     'scale', 'ibase', 'obase', 'auto', 'read'        */
 
80
%token <i_value> Scale    Ibase    Obase    Auto  Read
 
81
/*     'warranty', 'halt', 'last', 'continue', 'print', 'limits'   */
 
82
%token <i_value> Warranty, Halt, Last, Continue, Print, Limits
 
83
/*     'history' */
 
84
%token <i_value> UNARY_MINUS HistoryVar
 
85
 
 
86
/* Types of all other things. */
 
87
%type <i_value> expression return_expression named_expression opt_expression
 
88
%type <c_value> '+' '-' '*' '/' '%' 
 
89
%type <a_value> opt_parameter_list opt_auto_define_list define_list
 
90
%type <a_value> opt_argument_list argument_list
 
91
%type <i_value> program input_item semicolon_list statement_list
 
92
%type <i_value> statement function statement_or_error required_eol
 
93
 
 
94
/* precedence */
 
95
%left OR
 
96
%left AND
 
97
%nonassoc NOT
 
98
%left REL_OP
 
99
%right ASSIGN_OP
 
100
%left '+' '-'
 
101
%left '*' '/' '%'
 
102
%right '^'
 
103
%nonassoc UNARY_MINUS
 
104
%nonassoc INCR_DECR
 
105
 
 
106
%%
 
107
program                 : /* empty */
 
108
                            {
 
109
                              $$ = 0;
 
110
                              if (interactive && !quiet)
 
111
                                {
 
112
                                  show_bc_version ();
 
113
                                  welcome ();
 
114
                                }
 
115
                            }
 
116
                        | program input_item
 
117
                        ;
 
118
input_item              : semicolon_list ENDOFLINE
 
119
                            { run_code (); }
 
120
                        | function
 
121
                            { run_code (); }
 
122
                        | error ENDOFLINE
 
123
                            {
 
124
                              yyerrok;
 
125
                              init_gen ();
 
126
                            }
 
127
                        ;
 
128
opt_newline             : /* empty */
 
129
                        | ENDOFLINE
 
130
                            { warn ("newline not allowed"); }
 
131
                        ;
 
132
semicolon_list          : /* empty */
 
133
                            { $$ = 0; }
 
134
                        | statement_or_error
 
135
                        | semicolon_list ';' statement_or_error
 
136
                        | semicolon_list ';'
 
137
                        ;
 
138
statement_list          : /* empty */
 
139
                            { $$ = 0; }
 
140
                        | statement_or_error
 
141
                        | statement_list ENDOFLINE
 
142
                        | statement_list ENDOFLINE statement_or_error
 
143
                        | statement_list ';'
 
144
                        | statement_list ';' statement
 
145
                        ;
 
146
statement_or_error      : statement
 
147
                        | error statement
 
148
                            { $$ = $2; }
 
149
                        ;
 
150
statement               : Warranty
 
151
                            { warranty (""); }
 
152
                        | Limits
 
153
                            { limits (); }
 
154
                        | expression
 
155
                            {
 
156
                              if ($1 & 2)
 
157
                                warn ("comparison in expression");
 
158
                              if ($1 & 1)
 
159
                                generate ("W");
 
160
                              else 
 
161
                                generate ("p");
 
162
                            }
 
163
                        | STRING
 
164
                            {
 
165
                              $$ = 0;
 
166
                              generate ("w");
 
167
                              generate ($1);
 
168
                              free ($1);
 
169
                            }
 
170
                        | Break
 
171
                            {
 
172
                              if (break_label == 0)
 
173
                                yyerror ("Break outside a for/while");
 
174
                              else
 
175
                                {
 
176
                                  sprintf (genstr, "J%1d:", break_label);
 
177
                                  generate (genstr);
 
178
                                }
 
179
                            }
 
180
                        | Continue
 
181
                            {
 
182
                              warn ("Continue statement");
 
183
                              if (continue_label == 0)
 
184
                                yyerror ("Continue outside a for");
 
185
                              else
 
186
                                {
 
187
                                  sprintf (genstr, "J%1d:", continue_label);
 
188
                                  generate (genstr);
 
189
                                }
 
190
                            }
 
191
                        | Quit
 
192
                            { exit (0); }
 
193
                        | Halt
 
194
                            { generate ("h"); }
 
195
                        | Return return_expression
 
196
                            { generate ("R"); }
 
197
                        | For 
 
198
                            {
 
199
                              $1 = break_label; 
 
200
                              break_label = next_label++;
 
201
                            }
 
202
                          '(' opt_expression ';'
 
203
                            {
 
204
                              if ($4 & 2)
 
205
                                warn ("Comparison in first for expression");
 
206
                              if ($4 >= 0)
 
207
                                generate ("p");
 
208
                              $4 = next_label++;
 
209
                              sprintf (genstr, "N%1d:", $4);
 
210
                              generate (genstr);
 
211
                            }
 
212
                          opt_expression ';'
 
213
                            {
 
214
                              if ($7 < 0) generate ("1");
 
215
                              $7 = next_label++;
 
216
                              sprintf (genstr, "B%1d:J%1d:", $7, break_label);
 
217
                              generate (genstr);
 
218
                              $<i_value>$ = continue_label;
 
219
                              continue_label = next_label++;
 
220
                              sprintf (genstr, "N%1d:", continue_label);
 
221
                              generate (genstr);
 
222
                            }
 
223
                          opt_expression ')'
 
224
                            {
 
225
                              if ($10 & 2 )
 
226
                                warn ("Comparison in third for expression");
 
227
                              if ($10 & 16)
 
228
                                sprintf (genstr, "J%1d:N%1d:", $4, $7);
 
229
                              else
 
230
                                sprintf (genstr, "pJ%1d:N%1d:", $4, $7);
 
231
                              generate (genstr);
 
232
                            }
 
233
                          opt_newline statement
 
234
                            {
 
235
                              sprintf (genstr, "J%1d:N%1d:",
 
236
                                       continue_label, break_label);
 
237
                              generate (genstr);
 
238
                              break_label = $1;
 
239
                              continue_label = $<i_value>9;
 
240
                            }
 
241
                        | If '(' expression ')' 
 
242
                            {
 
243
                              $3 = if_label;
 
244
                              if_label = next_label++;
 
245
                              sprintf (genstr, "Z%1d:", if_label);
 
246
                              generate (genstr);
 
247
                            }
 
248
                          opt_newline statement  opt_else
 
249
                            {
 
250
                              sprintf (genstr, "N%1d:", if_label); 
 
251
                              generate (genstr);
 
252
                              if_label = $3;
 
253
                            }
 
254
                        | While 
 
255
                            {
 
256
                              $1 = next_label++;
 
257
                              sprintf (genstr, "N%1d:", $1);
 
258
                              generate (genstr);
 
259
                            }
 
260
                        '(' expression 
 
261
                            {
 
262
                              $4 = break_label; 
 
263
                              break_label = next_label++;
 
264
                              sprintf (genstr, "Z%1d:", break_label);
 
265
                              generate (genstr);
 
266
                            }
 
267
                        ')' opt_newline statement
 
268
                            {
 
269
                              sprintf (genstr, "J%1d:N%1d:", $1, break_label);
 
270
                              generate (genstr);
 
271
                              break_label = $4;
 
272
                            }
 
273
                        | '{' statement_list '}'
 
274
                            { $$ = 0; }
 
275
                        | Print
 
276
                            {  warn ("print statement"); }
 
277
                          print_list
 
278
                        ;
 
279
print_list              : print_element
 
280
                        | print_element ',' print_list
 
281
                        ;
 
282
print_element           : STRING
 
283
                            {
 
284
                              generate ("O");
 
285
                              generate ($1);
 
286
                              free ($1);
 
287
                            }
 
288
                        | expression
 
289
                            { generate ("P"); }
 
290
                        ;
 
291
opt_else                : /* nothing */
 
292
                        | Else 
 
293
                            {
 
294
                              warn ("else clause in if statement");
 
295
                              $1 = next_label++;
 
296
                              sprintf (genstr, "J%d:N%1d:", $1, if_label); 
 
297
                              generate (genstr);
 
298
                              if_label = $1;
 
299
                            }
 
300
                          opt_newline statement
 
301
function                : Define NAME '(' opt_parameter_list ')' opt_newline
 
302
                          '{' required_eol opt_auto_define_list 
 
303
                            {
 
304
                              /* Check auto list against parameter list? */
 
305
                              check_params ($4,$9);
 
306
                              sprintf (genstr, "F%d,%s.%s[",
 
307
                                       lookup($2,FUNCTDEF), 
 
308
                                       arg_str ($4), arg_str ($9));
 
309
                              generate (genstr);
 
310
                              free_args ($4);
 
311
                              free_args ($9);
 
312
                              $1 = next_label;
 
313
                              next_label = 1;
 
314
                            }
 
315
                          statement_list /* ENDOFLINE */ '}'
 
316
                            {
 
317
                              generate ("0R]");
 
318
                              next_label = $1;
 
319
                            }
 
320
                        ;
 
321
opt_parameter_list      : /* empty */ 
 
322
                            { $$ = NULL; }
 
323
                        | define_list
 
324
                        ;
 
325
opt_auto_define_list    : /* empty */ 
 
326
                            { $$ = NULL; }
 
327
                        | Auto define_list ENDOFLINE
 
328
                            { $$ = $2; } 
 
329
                        | Auto define_list ';'
 
330
                            { $$ = $2; } 
 
331
                        ;
 
332
define_list             : NAME
 
333
                            { $$ = nextarg (NULL, lookup ($1,SIMPLE), FALSE);}
 
334
                        | NAME '[' ']'
 
335
                            { $$ = nextarg (NULL, lookup ($1,ARRAY), FALSE); }
 
336
                        | '*' NAME '[' ']'
 
337
                            { $$ = nextarg (NULL, lookup ($2,ARRAY), TRUE); }
 
338
                        | define_list ',' NAME
 
339
                            { $$ = nextarg ($1, lookup ($3,SIMPLE), FALSE); }
 
340
                        | define_list ',' NAME '[' ']'
 
341
                            { $$ = nextarg ($1, lookup ($3,ARRAY), FALSE); }
 
342
                        | define_list ',' '*' NAME '[' ']'
 
343
                            { $$ = nextarg ($1, lookup ($4,ARRAY), TRUE); }
 
344
                        ;
 
345
opt_argument_list       : /* empty */
 
346
                            { $$ = NULL; }
 
347
                        | argument_list
 
348
                        ;
 
349
argument_list           : expression
 
350
                            {
 
351
                              if ($1 & 2) warn ("comparison in argument");
 
352
                              $$ = nextarg (NULL,0,FALSE);
 
353
                            }
 
354
                        | NAME '[' ']'
 
355
                            {
 
356
                              sprintf (genstr, "K%d:", -lookup ($1,ARRAY));
 
357
                              generate (genstr);
 
358
                              $$ = nextarg (NULL,1,FALSE);
 
359
                            }
 
360
                        | argument_list ',' expression
 
361
                            {
 
362
                              if ($3 & 2) warn ("comparison in argument");
 
363
                              $$ = nextarg ($1,0,FALSE);
 
364
                            }
 
365
                        | argument_list ',' NAME '[' ']'
 
366
                            {
 
367
                              sprintf (genstr, "K%d:", -lookup ($3,ARRAY));
 
368
                              generate (genstr);
 
369
                              $$ = nextarg ($1,1,FALSE);
 
370
                            }
 
371
                        ;
 
372
 
 
373
/* Expression lval meanings!  (Bits mean something!)
 
374
 *  0 => Top op is assignment.
 
375
 *  1 => Top op is not assignment.
 
376
 *  2 => Comparison is somewhere in expression.
 
377
 *  4 => Expression is in parenthesis.
 
378
 * 16 => Empty optional expression.
 
379
 */
 
380
 
 
381
opt_expression          : /* empty */
 
382
                            {
 
383
                              $$ = 16;
 
384
                              warn ("Missing expression in for statement");
 
385
                            }
 
386
                        | expression
 
387
                        ;
 
388
return_expression       : /* empty */
 
389
                            {
 
390
                              $$ = 0;
 
391
                              generate ("0");
 
392
                            }
 
393
                        | expression
 
394
                            {
 
395
                              if ($1 & 2)
 
396
                                warn ("comparison in return expresion");
 
397
                              if (!($1 & 4))
 
398
                                warn ("return expression requires parenthesis");
 
399
                            }
 
400
                        ;
 
401
expression              :  named_expression ASSIGN_OP 
 
402
                            {
 
403
                              if ($2 != '=')
 
404
                                {
 
405
                                  if ($1 < 0)
 
406
                                    sprintf (genstr, "DL%d:", -$1);
 
407
                                  else
 
408
                                    sprintf (genstr, "l%d:", $1);
 
409
                                  generate (genstr);
 
410
                                }
 
411
                            }
 
412
                          expression
 
413
                            {
 
414
                              if ($4 & 2) warn("comparison in assignment");
 
415
                              if ($2 != '=')
 
416
                                {
 
417
                                  sprintf (genstr, "%c", $2);
 
418
                                  generate (genstr);
 
419
                                }
 
420
                              if ($1 < 0)
 
421
                                sprintf (genstr, "S%d:", -$1);
 
422
                              else
 
423
                                sprintf (genstr, "s%d:", $1);
 
424
                              generate (genstr);
 
425
                              $$ = 0;
 
426
                            }
 
427
                        ;
 
428
                        | expression AND 
 
429
                            {
 
430
                              warn("&& operator");
 
431
                              $2 = next_label++;
 
432
                              sprintf (genstr, "DZ%d:p", $2);
 
433
                              generate (genstr);
 
434
                            }
 
435
                          expression
 
436
                            {
 
437
                              sprintf (genstr, "DZ%d:p1N%d:", $2, $2);
 
438
                              generate (genstr);
 
439
                              $$ = ($1 | $4) & ~4;
 
440
                            }
 
441
                        | expression OR
 
442
                            {
 
443
                              warn("|| operator");
 
444
                              $2 = next_label++;
 
445
                              sprintf (genstr, "B%d:", $2);
 
446
                              generate (genstr);
 
447
                            }
 
448
                          expression
 
449
                            {
 
450
                              int tmplab;
 
451
                              tmplab = next_label++;
 
452
                              sprintf (genstr, "B%d:0J%d:N%d:1N%d:",
 
453
                                       $2, tmplab, $2, tmplab);
 
454
                              generate (genstr);
 
455
                              $$ = ($1 | $4) & ~4;
 
456
                            }
 
457
                        | NOT expression
 
458
                            {
 
459
                              $$ = $2 & ~4;
 
460
                              warn("! operator");
 
461
                              generate ("!");
 
462
                            }
 
463
                        | expression REL_OP expression
 
464
                            {
 
465
                              $$ = 3;
 
466
                              switch (*($2))
 
467
                                {
 
468
                                case '=':
 
469
                                  generate ("=");
 
470
                                  break;
 
471
 
 
472
                                case '!':
 
473
                                  generate ("#");
 
474
                                  break;
 
475
 
 
476
                                case '<':
 
477
                                  if ($2[1] == '=')
 
478
                                    generate ("{");
 
479
                                  else
 
480
                                    generate ("<");
 
481
                                  break;
 
482
 
 
483
                                case '>':
 
484
                                  if ($2[1] == '=')
 
485
                                    generate ("}");
 
486
                                  else
 
487
                                    generate (">");
 
488
                                  break;
 
489
                                }
 
490
                            }
 
491
                        | expression '+' expression
 
492
                            {
 
493
                              generate ("+");
 
494
                              $$ = ($1 | $3) & ~4;
 
495
                            }
 
496
                        | expression '-' expression
 
497
                            {
 
498
                              generate ("-");
 
499
                              $$ = ($1 | $3) & ~4;
 
500
                            }
 
501
                        | expression '*' expression
 
502
                            {
 
503
                              generate ("*");
 
504
                              $$ = ($1 | $3) & ~4;
 
505
                            }
 
506
                        | expression '/' expression
 
507
                            {
 
508
                              generate ("/");
 
509
                              $$ = ($1 | $3) & ~4;
 
510
                            }
 
511
                        | expression '%' expression
 
512
                            {
 
513
                              generate ("%");
 
514
                              $$ = ($1 | $3) & ~4;
 
515
                            }
 
516
                        | expression '^' expression
 
517
                            {
 
518
                              generate ("^");
 
519
                              $$ = ($1 | $3) & ~4;
 
520
                            }
 
521
                        | '-' expression  %prec UNARY_MINUS
 
522
                            {
 
523
                              generate ("n");
 
524
                              $$ = $2 & ~4;
 
525
                            }
 
526
                        | named_expression
 
527
                            {
 
528
                              $$ = 1;
 
529
                              if ($1 < 0)
 
530
                                sprintf (genstr, "L%d:", -$1);
 
531
                              else
 
532
                                sprintf (genstr, "l%d:", $1);
 
533
                              generate (genstr);
 
534
                            }
 
535
                        | NUMBER
 
536
                            {
 
537
                              int len = strlen($1);
 
538
                              $$ = 1;
 
539
                              if (len == 1 && *$1 == '0')
 
540
                                generate ("0");
 
541
                              else if (len == 1 && *$1 == '1')
 
542
                                generate ("1");
 
543
                              else
 
544
                                {
 
545
                                  generate ("K");
 
546
                                  generate ($1);
 
547
                                  generate (":");
 
548
                                }
 
549
                              free ($1);
 
550
                            }
 
551
                        | '(' expression ')'
 
552
                            { $$ = $2 | 5; }
 
553
                        | NAME '(' opt_argument_list ')'
 
554
                            {
 
555
                              $$ = 1;
 
556
                              if ($3 != NULL)
 
557
                                { 
 
558
                                  sprintf (genstr, "C%d,%s:",
 
559
                                           lookup ($1,FUNCT),
 
560
                                           call_str ($3));
 
561
                                  free_args ($3);
 
562
                                }
 
563
                              else
 
564
                                {
 
565
                                  sprintf (genstr, "C%d:", lookup ($1,FUNCT));
 
566
                                }
 
567
                              generate (genstr);
 
568
                            }
 
569
                        | INCR_DECR named_expression
 
570
                            {
 
571
                              $$ = 1;
 
572
                              if ($2 < 0)
 
573
                                {
 
574
                                  if ($1 == '+')
 
575
                                    sprintf (genstr, "DA%d:L%d:", -$2, -$2);
 
576
                                  else
 
577
                                    sprintf (genstr, "DM%d:L%d:", -$2, -$2);
 
578
                                }
 
579
                              else
 
580
                                {
 
581
                                  if ($1 == '+')
 
582
                                    sprintf (genstr, "i%d:l%d:", $2, $2);
 
583
                                  else
 
584
                                    sprintf (genstr, "d%d:l%d:", $2, $2);
 
585
                                }
 
586
                              generate (genstr);
 
587
                            }
 
588
                        | named_expression INCR_DECR
 
589
                            {
 
590
                              $$ = 1;
 
591
                              if ($1 < 0)
 
592
                                {
 
593
                                  sprintf (genstr, "DL%d:x", -$1);
 
594
                                  generate (genstr); 
 
595
                                  if ($2 == '+')
 
596
                                    sprintf (genstr, "A%d:", -$1);
 
597
                                  else
 
598
                                      sprintf (genstr, "M%d:", -$1);
 
599
                                }
 
600
                              else
 
601
                                {
 
602
                                  sprintf (genstr, "l%d:", $1);
 
603
                                  generate (genstr);
 
604
                                  if ($2 == '+')
 
605
                                    sprintf (genstr, "i%d:", $1);
 
606
                                  else
 
607
                                    sprintf (genstr, "d%d:", $1);
 
608
                                }
 
609
                              generate (genstr);
 
610
                            }
 
611
                        | Length '(' expression ')'
 
612
                            { generate ("cL"); $$ = 1;}
 
613
                        | Sqrt '(' expression ')'
 
614
                            { generate ("cR"); $$ = 1;}
 
615
                        | Scale '(' expression ')'
 
616
                            { generate ("cS"); $$ = 1;}
 
617
                        | Read '(' ')'
 
618
                            {
 
619
                              warn ("read function");
 
620
                              generate ("cI"); $$ = 1;
 
621
                            }
 
622
                        ;
 
623
named_expression        : NAME
 
624
                            { $$ = lookup($1,SIMPLE); }
 
625
                        | NAME '[' expression ']'
 
626
                            {
 
627
                              if ($3 > 1) warn("comparison in subscript");
 
628
                              $$ = lookup($1,ARRAY);
 
629
                            }
 
630
                        | Ibase
 
631
                            { $$ = 0; }
 
632
                        | Obase
 
633
                            { $$ = 1; }
 
634
                        | Scale
 
635
                            { $$ = 2; }
 
636
                        | HistoryVar
 
637
                            { $$ = 3;
 
638
                              warn ("History variable");
 
639
                            }
 
640
                        | Last
 
641
                            { $$ = 4;
 
642
                              warn ("Last variable");
 
643
                            }
 
644
                        ;
 
645
 
 
646
 
 
647
required_eol            : { warn ("End of line required"); }
 
648
                        | ENDOFLINE
 
649
                        | required_eol ENDOFLINE
 
650
                          { warn ("Too many end of lines"); }
 
651
                        ;
 
652
 
 
653
%%
 
654