Implement a Makefile for Inform.
[inform.git] / src / syntax.c
1 /* ------------------------------------------------------------------------- */
2 /*   "syntax" : Syntax analyser and compiler                                 */
3 /*                                                                           */
4 /* Copyright (c) Graham Nelson 1993 - 2018                                   */
5 /*                                                                           */
6 /* This file is part of Inform.                                              */
7 /*                                                                           */
8 /* Inform 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 3 of the License, or         */
11 /* (at your option) any later version.                                       */
12 /*                                                                           */
13 /* Inform 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 Inform. If not, see https://gnu.org/licenses/                  */
20 /*                                                                           */
21 /* ------------------------------------------------------------------------- */
22
23 #include "header.h"
24
25 static char *lexical_source;
26
27 int no_syntax_lines;                                  /*  Syntax line count  */
28
29 static void begin_syntax_line(int statement_mode)
30 {   no_syntax_lines++;
31     next_token_begins_syntax_line = TRUE;
32
33     clear_expression_space();
34     if (statement_mode)
35     {   statements.enabled = TRUE;
36         conditions.enabled = TRUE;
37         local_variables.enabled = TRUE;
38         system_functions.enabled = TRUE;
39
40         misc_keywords.enabled = FALSE;
41         directive_keywords.enabled = FALSE;
42         directives.enabled = FALSE;
43         segment_markers.enabled = FALSE;
44         opcode_names.enabled = FALSE;
45     }
46     else
47     {   directives.enabled = TRUE;
48         segment_markers.enabled = TRUE;
49
50         statements.enabled = FALSE;
51         misc_keywords.enabled = FALSE;
52         directive_keywords.enabled = FALSE;
53         local_variables.enabled = FALSE;
54         system_functions.enabled = FALSE;
55         conditions.enabled = FALSE;
56         opcode_names.enabled = FALSE;
57     }
58
59     sequence_point_follows = TRUE;
60
61     if (debugfile_switch)
62     {   get_next_token();
63         statement_debug_location = get_token_location();
64         put_token_back();
65     }
66 }
67
68 extern void panic_mode_error_recovery(void)
69 {
70     /* Consume tokens until the next semicolon (or end of file).
71        This is typically called after a syntax error, in hopes of
72        getting parsing back on track. */
73
74     while ((token_type != EOF_TT)
75            && ((token_type != SEP_TT)||(token_value != SEMICOLON_SEP)))
76
77         get_next_token();
78 }
79
80 extern void get_next_token_with_directives(void)
81 {
82     /* A higher-level version of get_next_token(), which detects and
83        obeys directives such as #ifdef/#ifnot/#endif. (The # sign is
84        required in this case.)
85
86        This is called while parsing a long construct, such as Class or
87        Object, where we want to support internal #ifdefs. (Although
88        function-parsing predates this and doesn't make use of it.)
89
90        (Technically this permits *any* #-directive, which means you
91        can define global variables or properties or what-have-you in
92        the middle of an object. You can do that in the middle of an
93        object, too. Don't. It's about as well-supported as Wile E.
94        Coyote one beat before the plummet-lines kick in.) */
95
96     int directives_save, segment_markers_save, statements_save;
97
98     while (TRUE)
99     {
100         get_next_token();
101
102         /* If the first token is not a '#', return it directly. */
103         if ((token_type != SEP_TT) || (token_value != HASH_SEP))
104             return;
105
106         /* Save the lexer flags, and set up for directive parsing. */
107         directives_save = directives.enabled;
108         segment_markers_save = segment_markers.enabled;
109         statements_save = statements.enabled;
110
111         directives.enabled = TRUE;
112         segment_markers.enabled = FALSE;
113         statements.enabled = FALSE;
114         conditions.enabled = FALSE;
115         local_variables.enabled = FALSE;
116         misc_keywords.enabled = FALSE;
117         system_functions.enabled = FALSE;
118
119         get_next_token();
120
121         if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
122         {   error("It is illegal to nest a routine inside an object using '#['");
123             return;
124         }
125
126         if (token_type == DIRECTIVE_TT)
127             parse_given_directive(TRUE);
128         else
129         {   ebf_error("directive", token_text);
130             return;
131         }
132
133         /* Restore all the lexer flags. (We are squashing several of them
134            into a single save variable, which I think is safe because that's
135            what CKnight did.)
136         */
137         directive_keywords.enabled = FALSE;
138         directives.enabled = directives_save;
139         segment_markers.enabled = segment_markers_save;
140         statements.enabled =
141             conditions.enabled =
142             local_variables.enabled =
143             misc_keywords.enabled = 
144             system_functions.enabled = statements_save;
145     }
146 }
147
148 extern void parse_program(char *source)
149 {
150     lexical_source = source;
151     while (parse_directive(FALSE)) ;
152 }
153
154 extern int parse_directive(int internal_flag)
155 {
156     /*  Internal_flag is FALSE if the directive is encountered normally,
157         TRUE if encountered with a # prefix inside a routine or object
158         definition.
159
160         Returns: TRUE if program continues, FALSE if end of file reached.    */
161
162     int routine_symbol, rep_symbol;
163     int is_renamed;
164
165     begin_syntax_line(FALSE);
166     get_next_token();
167
168     if (token_type == EOF_TT) return(FALSE);
169
170     if ((token_type == SEP_TT) && (token_value == HASH_SEP))
171         get_next_token();
172
173     if ((token_type == SEP_TT) && (token_value == OPEN_SQUARE_SEP))
174     {   if (internal_flag)
175         {   error("It is illegal to nest routines using '#['");
176             return(TRUE);
177         }
178
179         directives.enabled = FALSE;
180         directive_keywords.enabled = FALSE;
181         segment_markers.enabled = FALSE;
182
183         /* The upcoming symbol is a definition; don't count it as a
184            top-level reference *to* the function. */
185         df_dont_note_global_symbols = TRUE;
186         get_next_token();
187         df_dont_note_global_symbols = FALSE;
188         if ((token_type != SYMBOL_TT)
189             || ((!(sflags[token_value] & UNKNOWN_SFLAG))
190                 && (!(sflags[token_value] & REPLACE_SFLAG))))
191         {   ebf_error("routine name", token_text);
192             return(FALSE);
193         }
194
195         routine_symbol = token_value;
196
197         rep_symbol = routine_symbol;
198         is_renamed = find_symbol_replacement(&rep_symbol);
199
200         if ((sflags[routine_symbol] & REPLACE_SFLAG) 
201             && !is_renamed && (is_systemfile()))
202         {   /* The function is definitely being replaced (system_file
203                always loses priority in a replacement) but is not
204                being renamed to something else. Skip its definition
205                entirely. */
206             dont_enter_into_symbol_table = TRUE;
207             do
208             {   get_next_token();
209             } while (!((token_type == EOF_TT)
210                      || ((token_type==SEP_TT)
211                          && (token_value==CLOSE_SQUARE_SEP))));
212             dont_enter_into_symbol_table = FALSE;
213             if (token_type == EOF_TT) return FALSE;
214         }
215         else
216         {   /* Parse the function definition and assign its symbol. */
217             assign_symbol(routine_symbol,
218                 parse_routine(lexical_source, FALSE,
219                     (char *) symbs[routine_symbol], FALSE, routine_symbol),
220                 ROUTINE_T);
221             slines[routine_symbol] = routine_starts_line;
222         }
223
224         if (is_renamed) {
225             /* This function was subject to a "Replace X Y" directive.
226                The first time we see a definition for symbol X, we
227                copy it to Y -- that's the "original" form of the
228                function. */
229             if (svals[rep_symbol] == 0) {
230                 assign_symbol(rep_symbol, svals[routine_symbol], ROUTINE_T);
231             }
232         }
233
234         get_next_token();
235         if ((token_type != SEP_TT) || (token_value != SEMICOLON_SEP))
236         {   ebf_error("';' after ']'", token_text);
237             put_token_back();
238         }
239         return TRUE;
240     }
241
242     if ((token_type == SYMBOL_TT) && (stypes[token_value] == CLASS_T))
243     {   if (internal_flag)
244         {   error("It is illegal to nest an object in a routine using '#classname'");
245             return(TRUE);
246         }
247         sflags[token_value] |= USED_SFLAG;
248         make_object(FALSE, NULL, -1, -1, svals[token_value]);
249         return TRUE;
250     }
251
252     if (token_type != DIRECTIVE_TT)
253     {   /* If we're internal, we expect only a directive here. If
254            we're top-level, the possibilities are broader. */
255         if (internal_flag)
256             ebf_error("directive", token_text);
257         else
258             ebf_error("directive, '[' or class name", token_text);
259         panic_mode_error_recovery();
260         return TRUE;
261     }
262
263     return !(parse_given_directive(internal_flag));
264 }
265
266 static int switch_sign(void)
267 {
268     if ((token_type == SEP_TT)&&(token_value == COLON_SEP))   return 1;
269     if ((token_type == SEP_TT)&&(token_value == COMMA_SEP))   return 2;
270     if ((token_type==MISC_KEYWORD_TT)&&(token_value==TO_MK))  return 3;
271     return 0;
272 }
273
274 static assembly_operand spec_stack[32];
275 static int spec_type[32];
276
277 static void compile_alternatives_z(assembly_operand switch_value, int n,
278     int stack_level, int label, int flag)
279 {   switch(n)
280     {   case 1:
281             assemblez_2_branch(je_zc, switch_value,
282                 spec_stack[stack_level],
283                 label, flag); return;
284         case 2:
285             assemblez_3_branch(je_zc, switch_value,
286                 spec_stack[stack_level], spec_stack[stack_level+1],
287                 label, flag); return;
288         case 3:
289             assemblez_4_branch(je_zc, switch_value,
290                 spec_stack[stack_level], spec_stack[stack_level+1],
291                 spec_stack[stack_level+2],
292                 label, flag); return;
293     }
294 }
295
296 static void compile_alternatives_g(assembly_operand switch_value, int n,
297     int stack_level, int label, int flag)
298 {   
299     int the_zc = (flag) ? jeq_gc : jne_gc;
300
301     if (n == 1) {
302       assembleg_2_branch(the_zc, switch_value,
303         spec_stack[stack_level],
304         label); 
305     }
306     else {
307       error("*** Cannot generate multi-equality tests in Glulx ***");
308     }
309 }
310
311 static void compile_alternatives(assembly_operand switch_value, int n,
312     int stack_level, int label, int flag)
313 {
314   if (!glulx_mode)
315     compile_alternatives_z(switch_value, n, stack_level, label, flag);
316   else
317     compile_alternatives_g(switch_value, n, stack_level, label, flag);
318 }
319
320 static void parse_switch_spec(assembly_operand switch_value, int label,
321     int action_switch)
322 {
323     int i, j, label_after = -1, spec_sp = 0;
324     int max_equality_args = ((!glulx_mode) ? 3 : 1);
325
326     sequence_point_follows = FALSE;
327
328     do
329     {   if (spec_sp == 32)
330         {   error("At most 32 values can be given in a single 'switch' case");
331             panic_mode_error_recovery();
332             return;
333         }
334
335         if (action_switch)
336         {   get_next_token();
337             if (token_type == SQ_TT || token_type == DQ_TT) {
338                 ebf_error("action (or fake action) name", token_text);
339                 continue;
340             }
341             spec_stack[spec_sp] = action_of_name(token_text);
342
343             if (spec_stack[spec_sp].value == -1)
344             {   spec_stack[spec_sp].value = 0;
345                 ebf_error("action (or fake action) name", token_text);
346             }
347         }
348         else
349             spec_stack[spec_sp] =
350       code_generate(parse_expression(CONSTANT_CONTEXT), CONSTANT_CONTEXT, -1);
351
352         misc_keywords.enabled = TRUE;
353         get_next_token();
354         misc_keywords.enabled = FALSE;
355
356         spec_type[spec_sp++] = switch_sign();
357         switch(spec_type[spec_sp-1])
358         {   case 0:
359                 if (action_switch)
360                     ebf_error("',' or ':'", token_text);
361                 else ebf_error("',', ':' or 'to'", token_text);
362                 panic_mode_error_recovery();
363                 return;
364             case 1: goto GenSpecCode;
365             case 3: if (label_after == -1) label_after = next_label++;
366         }
367      } while(TRUE);
368
369      GenSpecCode:
370
371      if ((spec_sp > max_equality_args) && (label_after == -1))
372          label_after = next_label++;
373
374      if (label_after == -1)
375      {   compile_alternatives(switch_value, spec_sp, 0, label, FALSE); return;
376      }
377
378      for (i=0; i<spec_sp;)
379      {
380          j=i; while ((j<spec_sp) && (spec_type[j] != 3)) j++;
381
382          if (j > i)
383          {   if (j-i > max_equality_args) j=i+max_equality_args;
384
385              if (j == spec_sp)
386                  compile_alternatives(switch_value, j-i, i, label, FALSE);
387              else
388                  compile_alternatives(switch_value, j-i, i, label_after, TRUE);
389
390              i=j;
391          }
392          else
393          {   
394            if (!glulx_mode) {
395              if (i == spec_sp - 2)
396              {   assemblez_2_branch(jl_zc, switch_value, spec_stack[i],
397                      label, TRUE);
398                  assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1],
399                      label, TRUE);
400              }
401              else
402              {   assemblez_2_branch(jl_zc, switch_value, spec_stack[i],
403                      next_label, TRUE);
404                  assemblez_2_branch(jg_zc, switch_value, spec_stack[i+1],
405                      label_after, FALSE);
406                  assemble_label_no(next_label++);
407              }
408            }
409            else {
410              if (i == spec_sp - 2)
411              {   assembleg_2_branch(jlt_gc, switch_value, spec_stack[i],
412                      label);
413                  assembleg_2_branch(jgt_gc, switch_value, spec_stack[i+1],
414                      label);
415              }
416              else
417              {   assembleg_2_branch(jlt_gc, switch_value, spec_stack[i],
418                      next_label);
419                  assembleg_2_branch(jle_gc, switch_value, spec_stack[i+1],
420                      label_after);
421                  assemble_label_no(next_label++);
422              }
423            }
424            i = i+2;
425          }
426      }
427
428      assemble_label_no(label_after);
429 }
430
431 extern int32 parse_routine(char *source, int embedded_flag, char *name,
432     int veneer_flag, int r_symbol)
433 {   int32 packed_address; int i; int debug_flag = FALSE;
434     int switch_clause_made = FALSE, default_clause_made = FALSE,
435         switch_label = 0;
436     debug_location_beginning beginning_debug_location =
437         get_token_location_beginning();
438
439     /*  (switch_label needs no initialisation here, but it prevents some
440         compilers from issuing warnings)   */
441
442     if ((source != lexical_source) || (veneer_flag))
443     {   lexical_source = source;
444         restart_lexer(lexical_source, name);
445     }
446
447     no_locals = 0;
448
449     for (i=0;i<MAX_LOCAL_VARIABLES-1;i++) local_variables.keywords[i] = "";
450
451     do
452     {   statements.enabled = TRUE;
453         dont_enter_into_symbol_table = TRUE;
454         get_next_token();
455         dont_enter_into_symbol_table = FALSE;
456         if ((token_type == SEP_TT) && (token_value == TIMES_SEP)
457             && (no_locals == 0) && (!debug_flag))
458         {   debug_flag = TRUE; continue;
459         }
460
461         if (token_type != DQ_TT)
462         {   if ((token_type == SEP_TT)
463                 && (token_value == SEMICOLON_SEP)) break;
464             ebf_error("local variable name or ';'", token_text);
465             panic_mode_error_recovery();
466             break;
467         }
468
469         if (strlen(token_text) > MAX_IDENTIFIER_LENGTH)
470         {   error_named("Local variable identifier too long:", token_text);
471             panic_mode_error_recovery();
472             break;
473         }
474
475         if (no_locals == MAX_LOCAL_VARIABLES-1)
476         {   error_numbered("Too many local variables for a routine; max is",
477                 MAX_LOCAL_VARIABLES-1);
478             panic_mode_error_recovery();
479             break;
480         }
481
482         for (i=0;i<no_locals;i++)
483             if (strcmpcis(token_text, local_variables.keywords[i])==0)
484                 error_named("Local variable defined twice:", token_text);
485         local_variables.keywords[no_locals++] = token_text;
486     } while(TRUE);
487
488     construct_local_variable_tables();
489
490     if ((trace_fns_setting==3)
491         || ((trace_fns_setting==2) && (veneer_mode==FALSE))
492         || ((trace_fns_setting==1) && (is_systemfile()==FALSE)))
493         debug_flag = TRUE;
494     if ((embedded_flag == FALSE) && (veneer_mode == FALSE) && debug_flag)
495         sflags[r_symbol] |= STAR_SFLAG;
496
497     packed_address = assemble_routine_header(no_locals, debug_flag,
498         name, embedded_flag, r_symbol);
499
500     do
501     {   begin_syntax_line(TRUE);
502
503         get_next_token();
504
505         if (token_type == EOF_TT)
506         {   ebf_error("']'", token_text);
507             assemble_routine_end
508                 (embedded_flag,
509                  get_token_location_end(beginning_debug_location));
510             put_token_back();
511             break;
512         }
513
514         if ((token_type == SEP_TT)
515             && (token_value == CLOSE_SQUARE_SEP))
516         {   if (switch_clause_made && (!default_clause_made))
517                 assemble_label_no(switch_label);
518             directives.enabled = TRUE;
519             sequence_point_follows = TRUE;
520             get_next_token();
521             assemble_routine_end
522                 (embedded_flag,
523                  get_token_location_end(beginning_debug_location));
524             put_token_back();
525             break;
526         }
527
528         if ((token_type == STATEMENT_TT) && (token_value == SDEFAULT_CODE))
529         {   if (default_clause_made)
530                 error("Multiple 'default' clauses defined in same 'switch'");
531             default_clause_made = TRUE;
532
533             if (switch_clause_made)
534             {   if (!execution_never_reaches_here)
535                 {   sequence_point_follows = FALSE;
536                     if (!glulx_mode)
537                         assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc);
538                     else
539                         assembleg_1(return_gc, 
540                             ((embedded_flag)?zero_operand:one_operand));
541                 }
542                 assemble_label_no(switch_label);
543             }
544             switch_clause_made = TRUE;
545
546             get_next_token();
547             if ((token_type == SEP_TT) &&
548                 (token_value == COLON_SEP)) continue;
549             ebf_error("':' after 'default'", token_text);
550             panic_mode_error_recovery();
551             continue;
552         }
553
554         /*  Only check for the form of a case switch if the initial token
555             isn't double-quoted text, as that would mean it was a print_ret
556             statement: this is a mild ambiguity in the grammar. 
557             Action statements also cannot be cases. */
558
559         if ((token_type != DQ_TT) && (token_type != SEP_TT))
560         {   get_next_token();
561             if (switch_sign() > 0)
562             {   assembly_operand AO;
563                 if (default_clause_made)
564                     error("'default' must be the last 'switch' case");
565
566                 if (switch_clause_made)
567                 {   if (!execution_never_reaches_here)
568                     {   sequence_point_follows = FALSE;
569                         if (!glulx_mode)
570                             assemblez_0((embedded_flag)?rfalse_zc:rtrue_zc);
571                         else
572                             assembleg_1(return_gc, 
573                                 ((embedded_flag)?zero_operand:one_operand));
574                     }
575                     assemble_label_no(switch_label);
576                 }
577
578                 switch_label = next_label++;
579                 switch_clause_made = TRUE;
580                 put_token_back(); put_token_back();
581
582                 if (!glulx_mode) {
583                     INITAOTV(&AO, VARIABLE_OT, 249);
584                 }
585                 else {
586                     INITAOTV(&AO, GLOBALVAR_OT, MAX_LOCAL_VARIABLES+6); /* sw__var */
587                 }
588                 parse_switch_spec(AO, switch_label, TRUE);
589
590                 continue;
591             }
592             else
593             {   put_token_back(); put_token_back(); get_next_token();
594                 sequence_point_follows = TRUE;
595             }
596         }
597
598         parse_statement(-1, -1);
599
600     } while (TRUE);
601
602     return packed_address;
603 }
604
605 extern void parse_code_block(int break_label, int continue_label,
606     int switch_rule)
607 {   int switch_clause_made = FALSE, default_clause_made = FALSE, switch_label = 0,
608         unary_minus_flag;
609
610     begin_syntax_line(TRUE);
611     get_next_token();
612
613     if (token_type == SEP_TT && token_value == OPEN_BRACE_SEP)
614     {   do
615         {   begin_syntax_line(TRUE);
616             get_next_token();
617             if (token_type == SEP_TT && token_value == CLOSE_BRACE_SEP)
618             {   if (switch_clause_made && (!default_clause_made))
619                     assemble_label_no(switch_label);
620                 return;
621             }
622             if (token_type == EOF_TT)
623             {   ebf_error("'}'", token_text); return; }
624
625             if (switch_rule != 0)
626             {
627                 /*  Within a 'switch' block  */
628
629                 if ((token_type==STATEMENT_TT)&&(token_value==SDEFAULT_CODE))
630                 {   if (default_clause_made)
631                 error("Multiple 'default' clauses defined in same 'switch'");
632                     default_clause_made = TRUE;
633
634                     if (switch_clause_made)
635                     {   if (!execution_never_reaches_here)
636                         {   sequence_point_follows = FALSE;
637                             assemble_jump(break_label);
638                         }
639                         assemble_label_no(switch_label);
640                     }
641                     switch_clause_made = TRUE;
642
643                     get_next_token();
644                     if ((token_type == SEP_TT) &&
645                         (token_value == COLON_SEP)) continue;
646                     ebf_error("':' after 'default'", token_text);
647                     panic_mode_error_recovery();
648                     continue;
649                 }
650
651                 /*  Decide: is this an ordinary statement, or the start
652                     of a new case?  */
653
654                 if (token_type == DQ_TT) goto NotASwitchCase;
655
656                 unary_minus_flag
657                     = ((token_type == SEP_TT)&&(token_value == MINUS_SEP));
658                 if (unary_minus_flag) get_next_token();
659
660                 /*  Now read the token _after_ any possible constant:
661                     if that's a 'to', ',' or ':' then we have a case  */
662
663                 misc_keywords.enabled = TRUE;
664                 get_next_token();
665                 misc_keywords.enabled = FALSE;
666
667                 if (switch_sign() > 0)
668                 {   assembly_operand AO;
669
670                     if (default_clause_made)
671                         error("'default' must be the last 'switch' case");
672
673                     if (switch_clause_made)
674                     {   if (!execution_never_reaches_here)
675                         {   sequence_point_follows = FALSE;
676                             assemble_jump(break_label);
677                         }
678                         assemble_label_no(switch_label);
679                     }
680
681                     switch_label = next_label++;
682                     switch_clause_made = TRUE;
683                     put_token_back(); put_token_back();
684                     if (unary_minus_flag) put_token_back();
685
686                     AO = temp_var1;
687                     parse_switch_spec(AO, switch_label, FALSE);
688                     continue;
689                 }
690                 else
691                 {   put_token_back(); put_token_back();
692                     if (unary_minus_flag) put_token_back();
693                     get_next_token();
694                 }
695             }
696
697             if ((switch_rule != 0) && (!switch_clause_made))
698                 ebf_error("switch value", token_text);
699
700             NotASwitchCase:
701             sequence_point_follows = TRUE;
702             parse_statement(break_label, continue_label);
703         }
704         while(TRUE);
705     }
706
707     if (switch_rule != 0)
708         ebf_error("braced code block after 'switch'", token_text);
709
710     parse_statement(break_label, continue_label);
711     return;
712 }
713
714 /* ========================================================================= */
715 /*   Data structure management routines                                      */
716 /* ------------------------------------------------------------------------- */
717
718 extern void init_syntax_vars(void)
719 {
720 }
721
722 extern void syntax_begin_pass(void)
723 {   no_syntax_lines = 0;
724 }
725
726 extern void syntax_allocate_arrays(void)
727 {
728 }
729
730 extern void syntax_free_arrays(void)
731 {
732 }
733
734 /* ========================================================================= */