-*- Autoconf -*- # D language support for Bison # Copyright (C) 2018-2022 Free Software Foundation, Inc. # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . m4_include(b4_skeletonsdir/[c-like.m4]) # b4_symbol_action(SYMBOL-NUM, ACTION) # ------------------------------------ # Run the action ACTION ("destructor" or "printer") for SYMBOL-NUM. m4_define([b4_symbol_action], [b4_symbol_if([$1], [has_$2], [b4_dollar_pushdef([yyval], [$1], [], [yyloc])dnl _b4_symbol_case([$1])[]dnl b4_syncline([b4_symbol([$1], [$2_line])], [b4_symbol([$1], [$2_file])])dnl b4_symbol([$1], [$2]) b4_syncline([@oline@], [@ofile@])dnl break; b4_dollar_popdef[]dnl ])]) # b4_use(EXPR) # ------------ # Pacify the compiler about some maybe unused value. m4_define([b4_use], []) # b4_sync_start(LINE, FILE) # ------------------------- m4_define([b4_sync_start], [[#]line $1 $2]) # b4_list2(LIST1, LIST2) # ---------------------- # Join two lists with a comma if necessary. m4_define([b4_list2], [$1[]m4_ifval(m4_quote($1), [m4_ifval(m4_quote($2), [[, ]])])[]$2]) # b4_percent_define_get3(DEF, PRE, POST, NOT) # ------------------------------------------- # Expand to the value of DEF surrounded by PRE and POST if it's %define'ed, # otherwise NOT. m4_define([b4_percent_define_get3], [m4_ifval(m4_quote(b4_percent_define_get([$1])), [$2[]b4_percent_define_get([$1])[]$3], [$4])]) # b4_percent_define_if_get2(ARG1, ARG2, DEF, NOT) # ----------------------------------------------- # Expand to the value of DEF if ARG1 or ARG2 are %define'ed, # otherwise NOT. m4_define([b4_percent_define_if_get2], [m4_ifval(m4_quote(b4_percent_define_get([$1])), [$3], [m4_ifval(m4_quote(b4_percent_define_get([$2])), [$3], [$4])])]) # b4_percent_define_class_before_interface(CLASS, INTERFACE) # ---------------------------------------------------------- # Expand to a ', ' if both a class and an interface have been %define'ed m4_define([b4_percent_define_class_before_interface], [m4_ifval(m4_quote(b4_percent_define_get([$1])), [m4_ifval(m4_quote(b4_percent_define_get([$2])), [, ])])]) # b4_flag_value(BOOLEAN-FLAG) # --------------------------- m4_define([b4_flag_value], [b4_flag_if([$1], [true], [false])]) # b4_parser_class_declaration # --------------------------- # The declaration of the parser class ("class YYParser"), with all its # qualifiers/annotations. b4_percent_define_default([[api.parser.abstract]], [[false]]) b4_percent_define_default([[api.parser.final]], [[false]]) b4_percent_define_default([[api.parser.public]], [[false]]) m4_define([b4_parser_class_declaration], [b4_percent_define_get3([api.parser.annotations], [], [ ])dnl b4_percent_define_flag_if([api.parser.public], [public ])dnl b4_percent_define_flag_if([api.parser.abstract], [abstract ])dnl b4_percent_define_flag_if([api.parser.final], [final ])dnl [class ]b4_parser_class[]dnl b4_percent_define_if_get2([api.parser.extends], [api.parser.implements], [ : ])dnl b4_percent_define_get([api.parser.extends])dnl b4_percent_define_class_before_interface([api.parser.extends], [api.parser.implements])dnl b4_percent_define_get([api.parser.implements])]) # b4_lexer_if(TRUE, FALSE) # ------------------------ m4_define([b4_lexer_if], [b4_percent_code_ifdef([[lexer]], [$1], [$2])]) # b4_position_type_if(TRUE, FALSE) # -------------------------------- m4_define([b4_position_type_if], [b4_percent_define_ifdef([[position_type]], [$1], [$2])]) # b4_location_type_if(TRUE, FALSE) # -------------------------------- m4_define([b4_location_type_if], [b4_percent_define_ifdef([[location_type]], [$1], [$2])]) # b4_identification # ----------------- m4_define([b4_identification], [[/** Version number for the Bison executable that generated this parser. */ public static immutable string yy_bison_version = "]b4_version_string["; /** Name of the skeleton that generated this parser. */ public static immutable string yy_bison_skeleton = ]b4_skeleton[; ]]) ## ------------ ## ## Data types. ## ## ------------ ## # b4_int_type(MIN, MAX) # --------------------- # Return the smallest int type able to handle numbers ranging from # MIN to MAX (included). m4_define([b4_int_type], [m4_if(b4_ints_in($@, [-128], [127]), [1], [byte], b4_ints_in($@, [-32768], [32767]), [1], [short], [int])]) # b4_int_type_for(NAME) # --------------------- # Return the smallest int type able to handle numbers ranging from # `NAME_min' to `NAME_max' (included). m4_define([b4_int_type_for], [b4_int_type($1_min, $1_max)]) # b4_null # ------- m4_define([b4_null], [null]) # b4_integral_parser_table_define(NAME, DATA, COMMENT) #----------------------------------------------------- # Define "yy" whose contents is CONTENT. m4_define([b4_integral_parser_table_define], [m4_ifvaln([$3], [b4_comment([$3], [ ])])dnl private static immutable b4_int_type_for([$2])[[]] yy$1_ = @{ $2 @};dnl ]) ## ------------- ## ## Token kinds. ## ## ------------- ## m4_define([b4_symbol(-2, id)], [[YYEMPTY]]) b4_percent_define_default([[api.token.raw]], [[true]]) # b4_token_enum(TOKEN-NAME, TOKEN-NUMBER) # --------------------------------------- # Output the definition of this token as an enum. m4_define([b4_token_enum], [b4_token_format([ %s = %s, ], [$1])]) # b4_token_enums # -------------- # Output the definition of the tokens as enums. m4_define([b4_token_enums], [/* Token kinds. */ public enum TokenKind { ]b4_symbol(empty, id)[ = -2, b4_symbol_foreach([b4_token_enum])dnl } ]) # b4_symbol_translate(STRING) # --------------------------- # Used by "bison" in the array of symbol names to mark those that # require translation. m4_define([b4_symbol_translate], [[_($1)]]) # _b4_token_constructor_define(SYMBOL-NUM) # ---------------------------------------- # Define Symbol.FOO for SYMBOL-NUM. m4_define([_b4_token_constructor_define], [b4_token_visible_if([$1], [[ static auto ]b4_symbol([$1], [id])[(]b4_symbol_if([$1], [has_type], [b4_union_if([b4_symbol([$1], [type]], [[typeof(YYSemanticType.]b4_symbol([$1], [type])[]])) [val]])dnl []b4_locations_if([b4_symbol_if([$1], [has_type], [[, ]])[Location l]])[) { return Symbol(TokenKind.]b4_symbol([$1], [id])[]b4_symbol_if([$1], [has_type], [[, val]])[]b4_locations_if([[, l]])[); }]])]) # b4_token_constructor_define # --------------------------- # Define Symbol.FOO for each token kind FOO. m4_define([b4_token_constructor_define], [[ /* Implementation of token constructors for each symbol type visible to * the user. The code generates static methods that have the same names * as the TokenKinds. */]b4_symbol_foreach([_b4_token_constructor_define])dnl ]) ## -------------- ## ## Symbol kinds. ## ## -------------- ## # b4_symbol_kind(NUM) # ------------------- m4_define([b4_symbol_kind], [SymbolKind.b4_symbol_kind_base($@)]) # b4_symbol_enum(SYMBOL-NUM) # -------------------------- # Output the definition of this symbol as an enum. m4_define([b4_symbol_enum], [m4_format([ %-30s %s], m4_format([[%s = %s,]], b4_symbol([$1], [kind_base]), [$1]), [b4_symbol_tag_comment([$1])])]) # b4_declare_symbol_enum # ---------------------- # The definition of the symbol internal numbers as an enum. # Defining YYEMPTY here is important: it forces the compiler # to use a signed type, which matters for yytoken. m4_define([b4_declare_symbol_enum], [[ /* Symbol kinds. */ struct SymbolKind { enum { ]b4_symbol(empty, kind_base)[ = -2, /* No symbol. */ ]b4_symbol_foreach([b4_symbol_enum])dnl [ } private int yycode_; alias yycode_ this; this(int code) { yycode_ = code; } /* Return YYSTR after stripping away unnecessary quotes and backslashes, so that it's suitable for yyerror. The heuristic is that double-quoting is unnecessary unless the string contains an apostrophe, a comma, or backslash (other than backslash-backslash). YYSTR is taken from yytname. */ final void toString(void delegate(const(char)[]) sink) const { immutable string[] yy_sname = @{ ]b4_symbol_names[ @};]b4_has_translations_if([[ /* YYTRANSLATABLE[SYMBOL-NUM] -- Whether YY_SNAME[SYMBOL-NUM] is internationalizable. */ immutable ]b4_int_type_for([b4_translatable])[[] yytranslatable = @{ ]b4_translatable[ @};]])[ sink.formattedWrite!"%s"(yy_sname[yycode_]); } } ]]) # b4_case(ID, CODE, [COMMENTS]) # ----------------------------- m4_define([b4_case], [ case $1:m4_ifval([$3], [ b4_comment([$3])]) $2 break;]) ## ---------------- ## ## Default values. ## ## ---------------- ## m4_define([b4_yystype], [b4_percent_define_get([[stype]])]) b4_percent_define_default([[stype]], [[YYSemanticType]])]) # %name-prefix m4_define_default([b4_prefix], [[YY]]) b4_percent_define_default([[api.parser.class]], [b4_prefix[]Parser])]) m4_define([b4_parser_class], [b4_percent_define_get([[api.parser.class]])]) #b4_percent_define_default([[location_type]], [Location])]) m4_define([b4_location_type], b4_percent_define_ifdef([[location_type]],[b4_percent_define_get([[location_type]])],[YYLocation])) #b4_percent_define_default([[position_type]], [Position])]) m4_define([b4_position_type], b4_percent_define_ifdef([[position_type]],[b4_percent_define_get([[position_type]])],[YYPosition])) ## ---------------- ## ## api.value.type. ## ## ---------------- ## # ---------------------- # # api.value.type=union. # # ---------------------- # # b4_symbol_type_register(SYMBOL-NUM) # ----------------------------------- # Symbol SYMBOL-NUM has a type (for union) instead of a type-tag. # Extend the definition of %union's body (b4_union_members) with a # field of that type, and extend the symbol's "type" field to point to # the field name, instead of the type name. m4_define([b4_symbol_type_register], [m4_define([b4_symbol($1, type_tag)], [b4_symbol_if([$1], [has_id], [b4_symbol([$1], [id])], [yykind_[]b4_symbol([$1], [number])])])dnl m4_append([b4_union_members], m4_expand([m4_format([ %-40s %s], m4_expand([b4_symbol([$1], [type]) b4_symbol([$1], [type_tag]);]), [b4_symbol_tag_comment([$1])])])) ]) # b4_type_define_tag(SYMBOL1-NUM, ...) # ------------------------------------ # For the batch of symbols SYMBOL1-NUM... (which all have the same # type), enhance the %union definition for each of them, and set # there "type" field to the field tag name, instead of the type name. m4_define([b4_type_define_tag], [b4_symbol_if([$1], [has_type], [m4_map([b4_symbol_type_register], [$@])]) ]) # b4_symbol_value_union(VAL, SYMBOL-NUM, [TYPE]) # ---------------------------------------------- # Same of b4_symbol_value, but when api.value.type=union. m4_define([b4_symbol_value_union], [m4_ifval([$3], [(*($3*)(&$1))], [m4_ifval([$2], [b4_symbol_if([$2], [has_type], [($1.b4_symbol([$2], [type_tag]))], [$1])], [$1])])]) # b4_value_type_setup_union # ------------------------- # Setup support for api.value.type=union. Symbols are defined with a # type instead of a union member name: build the corresponding union, # and give the symbols their tag. m4_define([b4_value_type_setup_union], [m4_define([b4_union_members]) b4_type_foreach([b4_type_define_tag]) m4_copy_force([b4_symbol_value_union], [b4_symbol_value]) ]) # _b4_value_type_setup_keyword # ---------------------------- # api.value.type is defined with a keyword/string syntax. Check if # that is properly defined, and prepare its use. m4_define([_b4_value_type_setup_keyword], [b4_percent_define_check_values([[[[api.value.type]], [[none]], [[union]], [[union-directive]], [[yystype]]]])dnl m4_case(b4_percent_define_get([[api.value.type]]), [union], [b4_value_type_setup_union])]) # b4_value_type_setup # ------------------- # Check if api.value.type is properly defined, and possibly prepare # its use. b4_define_silent([b4_value_type_setup], [ # Define default value. b4_percent_define_ifdef([[api.value.type]], [], [# %union => api.value.type=union-directive m4_ifdef([b4_union_members], [m4_define([b4_percent_define_kind(api.value.type)], [keyword]) m4_define([b4_percent_define(api.value.type)], [union-directive])], [# no tag seen => api.value.type={int} m4_if(b4_tag_seen_flag, 0, [m4_define([b4_percent_define_kind(api.value.type)], [code]) m4_define([b4_percent_define(api.value.type)], [int])], [# otherwise api.value.type=yystype m4_define([b4_percent_define_kind(api.value.type)], [keyword]) m4_define([b4_percent_define(api.value.type)], [yystype])])])]) # Set up. m4_bmatch(b4_percent_define_get_kind([[api.value.type]]), [keyword], [_b4_value_type_setup_keyword]) ]) ## ----------------- ## ## Semantic Values. ## ## ----------------- ## # b4_symbol_value(VAL, [SYMBOL-NUM], [TYPE-TAG]) # ---------------------------------------------- # See README. FIXME: factor in c-like? m4_define([b4_symbol_value], [m4_ifval([$3], [($1.$3)], [m4_ifval([$2], [b4_symbol_if([$2], [has_type], [($1.b4_symbol([$2], [type]))], [$1])], [$1])])]) # b4_lhs_value(SYMBOL-NUM, [TYPE]) # -------------------------------- # See README. m4_define([b4_lhs_value], [b4_symbol_value([yyval], [$1], [$2])]) # b4_rhs_value(RULE-LENGTH, POS, SYMBOL-NUM, [TYPE]) # -------------------------------------------------- # See README. # # In this simple implementation, %token and %type have class names # between the angle brackets. m4_define([b4_rhs_value], [b4_symbol_value([(yystack.valueAt (b4_subtract([$1], [$2])))], [$3], [$4])]) # b4_lhs_location() # ----------------- # Expansion of @$. m4_define([b4_lhs_location], [(yyloc)]) # b4_rhs_location(RULE-LENGTH, POS) # --------------------------------- # Expansion of @POS, where the current rule has RULE-LENGTH symbols # on RHS. m4_define([b4_rhs_location], [yystack.locationAt (b4_subtract($@))]) # b4_lex_param # b4_parse_param # -------------- # If defined, b4_lex_param arrives double quoted, but below we prefer # it to be single quoted. Same for b4_parse_param. # TODO: should be in bison.m4 m4_define_default([b4_lex_param], [[]])) m4_define([b4_lex_param], b4_lex_param)) m4_define([b4_parse_param], b4_parse_param)) # b4_lex_param_decl # ------------------- # Extra formal arguments of the constructor. m4_define([b4_lex_param_decl], [m4_ifset([b4_lex_param], [b4_remove_comma([$1], b4_param_decls(b4_lex_param))], [$1])]) m4_define([b4_param_decls], [m4_map([b4_param_decl], [$@])]) m4_define([b4_param_decl], [, $1]) m4_define([b4_remove_comma], [m4_ifval(m4_quote($1), [$1, ], [])m4_shift2($@)]) # b4_parse_param_decl # ------------------- # Extra formal arguments of the constructor. m4_define([b4_parse_param_decl], [m4_ifset([b4_parse_param], [b4_remove_comma([$1], b4_param_decls(b4_parse_param))], [$1])]) # b4_lex_param_call # ------------------- # Delegating the lexer parameters to the lexer constructor. m4_define([b4_lex_param_call], [m4_ifset([b4_lex_param], [b4_remove_comma([$1], b4_param_calls(b4_lex_param))], [$1])]) m4_define([b4_param_calls], [m4_map([b4_param_call], [$@])]) m4_define([b4_param_call], [, $2]) # b4_parse_param_cons # ------------------- # Extra initialisations of the constructor. m4_define([b4_parse_param_cons], [m4_ifset([b4_parse_param], [b4_constructor_calls(b4_parse_param)])]) m4_define([b4_constructor_calls], [m4_map([b4_constructor_call], [$@])]) m4_define([b4_constructor_call], [this.$2 = $2; ]) # b4_parse_param_vars # ------------------- # Extra instance variables. m4_define([b4_parse_param_vars], [m4_ifset([b4_parse_param], [ /* User arguments. */ b4_var_decls(b4_parse_param)])]) m4_define([b4_var_decls], [m4_map_sep([b4_var_decl], [ ], [$@])]) m4_define([b4_var_decl], [ protected $1;]) # b4_public_types_declare # ----------------------- # Define the public types: token, semantic value, location, and so forth. # Depending on %define token_lex, may be output in the header or source file. m4_define([b4_public_types_declare], [[ alias Symbol = ]b4_parser_class[.Symbol; alias Value = ]b4_yystype[;]b4_locations_if([[ alias Location = ]b4_location_type[; alias Position = ]b4_position_type[;]b4_push_if([[ alias PUSH_MORE = ]b4_parser_class[.YYPUSH_MORE; alias ABORT = ]b4_parser_class[.YYABORT; alias ACCEPT = ]b4_parser_class[.YYACCEPT;]])[]])[ ]]) # b4_basic_symbol_constructor_define # ---------------------------------- # Create Symbol struct constructors for all the visible types. m4_define([b4_basic_symbol_constructor_define], [b4_token_visible_if([$1], [[ this(TokenKind token]b4_symbol_if([$1], [has_type], [[, ]b4_union_if([], [[typeof(YYSemanticType.]])b4_symbol([$1], [type])dnl []b4_union_if([], [[) ]])[ val]])[]b4_locations_if([[, Location loc]])[) { kind = yytranslate_(token);]b4_union_if([b4_symbol_if([$1], [has_type], [[ static foreach (member; __traits(allMembers, YYSemanticType)) { static if (is(typeof(mixin("value_." ~ member)) == ]b4_symbol([$1], [type])[)) { mixin("value_." ~ member ~ " = val;"); } }]])], [b4_symbol_if([$1], [has_type], [[ value_.]b4_symbol([$1], [type])[ = val;]])])[]b4_locations_if([ location_ = loc;])[ } ]])]) # b4_symbol_type_define # --------------------- # Define symbol_type, the external type for symbols used for symbol # constructors. m4_define([b4_symbol_type_define], [[ /** * A complete symbol */ struct Symbol { private SymbolKind kind; private Value value_;]b4_locations_if([[ private Location location_;]])[ ]b4_type_foreach([b4_basic_symbol_constructor_define])[ SymbolKind token() { return kind; } Value value() { return value_; }]b4_locations_if([[ Location location() { return location_; }]])[ ]b4_token_ctor_if([b4_token_constructor_define])[ } ]])