d: add token constructors support

The user can return from yylex() by calling the Symbol method of the
same name as the TokenKind reported, and adding the parameters for
value and location if necessary.  These methods generate compile-time
errors if the parameters are not correlated.  Token constructors work
with both %union and api.value.type union.

* data/skeletons/d.m4: Here.
* tests/calc.at: Test it.
This commit is contained in:
Adela Vais
2021-01-25 22:53:30 +02:00
committed by Akim Demaille
parent ae0889d805
commit 4bd4cdf377
2 changed files with 53 additions and 16 deletions

View File

@@ -208,6 +208,32 @@ b4_symbol_foreach([b4_token_enum])dnl
m4_define([b4_symbol_translate],
[[_($1)]])
# _b4_token_constructor_define
# ----------------------------
# Define make_symbol for a value type.
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 the overloaded versions of make_symbol for all the value types.
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])])
## -------------- ##
## Symbol kinds. ##
## -------------- ##
@@ -593,5 +619,6 @@ m4_define([b4_symbol_type_define],
SymbolKind token() { return kind; }
Value value() { return value_; }]b4_locations_if([[
Location location() { return location_; }]])[
]b4_token_ctor_if([b4_token_constructor_define])[
}
]])

View File

@@ -519,6 +519,16 @@ m4_copy([_AT_DATA_CALC_Y(c)], [_AT_DATA_CALC_Y(c++)])
## Calc in D. ##
## ----------- ##
# AT_YYLEX_RETURN_VAL
# -------------------
# Produce the return value for yylex().
m4_define([AT_YYLEX_RETURN_VAL],
[return dnl
AT_TOKEN_CTOR_IF(
[[Symbol.]AT_TOKEN_PREFIX[$1](m4_ifval([$2], [$2])[]AT_LOCATION_IF([m4_ifval([$2], [, ])[location]])[);]],
[[Symbol(TokenKind.]AT_TOKEN_PREFIX[$1]m4_ifval([$2], [, $2])[]AT_LOCATION_IF([[, location]])[);]])]
)
# AT_CALC_MAIN(d).
m4_define([AT_CALC_MAIN(d)],
[[int main (string[] args)
@@ -595,11 +605,10 @@ if (isInputRange!R && is (ElementType!R : dchar))
// EOF.
if (input.empty)
return Symbol(TokenKind.]AT_TOKEN_PREFIX[EOF]AT_LOCATION_IF([[, location]])[);
]AT_YYLEX_RETURN_VAL([EOF])[
// Numbers.
if (input.front.isNumber)
return Symbol(TokenKind.]AT_TOKEN_PREFIX[NUM, parseInt]AT_LOCATION_IF([[, location]])[);
]AT_YYLEX_RETURN_VAL([NUM], [parseInt])[
// Individual characters
auto c = input.front;]AT_LOCATION_IF([[
@@ -616,22 +625,22 @@ if (isInputRange!R && is (ElementType!R : dchar))
if (c == '#')
{
stderr.writeln (]AT_LOCATION_IF([location, ": ", ])["syntax error: invalid character: '#'");
return Symbol(TokenKind.]AT_TOKEN_PREFIX[YYerror]AT_LOCATION_IF([[, location]])[);
]AT_YYLEX_RETURN_VAL([YYerror])[
}
switch (c)
{
case '+': return Symbol(TokenKind.]AT_TOKEN_PREFIX[PLUS]AT_LOCATION_IF([[, location]])[);
case '-': return Symbol(TokenKind.]AT_TOKEN_PREFIX[MINUS]AT_LOCATION_IF([[, location]])[);
case '*': return Symbol(TokenKind.]AT_TOKEN_PREFIX[STAR]AT_LOCATION_IF([[, location]])[);
case '/': return Symbol(TokenKind.]AT_TOKEN_PREFIX[SLASH]AT_LOCATION_IF([[, location]])[);
case '(': return Symbol(TokenKind.]AT_TOKEN_PREFIX[LPAR]AT_LOCATION_IF([[, location]])[);
case ')': return Symbol(TokenKind.]AT_TOKEN_PREFIX[RPAR]AT_LOCATION_IF([[, location]])[);
case '\n': return Symbol(TokenKind.]AT_TOKEN_PREFIX[EOL]AT_LOCATION_IF([[, location]])[);
case '=': return Symbol(TokenKind.]AT_TOKEN_PREFIX[EQUAL]AT_LOCATION_IF([[, location]])[);
case '^': return Symbol(TokenKind.]AT_TOKEN_PREFIX[POW]AT_LOCATION_IF([[, location]])[);
case '!': return Symbol(TokenKind.]AT_TOKEN_PREFIX[NOT]AT_LOCATION_IF([[, location]])[);
default: return Symbol(TokenKind.]AT_TOKEN_PREFIX[YYUNDEF]AT_LOCATION_IF([[, location]])[);
case '+': ]AT_YYLEX_RETURN_VAL([PLUS])[
case '-': ]AT_YYLEX_RETURN_VAL([MINUS])[
case '*': ]AT_YYLEX_RETURN_VAL([STAR])[
case '/': ]AT_YYLEX_RETURN_VAL([SLASH])[
case '(': ]AT_YYLEX_RETURN_VAL([LPAR])[
case ')': ]AT_YYLEX_RETURN_VAL([RPAR])[
case '\n': ]AT_YYLEX_RETURN_VAL([EOL])[
case '=': ]AT_YYLEX_RETURN_VAL([EQUAL])[
case '^': ]AT_YYLEX_RETURN_VAL([POW])[
case '!': ]AT_YYLEX_RETURN_VAL([NOT])[
default: ]AT_YYLEX_RETURN_VAL([YYUNDEF])[
}
}
}
@@ -1499,7 +1508,8 @@ AT_CHECK_CALC_LALR1_D([%locations %define parse.lac full %define parse.error det
#AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
#AT_CHECK_CALC_LALR1_D([%locations %define parse.error detailed %debug %define api.prefix {calc} %verbose %parse-param {semantic_value *result}{int *count}{int *nerrs}])
AT_CHECK_CALC_LALR1_D([%define parse.error custom %define api.value.type union])
AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error custom %define api.value.type union])
AT_CHECK_CALC_LALR1_D([%define api.token.constructor %locations %define parse.error detailed])
# ----------------------- #
# LALR1 Java Calculator. #