mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-23 07:59:37 +00:00
1299 lines
48 KiB
Text
1299 lines
48 KiB
Text
// vim: set filetype=none:
|
|
// (Lemon files have .y extensions like Yacc files but are not Yacc.)
|
|
|
|
%include {
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include "../lib/mlrutil.h"
|
|
#include "./ex_ast.h"
|
|
#include "../containers/sllv.h"
|
|
|
|
#define DO_WRITE_APPEND // transitional pending lemon-memory issue
|
|
|
|
// ================================================================
|
|
// AST:
|
|
// * parens, commas, semis, line endings, whitespace are all stripped away
|
|
// * variable names and literal values remain as leaf nodes of the AST
|
|
// * = + - * / ** {function names} remain as non-leaf nodes of the AST
|
|
// CST: See ex1_cst.c
|
|
//
|
|
// Note: This parser accepts many things that are invalid, e.g.
|
|
// * begin{end{}} -- begin/end not at top level
|
|
// * begin{$x=1} -- references to stream records at begin/end
|
|
// * break/continue outside of for/while/do-while
|
|
// * $x=x -- boundvars outside of for-loop variable bindings
|
|
// All of the above are enforced by the CST builder, which takes this parser's output AST as input.
|
|
// This is done (a) to keep this grammar from being overly complex, and (b) so we can get much more
|
|
// informative error messages in C than in Lemon ('syntax error').
|
|
//
|
|
// The parser hooks all build up an abstract syntax tree specifically for the CST builder.
|
|
// For clearer visuals on what the ASTs look like:
|
|
// * See ex1_cst.c
|
|
// * See reg_test/run's filter -v and put -v outputs, e.g. in reg_test/expected/out
|
|
// * Do "mlr -n put -v 'your expression goes here'"
|
|
// ================================================================
|
|
|
|
}
|
|
|
|
%token_type {ex_ast_node_t*}
|
|
%default_type {ex_ast_node_t*}
|
|
%extra_argument {ex_ast_t* past}
|
|
|
|
//void token_destructor(ex_ast_node_t t) {
|
|
// printf("In token_destructor t->text(%s)=t->type(%lf)\n", t->text, t->type);
|
|
//}
|
|
//%token_destructor {token_destructor($$);}
|
|
|
|
%parse_accept {
|
|
}
|
|
|
|
// The caller is expected to provide more context.
|
|
%syntax_error {
|
|
fprintf(stderr, "mlr DSL: syntax error.\n");
|
|
}
|
|
|
|
// ================================================================
|
|
md_body ::= md_statement_list(B). {
|
|
past->proot = B;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Given "$a=1;$b=2;$c=3": since this is a bottom-up parser, we get first the "$a=1", then
|
|
// "$a=1;$b=2", then "$a=1;$b=2;$c=3", then finally realize that's the top level, or it's embedded
|
|
// within a cond-block, or for-loop body, etc.
|
|
|
|
// * On the "$a=1" we make a sub-AST called "list" with child $a=1.
|
|
// * On the "$b=2" we append the next argument to get "list" having children $a=1 and $b=2.
|
|
// * On the "$c=3" we append the next argument to get "list" having children $a=1, $b=2, and $c=3.
|
|
//
|
|
// We handle statements of the form ' ; ; ' by parsing the empty spaces around the semicolons as NOP nodes.
|
|
// But, the NOP nodes are immediately stripped here and are not included in the AST we return.
|
|
|
|
md_statement_list(A) ::= md_statement_not_braced_end(B). {
|
|
if (B->type == MD_AST_NODE_TYPE_NOP) {
|
|
A = ex_ast_node_alloc_zary("list", MD_AST_NODE_TYPE_STATEMENT_BLOCK);
|
|
} else {
|
|
A = ex_ast_node_alloc_unary("list", MD_AST_NODE_TYPE_STATEMENT_BLOCK, B);
|
|
}
|
|
}
|
|
|
|
md_statement_list(A) ::= md_statement_braced_end(B). {
|
|
if (B->type == MD_AST_NODE_TYPE_NOP) {
|
|
A = ex_ast_node_alloc_zary("list", MD_AST_NODE_TYPE_STATEMENT_BLOCK);
|
|
} else {
|
|
A = ex_ast_node_alloc_unary("list", MD_AST_NODE_TYPE_STATEMENT_BLOCK, B);
|
|
}
|
|
}
|
|
|
|
// This could also be done with the list on the left and statement on the right. However,
|
|
// curly-brace-terminated statements *end* with a semicolon; they don't start with one. So this seems
|
|
// to be the right way to differentiate.
|
|
md_statement_list(A) ::= md_statement_not_braced_end(B) MD_TOKEN_SEMICOLON md_statement_list(C). {
|
|
if (B->type == MD_AST_NODE_TYPE_NOP) {
|
|
A = C;
|
|
} else {
|
|
A = ex_ast_node_prepend_arg(C, B);
|
|
}
|
|
}
|
|
|
|
md_statement_list(A) ::= md_statement_braced_end(B) MD_SEMICOLON md_statement_list(C). {
|
|
if (B->type == MD_AST_NODE_TYPE_NOP) {
|
|
A = C;
|
|
} else {
|
|
A = ex_ast_node_prepend_arg(C, B);
|
|
}
|
|
}
|
|
|
|
// This allows for trailing semicolon, as well as empty string (or whitespace) between semicolons:
|
|
md_statement_not_braced_end(A) ::= . {
|
|
A = ex_ast_node_alloc_zary("nop", MD_AST_NODE_TYPE_NOP);
|
|
}
|
|
|
|
// Begin/end (non-nestable)
|
|
md_statement_braced_end(A) ::= md_begin_block(B) .{ A = B; }
|
|
md_statement_braced_end(A) ::= md_end_block(B). { A = B; }
|
|
|
|
// Nested control structures:
|
|
md_statement_braced_end(A) ::= md_cond_block(B).
|
|
md_statement_braced_end(A) ::= md_while_block(B).
|
|
md_statement_braced_end(A) ::= md_for_loop_full_srec(B).
|
|
md_statement_braced_end(A) ::= md_for_loop_full_oosvar(B).
|
|
md_statement_braced_end(A) ::= md_for_loop_oosvar(B).
|
|
md_statement_braced_end(A) ::= md_if_chain(B).
|
|
|
|
// Not valid in begin/end since they refer to srecs:
|
|
md_statement_not_braced_end ::= md_srec_assignment.
|
|
md_statement_not_braced_end ::= md_srec_indirect_assignment.
|
|
md_statement_not_braced_end ::= md_oosvar_from_full_srec_assignment.
|
|
md_statement_not_braced_end ::= md_full_srec_from_oosvar_assignment.
|
|
|
|
// Valid in begin/end since they don't refer to srecs (although the RHSs might):
|
|
md_statement_not_braced_end ::= md_do_while_block.
|
|
md_statement_not_braced_end ::= md_bare_boolean.
|
|
md_statement_not_braced_end ::= md_oosvar_assignment.
|
|
md_statement_not_braced_end ::= md_filter.
|
|
md_statement_not_braced_end ::= md_unset.
|
|
|
|
md_statement_not_braced_end ::= md_emitf.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_emitf_write.
|
|
md_statement_not_braced_end ::= md_emitf_append.
|
|
%endif
|
|
md_statement_not_braced_end ::= md_emitp.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_emitp_write.
|
|
md_statement_not_braced_end ::= md_emitp_append.
|
|
%endif
|
|
md_statement_not_braced_end ::= md_emit.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_emit_write.
|
|
md_statement_not_braced_end ::= md_emit_append.
|
|
%endif
|
|
md_statement_not_braced_end ::= md_emitp_lashed.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_emitp_lashed_write.
|
|
md_statement_not_braced_end ::= md_emitp_lashed_append.
|
|
%endif
|
|
md_statement_not_braced_end ::= md_emit_lashed.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_emit_lashed_write.
|
|
md_statement_not_braced_end ::= md_emit_lashed_append.
|
|
%endif
|
|
|
|
md_statement_not_braced_end ::= md_dump.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_dump_write.
|
|
md_statement_not_braced_end ::= md_dump_append.
|
|
%endif
|
|
md_statement_not_braced_end ::= md_edump.
|
|
md_statement_not_braced_end ::= md_print.
|
|
md_statement_not_braced_end ::= md_eprint.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_print_write.
|
|
md_statement_not_braced_end ::= md_print_append.
|
|
%endif
|
|
md_statement_not_braced_end ::= md_printn.
|
|
md_statement_not_braced_end ::= md_eprintn.
|
|
%ifndef DO_WRITE_APPEND
|
|
md_statement_not_braced_end ::= md_printn_write.
|
|
md_statement_not_braced_end ::= md_printn_append.
|
|
%endif
|
|
|
|
// Valid only within for/while, but we accept them here syntactically and reject them in the AST-to-CST
|
|
// conversion, where we can produce much more informative error messages:
|
|
md_statement_not_braced_end(A) ::= MD_TOKEN_BREAK(O). {
|
|
A = ex_ast_node_alloc(O->text, MD_AST_NODE_TYPE_BREAK);
|
|
}
|
|
md_statement_not_braced_end(A) ::= MD_TOKEN_CONTINUE(O). {
|
|
A = ex_ast_node_alloc(O->text, MD_AST_NODE_TYPE_CONTINUE);
|
|
}
|
|
|
|
// ================================================================
|
|
md_begin_block(A) ::= MD_TOKEN_BEGIN(O) MD_TOKEN_LBRACE md_statement_list(B) MD_TOKEN_RBRACE. {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_BEGIN, B);
|
|
}
|
|
md_end_block(A) ::= MD_TOKEN_END(O) MD_TOKEN_LBRACE md_statement_list(B) MD_TOKEN_RBRACE. {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_END, B);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_cond_block(A) ::= md_rhs(B) MD_TOKEN_LBRACE md_statement_list(C) MD_TOKEN_RBRACE. {
|
|
//A = ex_ast_node_prepend_arg(C, B);
|
|
A = ex_ast_node_alloc_binary("cond", MD_AST_NODE_TYPE_CONDITIONAL_BLOCK, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_while_block(A) ::=
|
|
MD_TOKEN_WHILE(O)
|
|
MD_TOKEN_LPAREN md_rhs(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE md_statement_list(C) MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_WHILE, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_do_while_block(A) ::=
|
|
MD_TOKEN_DO(O)
|
|
MD_TOKEN_LBRACE md_statement_list(B) MD_TOKEN_RBRACE
|
|
MD_TOKEN_WHILE
|
|
MD_TOKEN_LPAREN md_rhs(C) MD_TOKEN_RPAREN.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_DO_WHILE, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// for(k, v in $*) { ... }
|
|
md_for_loop_full_srec(A) ::=
|
|
MD_TOKEN_FOR(F) MD_TOKEN_LPAREN
|
|
md_for_loop_index(K) MD_TOKEN_COMMA md_for_loop_index(V)
|
|
MD_TOKEN_IN MD_TOKEN_FULL_SREC
|
|
MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE
|
|
md_statement_list(S)
|
|
MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_binary(
|
|
F->text,
|
|
MD_AST_NODE_TYPE_FOR_SREC,
|
|
ex_ast_node_alloc_binary(
|
|
"variables",
|
|
MD_AST_NODE_TYPE_FOR_VARIABLES,
|
|
K,
|
|
V
|
|
),
|
|
S
|
|
);
|
|
}
|
|
|
|
// for(k, v in @*) { ... }
|
|
md_for_loop_full_oosvar(A) ::=
|
|
MD_TOKEN_FOR(F) MD_TOKEN_LPAREN
|
|
md_for_loop_index(K) MD_TOKEN_COMMA md_for_loop_index(V)
|
|
MD_TOKEN_IN MD_TOKEN_FULL_OOSVAR
|
|
MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE
|
|
md_statement_list(S)
|
|
MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_ternary(
|
|
F->text,
|
|
MD_AST_NODE_TYPE_FOR_OOSVAR,
|
|
ex_ast_node_alloc_binary(
|
|
"key_and_value_variables",
|
|
MD_AST_NODE_TYPE_FOR_VARIABLES,
|
|
ex_ast_node_alloc_unary(
|
|
"key_variables",
|
|
MD_AST_NODE_TYPE_FOR_VARIABLES,
|
|
K
|
|
),
|
|
V
|
|
),
|
|
ex_ast_node_alloc_zary("empty_keylist", MD_AST_NODE_TYPE_OOSVAR_KEYLIST),
|
|
S
|
|
);
|
|
}
|
|
|
|
// for((k1, k2), v in @*) { ... }
|
|
// for((k1, k2, k3), v in @*) { ... }
|
|
md_for_loop_full_oosvar(A) ::=
|
|
MD_TOKEN_FOR(F) MD_TOKEN_LPAREN
|
|
MD_TOKEN_LPAREN md_for_oosvar_keylist(L) MD_TOKEN_RPAREN MD_TOKEN_COMMA md_for_loop_index(V)
|
|
MD_TOKEN_IN MD_TOKEN_FULL_OOSVAR
|
|
MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE
|
|
md_statement_list(S)
|
|
MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_ternary(
|
|
F->text,
|
|
MD_AST_NODE_TYPE_FOR_OOSVAR,
|
|
ex_ast_node_alloc_binary(
|
|
"key_and_value_variables",
|
|
MD_AST_NODE_TYPE_FOR_VARIABLES,
|
|
L,
|
|
V
|
|
),
|
|
ex_ast_node_alloc_zary("empty_keylist", MD_AST_NODE_TYPE_OOSVAR_KEYLIST),
|
|
S
|
|
);
|
|
}
|
|
|
|
// for(k, v in @o[1][2]) { ... }
|
|
md_for_loop_oosvar(A) ::=
|
|
MD_TOKEN_FOR(F) MD_TOKEN_LPAREN
|
|
md_for_loop_index(K) MD_TOKEN_COMMA md_for_loop_index(V)
|
|
MD_TOKEN_IN md_oosvar_keylist(O)
|
|
MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE
|
|
md_statement_list(S)
|
|
MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_ternary(
|
|
F->text,
|
|
MD_AST_NODE_TYPE_FOR_OOSVAR,
|
|
ex_ast_node_alloc_binary(
|
|
"key_and_value_variables",
|
|
MD_AST_NODE_TYPE_FOR_VARIABLES,
|
|
ex_ast_node_alloc_unary(
|
|
"key_variables",
|
|
MD_AST_NODE_TYPE_FOR_VARIABLES,
|
|
K
|
|
),
|
|
V
|
|
),
|
|
O,
|
|
S
|
|
);
|
|
}
|
|
|
|
// for((k1, k2), v in @o[1][2]) { ... }
|
|
// for((k1, k2, k3), v in @o[1][2]) { ... }
|
|
md_for_loop_oosvar(A) ::=
|
|
MD_TOKEN_FOR(F) MD_TOKEN_LPAREN
|
|
MD_TOKEN_LPAREN md_for_oosvar_keylist(L) MD_TOKEN_RPAREN MD_TOKEN_COMMA md_for_loop_index(V)
|
|
MD_TOKEN_IN md_oosvar_keylist(O)
|
|
MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE
|
|
md_statement_list(S)
|
|
MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_ternary(
|
|
F->text,
|
|
MD_AST_NODE_TYPE_FOR_OOSVAR,
|
|
ex_ast_node_alloc_binary(
|
|
"key_and_value_variables",
|
|
MD_AST_NODE_TYPE_FOR_VARIABLES,
|
|
L,
|
|
V
|
|
),
|
|
O,
|
|
S
|
|
);
|
|
}
|
|
|
|
md_for_loop_index(A) ::= MD_TOKEN_NON_SIGIL_NAME(B). {
|
|
A = ex_ast_node_alloc(B->text, MD_AST_NODE_TYPE_NON_SIGIL_NAME);
|
|
}
|
|
md_for_oosvar_keylist(A) ::= MD_TOKEN_NON_SIGIL_NAME(K). {
|
|
A = ex_ast_node_alloc_unary("key_variables", MD_AST_NODE_TYPE_FOR_VARIABLES, K);
|
|
}
|
|
md_for_oosvar_keylist(A) ::= md_for_oosvar_keylist(L) MD_TOKEN_COMMA MD_TOKEN_NON_SIGIL_NAME(K). {
|
|
A = ex_ast_node_append_arg(L, K);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Cases:
|
|
// if elif*
|
|
// if elif* else
|
|
|
|
md_if_chain(A) ::= md_if_elif_star(B) . {
|
|
A = B;
|
|
}
|
|
md_if_chain(A) ::= md_if_elif_star(B) md_else_block(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
md_if_elif_star(A) ::= md_if_block(B). {
|
|
A = ex_ast_node_alloc_unary("if_head", MD_AST_NODE_TYPE_IF_HEAD, B);
|
|
}
|
|
md_if_elif_star(A) ::= md_if_elif_star(B) md_elif_block(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
md_if_block(A) ::=
|
|
MD_TOKEN_IF(O)
|
|
MD_TOKEN_LPAREN md_rhs(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE md_statement_list(C) MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_IF_ITEM, B, C);
|
|
}
|
|
|
|
md_elif_block(A) ::=
|
|
MD_TOKEN_ELIF(O)
|
|
MD_TOKEN_LPAREN md_rhs(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_LBRACE md_statement_list(C) MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_IF_ITEM, B, C);
|
|
}
|
|
|
|
md_else_block(A) ::=
|
|
MD_TOKEN_ELSE(O)
|
|
MD_TOKEN_LBRACE md_statement_list(C) MD_TOKEN_RBRACE.
|
|
{
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_IF_ITEM, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_bare_boolean(A) ::= md_rhs(B). {
|
|
A = B;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_filter(A) ::= MD_TOKEN_FILTER(O) md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_FILTER, B);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_ASSIGN(O) md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B, C);
|
|
}
|
|
md_srec_indirect_assignment(A) ::=
|
|
MD_TOKEN_DOLLAR_SIGN MD_TOKEN_LEFT_BRACKET md_rhs(B) MD_TOKEN_RIGHT_BRACKET
|
|
MD_TOKEN_ASSIGN(O) md_rhs(C).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_INDIRECT_SREC_ASSIGNMENT, B, C);
|
|
}
|
|
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_ASSIGN(O) md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B, C);
|
|
}
|
|
|
|
md_oosvar_from_full_srec_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_ASSIGN(O) MD_TOKEN_FULL_SREC(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OOSVAR_FROM_FULL_SREC_ASSIGNMENT, B, C);
|
|
}
|
|
|
|
md_full_srec_from_oosvar_assignment(A) ::= MD_TOKEN_FULL_SREC(B) MD_TOKEN_ASSIGN(O) md_oosvar_keylist(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_FULL_SREC_FROM_OOSVAR_ASSIGNMENT, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_LOGICAL_OR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("||", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_LOGICAL_XOR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("^^", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_LOGICAL_AND_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("&&", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_BITWISE_OR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("|", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_BITWISE_XOR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("^", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_BITWISE_AND_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("&", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_BITWISE_LSH_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("<<", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_BITWISE_RSH_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary(">>", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_PLUS_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("+", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_MINUS_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("-", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_DOT_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary(".", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_TIMES_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("*", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_DIVIDE_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("/", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_INT_DIVIDE_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("//", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_MOD_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("%", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_srec_assignment(A) ::= md_field_name(B) MD_TOKEN_POW_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_SREC_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("**", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
|
|
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_LOGICAL_OR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("||", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_LOGICAL_XOR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("^^", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_LOGICAL_AND_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("&&", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_BITWISE_OR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("|", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_BITWISE_XOR_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("^", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_BITWISE_AND_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("&", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_BITWISE_LSH_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("<<", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_BITWISE_RSH_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary(">>", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_PLUS_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("+", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_MINUS_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("-", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_DOT_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary(".", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_TIMES_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("*", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_DIVIDE_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("/", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_INT_DIVIDE_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("//", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_MOD_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("%", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
md_oosvar_assignment(A) ::= md_oosvar_keylist(B) MD_TOKEN_POW_EQUALS md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary("=", MD_AST_NODE_TYPE_OOSVAR_ASSIGNMENT, B,
|
|
ex_ast_node_alloc_binary("**", MD_AST_NODE_TYPE_OPERATOR, ex_ast_tree_copy(B) , C));
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_unset(A) ::= MD_TOKEN_UNSET(O) MD_TOKEN_ALL(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_UNSET, B);
|
|
}
|
|
md_unset(A) ::= MD_TOKEN_UNSET(O) MD_TOKEN_FULL_OOSVAR(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_UNSET, B);
|
|
}
|
|
md_unset(A) ::= MD_TOKEN_UNSET(O) md_unset_args(B). {
|
|
A = ex_ast_node_set_function_name(B, O->text);
|
|
}
|
|
// Need to invalidate "emit @a," -- use some non-empty-args expr.
|
|
md_unset_args(A) ::= . {
|
|
A = ex_ast_node_alloc_zary("temp", MD_AST_NODE_TYPE_UNSET);
|
|
}
|
|
|
|
md_unset_args(A) ::= md_field_name(B). {
|
|
A = ex_ast_node_alloc_unary("temp", MD_AST_NODE_TYPE_UNSET, B);
|
|
}
|
|
md_unset_args(A) ::= md_indirect_field_name(B). {
|
|
A = ex_ast_node_alloc_unary("temp", MD_AST_NODE_TYPE_UNSET, B);
|
|
}
|
|
md_unset_args(A) ::= MD_TOKEN_FULL_SREC(B). {
|
|
A = ex_ast_node_alloc_unary("temp", MD_AST_NODE_TYPE_UNSET, B);
|
|
}
|
|
md_unset_args(A) ::= md_oosvar_keylist(B). {
|
|
A = ex_ast_node_alloc_unary("temp", MD_AST_NODE_TYPE_UNSET, B);
|
|
}
|
|
|
|
md_unset_args(A) ::= md_unset_args(B) MD_TOKEN_COMMA md_field_name(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
md_unset_args(A) ::= md_unset_args(B) MD_TOKEN_COMMA md_oosvar_keylist(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Given "emitf @a,@b,@c": since this is a bottom-up parser, we get first the "@a",
|
|
// then "@a,@b", then "@a,@b,@c", then finally "emit @a,@b,@c". So:
|
|
// * On the "@a" we make a sub-AST called "temp @a" (although we could call it "emit").
|
|
// * On the "@b" we append the next argument to get "temp @a,@b".
|
|
// * On the "@c" we append the next argument to get "temp @a,@b,@c".
|
|
// * On the "emit" we change the name to get "emit @a,@b,@c".
|
|
|
|
md_emitf(A) ::= MD_TOKEN_EMITF(O) md_emitf_args(B). {
|
|
A = ex_ast_node_set_function_name(B, O->text);
|
|
}
|
|
// Need to invalidate "emit @a," -- use some non-empty-args expr.
|
|
md_emitf_args(A) ::= . {
|
|
A = ex_ast_node_alloc_zary("temp", MD_AST_NODE_TYPE_EMITF);
|
|
}
|
|
md_emitf_args(A) ::= md_oosvar_keylist(B). {
|
|
A = ex_ast_node_alloc_unary("temp", MD_AST_NODE_TYPE_EMITF, B);
|
|
}
|
|
md_emitf_args(A) ::= md_emitf_args(B) MD_TOKEN_COMMA md_oosvar_keylist(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emitf_write(A) ::= MD_TOKEN_EMITF(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA md_emitf_args(B). {
|
|
B = ex_ast_node_set_function_name(B, O->text);
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITF_WRITE, B, F);
|
|
}
|
|
md_emitf_append(A) ::= MD_TOKEN_EMITF(O) MD_TOKEN_BITWISE_RSH md_rhs(F) MD_TOKEN_COMMA md_emitf_args(B). {
|
|
B = ex_ast_node_set_function_name(B, O->text);
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITF_APPEND, B, F);
|
|
}
|
|
%endif
|
|
|
|
// ----------------------------------------------------------------
|
|
md_emitp(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_ALL(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMITP, B);
|
|
}
|
|
md_emitp(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_ALL(B) MD_TOKEN_COMMA md_emitp_namelist(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP, B, C);
|
|
}
|
|
md_emitp(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_FULL_OOSVAR(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMITP, B);
|
|
}
|
|
md_emitp(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_FULL_OOSVAR(B) MD_TOKEN_COMMA md_emitp_namelist(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP, B, C);
|
|
}
|
|
md_emitp(A) ::= MD_TOKEN_EMITP(O) md_oosvar_keylist(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMITP, B);
|
|
}
|
|
md_emitp(A) ::= MD_TOKEN_EMITP(O) md_oosvar_keylist(B) MD_TOKEN_COMMA md_emitp_namelist(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP, B, C);
|
|
}
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emitp_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, F);
|
|
}
|
|
md_emitp_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B) MD_TOKEN_COMMA md_emitp_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, C, F);
|
|
}
|
|
md_emitp_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, F);
|
|
}
|
|
md_emitp_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B) MD_TOKEN_COMMA md_emitp_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, C, F);
|
|
}
|
|
md_emitp_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, F);
|
|
}
|
|
md_emitp_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B) MD_TOKEN_COMMA md_emitp_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emitp_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_APPEND, B, F);
|
|
}
|
|
md_emitp_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B) MD_TOKEN_COMMA md_emitp_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_APPEND, B, C, F);
|
|
}
|
|
md_emitp_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, F);
|
|
}
|
|
md_emitp_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B) MD_TOKEN_COMMA md_emitp_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_WRITE, B, C, F);
|
|
}
|
|
md_emitp_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_APPEND, B, F);
|
|
}
|
|
md_emitp_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B) MD_TOKEN_COMMA md_emitp_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_APPEND, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
md_emitp_namelist(A) ::= md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary("emitp_namelist", MD_AST_NODE_TYPE_EMITP, B);
|
|
}
|
|
md_emitp_namelist(A) ::= md_emitp_namelist(B) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_emit(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_ALL(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMIT, B);
|
|
}
|
|
md_emit(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_ALL(B) MD_TOKEN_COMMA md_emit_namelist(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT, B, C);
|
|
}
|
|
|
|
md_emit(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_FULL_OOSVAR(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMIT, B);
|
|
}
|
|
md_emit(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_FULL_OOSVAR(B) MD_TOKEN_COMMA md_emit_namelist(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT, B, C);
|
|
}
|
|
|
|
md_emit(A) ::= MD_TOKEN_EMIT(O) md_oosvar_keylist(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMIT, B);
|
|
}
|
|
md_emit(A) ::= MD_TOKEN_EMIT(O) md_oosvar_keylist(B) MD_TOKEN_COMMA md_emit_namelist(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT, B, C);
|
|
}
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emit_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, F);
|
|
}
|
|
md_emit_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B) MD_TOKEN_COMMA md_emit_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, C, F);
|
|
}
|
|
md_emit_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, F);
|
|
}
|
|
md_emit_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B) MD_TOKEN_COMMA md_emit_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, C, F);
|
|
}
|
|
md_emit_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B).
|
|
{
|
|
// xxx
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, F);
|
|
}
|
|
md_emit_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B) MD_TOKEN_COMMA md_emit_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_APPEND, B, F);
|
|
}
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_ALL(B) MD_TOKEN_COMMA md_emit_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_APPEND, B, C, F);
|
|
}
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, F);
|
|
}
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_FULL_OOSVAR(B) MD_TOKEN_COMMA md_emit_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_WRITE, B, C, F);
|
|
}
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_IF md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B).
|
|
{
|
|
// xxx
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_APPEND, B, F);
|
|
}
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_POW md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B).
|
|
{
|
|
// xxx
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_APPEND, B, F);
|
|
}
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B).
|
|
{
|
|
// xxx
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_APPEND, B, F);
|
|
}
|
|
md_emit_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RHS md_rhs(F) MD_TOKEN_COMMA
|
|
md_oosvar_keylist(B) MD_TOKEN_COMMA md_emit_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_APPEND, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
md_emit_namelist(A) ::= md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary("emit_namelist", MD_AST_NODE_TYPE_EMIT, B);
|
|
}
|
|
md_emit_namelist(A) ::= md_emit_namelist(B) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_emitp_lashed(A) ::= MD_TOKEN_EMITP(O)
|
|
MD_TOKEN_LPAREN md_emitp_lashed_keylists(B) MD_TOKEN_RPAREN.
|
|
{
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMITP_LASHED, B);
|
|
}
|
|
md_emitp_lashed(A) ::= MD_TOKEN_EMITP(O)
|
|
MD_TOKEN_LPAREN md_emitp_lashed_keylists(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_COMMA md_emitp_lashed_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_LASHED, B, C);
|
|
}
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emitp_lashed_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emitp_lashed_keylists(B) MD_TOKEN_RPAREN.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_LASHED_WRITE, B, F);
|
|
}
|
|
md_emitp_lashed_write(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emitp_lashed_keylists(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_COMMA md_emitp_lashed_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_LASHED_WRITE, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emitp_lashed_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RSH md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emitp_lashed_keylists(B) MD_TOKEN_RPAREN.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMITP_LASHED_APPEND, B, F);
|
|
}
|
|
md_emitp_lashed_append(A) ::= MD_TOKEN_EMITP(O) MD_TOKEN_BITWISE_RSH md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emitp_lashed_keylists(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_COMMA md_emitp_lashed_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMITP_LASHED_APPEND, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
md_emitp_lashed_keylists(A) ::= md_oosvar_keylist(B). {
|
|
A = ex_ast_node_alloc_unary("lashed_keylists", MD_AST_NODE_TYPE_EMITP_LASHED, B);
|
|
}
|
|
md_emitp_lashed_keylists(A) ::= md_emitp_lashed_keylists(B) MD_TOKEN_COMMA md_oosvar_keylist(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
md_emitp_lashed_namelist(A) ::= md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary("lashed_namelist", MD_AST_NODE_TYPE_EMITP_LASHED, B);
|
|
}
|
|
md_emitp_lashed_namelist(A) ::= md_emitp_lashed_namelist(B) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_emit_lashed(A) ::= MD_TOKEN_EMIT(O)
|
|
MD_TOKEN_LPAREN md_emit_lashed_keylists(B) MD_TOKEN_RPAREN.
|
|
{
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EMIT_LASHED, B);
|
|
}
|
|
md_emit_lashed(A) ::= MD_TOKEN_EMIT(O)
|
|
MD_TOKEN_LPAREN md_emit_lashed_keylists(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_COMMA md_emit_lashed_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_LASHED, B, C);
|
|
}
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emit_lashed_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emit_lashed_keylists(B) MD_TOKEN_RPAREN.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_LASHED_WRITE, B, F);
|
|
}
|
|
md_emit_lashed_write(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emit_lashed_keylists(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_COMMA md_emit_lashed_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_LASHED_WRITE, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
%ifndef DO_WRITE_APPEND
|
|
md_emit_lashed_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RSH md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emit_lashed_keylists(B) MD_TOKEN_RPAREN.
|
|
{
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_EMIT_LASHED_APPEND, B, F);
|
|
}
|
|
md_emit_lashed_append(A) ::= MD_TOKEN_EMIT(O) MD_TOKEN_BITWISE_RSH md_rhs(F) MD_TOKEN_COMMA
|
|
MD_TOKEN_LPAREN md_emit_lashed_keylists(B) MD_TOKEN_RPAREN
|
|
MD_TOKEN_COMMA md_emit_lashed_namelist(C).
|
|
{
|
|
A = ex_ast_node_alloc_ternary(O->text, MD_AST_NODE_TYPE_EMIT_LASHED_APPEND, B, C, F);
|
|
}
|
|
%endif
|
|
|
|
md_emit_lashed_keylists(A) ::= md_oosvar_keylist(B). {
|
|
A = ex_ast_node_alloc_unary("lashed_keylists", MD_AST_NODE_TYPE_EMIT_LASHED, B);
|
|
}
|
|
md_emit_lashed_keylists(A) ::= md_emit_lashed_keylists(B) MD_TOKEN_COMMA md_oosvar_keylist(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
md_emit_lashed_namelist(A) ::= md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary("lashed_namelist", MD_AST_NODE_TYPE_EMIT_LASHED, B);
|
|
}
|
|
md_emit_lashed_namelist(A) ::= md_emit_lashed_namelist(B) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_dump(A) ::= MD_TOKEN_DUMP(O). {
|
|
A = ex_ast_node_alloc_zary(O->text, MD_AST_NODE_TYPE_DUMP);
|
|
}
|
|
md_edump(A) ::= MD_TOKEN_EDUMP(O). {
|
|
A = ex_ast_node_alloc_zary(O->text, MD_AST_NODE_TYPE_EDUMP);
|
|
}
|
|
%ifndef DO_WRITE_APPEND
|
|
md_dump_write(A) ::= MD_TOKEN_DUMP(O) MD_TOKEN_GT md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_DUMP_WRITE, B);
|
|
}
|
|
md_dump_append(A) ::= MD_TOKEN_DUMP(O) MD_TOKEN_BITWISE_RSH md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_DUMP_APPEND, B);
|
|
}
|
|
%endif
|
|
|
|
md_print(A) ::= MD_TOKEN_PRINT(O) md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_PRINT, B);
|
|
}
|
|
md_eprint(A) ::= MD_TOKEN_EPRINT(O) md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EPRINT, B);
|
|
}
|
|
%ifndef DO_WRITE_APPEND
|
|
md_print_write(A) ::= MD_TOKEN_PRINT(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_PRINT_WRITE, C, F);
|
|
}
|
|
md_print_append(A) ::= MD_TOKEN_PRINT(O) MD_TOKEN_BITWISE_RSH md_rhs(F) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_PRINT_APPEND, C, F);
|
|
}
|
|
%endif
|
|
|
|
md_printn(A) ::= MD_TOKEN_PRINTN(O) md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_PRINTN, B);
|
|
}
|
|
md_eprintn(A) ::= MD_TOKEN_EPRINTN(O) md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_EPRINTN, B);
|
|
}
|
|
%ifndef DO_WRITE_APPEND
|
|
md_printn_write(A) ::= MD_TOKEN_PRINTN(O) MD_TOKEN_GT md_rhs(F) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_PRINTN_WRITE, C, F);
|
|
}
|
|
md_printn_append(A) ::= MD_TOKEN_PRINTN(O) MD_TOKEN_BITWISE_RSH md_rhs(F) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_PRINTN_APPEND, C, F);
|
|
}
|
|
%endif
|
|
|
|
// ================================================================
|
|
// Begin RHS precedence chain
|
|
|
|
md_rhs(A) ::= md_ternary(B). {
|
|
A = B;
|
|
}
|
|
|
|
md_ternary(A) ::= md_logical_or_term(B) MD_TOKEN_QUESTION_MARK md_ternary(C) MD_TOKEN_COLON md_ternary(D). {
|
|
A = ex_ast_node_alloc_ternary("? :", MD_AST_NODE_TYPE_OPERATOR, B, C, D);
|
|
}
|
|
|
|
md_ternary(A) ::= md_logical_or_term(B). {
|
|
A = B;
|
|
}
|
|
|
|
// ================================================================
|
|
md_logical_or_term(A) ::= md_logical_xor_term(B). {
|
|
A = B;
|
|
}
|
|
md_logical_or_term(A) ::= md_logical_or_term(B) MD_TOKEN_LOGICAL_OR(O) md_logical_xor_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_logical_xor_term(A) ::= md_logical_and_term(B). {
|
|
A = B;
|
|
}
|
|
md_logical_xor_term(A) ::= md_logical_xor_term(B) MD_TOKEN_LOGICAL_XOR(O) md_logical_and_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_logical_and_term(A) ::= md_eqne_term(B). {
|
|
A = B;
|
|
}
|
|
md_logical_and_term(A) ::= md_logical_and_term(B) MD_TOKEN_LOGICAL_AND(O) md_eqne_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_eqne_term(A) ::= md_cmp_term(B). {
|
|
A = B;
|
|
}
|
|
md_eqne_term(A) ::= md_eqne_term(B) MD_TOKEN_MATCHES(O) md_cmp_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_eqne_term(A) ::= md_eqne_term(B) MD_TOKEN_DOES_NOT_MATCH(O) md_cmp_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_eqne_term(A) ::= md_eqne_term(B) MD_TOKEN_EQ(O) md_cmp_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_eqne_term(A) ::= md_eqne_term(B) MD_TOKEN_NE(O) md_cmp_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_cmp_term(A) ::= md_bitwise_or_term(B). {
|
|
A = B;
|
|
}
|
|
md_cmp_term(A) ::= md_cmp_term(B) MD_TOKEN_GT(O) md_bitwise_or_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_cmp_term(A) ::= md_cmp_term(B) MD_TOKEN_GE(O) md_bitwise_or_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_cmp_term(A) ::= md_cmp_term(B) MD_TOKEN_LT(O) md_bitwise_or_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_cmp_term(A) ::= md_cmp_term(B) MD_TOKEN_LE(O) md_bitwise_or_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_bitwise_or_term(A) ::= md_bitwise_xor_term(B). {
|
|
A = B;
|
|
}
|
|
md_bitwise_or_term(A) ::= md_bitwise_or_term(B) MD_TOKEN_BITWISE_OR(O) md_bitwise_xor_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_bitwise_xor_term(A) ::= md_bitwise_and_term(B). {
|
|
A = B;
|
|
}
|
|
md_bitwise_xor_term(A) ::= md_bitwise_xor_term(B) MD_TOKEN_BITWISE_XOR(O) md_bitwise_and_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_bitwise_and_term(A) ::= md_bitwise_shift_term(B). {
|
|
A = B;
|
|
}
|
|
md_bitwise_and_term(A) ::= md_bitwise_and_term(B) MD_TOKEN_BITWISE_AND(O) md_bitwise_shift_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_bitwise_shift_term(A) ::= md_addsubdot_term(B). {
|
|
A = B;
|
|
}
|
|
md_bitwise_shift_term(A) ::= md_bitwise_shift_term(B) MD_TOKEN_BITWISE_LSH(O) md_addsubdot_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_bitwise_shift_term(A) ::= md_bitwise_shift_term(B) MD_TOKEN_BITWISE_RSH(O) md_addsubdot_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_addsubdot_term(A) ::= md_muldiv_term(B). {
|
|
A = B;
|
|
}
|
|
md_addsubdot_term(A) ::= md_addsubdot_term(B) MD_TOKEN_PLUS(O) md_muldiv_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_addsubdot_term(A) ::= md_addsubdot_term(B) MD_TOKEN_MINUS(O) md_muldiv_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_addsubdot_term(A) ::= md_addsubdot_term(B) MD_TOKEN_DOT(O) md_muldiv_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_muldiv_term(A) ::= md_unary_bitwise_op_term(B). {
|
|
A = B;
|
|
}
|
|
md_muldiv_term(A) ::= md_muldiv_term(B) MD_TOKEN_TIMES(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_muldiv_term(A) ::= md_muldiv_term(B) MD_TOKEN_DIVIDE(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_muldiv_term(A) ::= md_muldiv_term(B) MD_TOKEN_INT_DIVIDE(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
md_muldiv_term(A) ::= md_muldiv_term(B) MD_TOKEN_MOD(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_unary_bitwise_op_term(A) ::= md_pow_term(B). {
|
|
A = B;
|
|
}
|
|
md_unary_bitwise_op_term(A) ::= MD_TOKEN_PLUS(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_OPERATOR, C);
|
|
}
|
|
md_unary_bitwise_op_term(A) ::= MD_TOKEN_MINUS(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_OPERATOR, C);
|
|
}
|
|
md_unary_bitwise_op_term(A) ::= MD_TOKEN_LOGICAL_NOT(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_OPERATOR, C);
|
|
}
|
|
md_unary_bitwise_op_term(A) ::= MD_TOKEN_BITWISE_NOT(O) md_unary_bitwise_op_term(C). {
|
|
A = ex_ast_node_alloc_unary(O->text, MD_AST_NODE_TYPE_OPERATOR, C);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_pow_term(A) ::= md_atom_or_fcn(B). {
|
|
A = B;
|
|
}
|
|
md_pow_term(A) ::= md_atom_or_fcn(B) MD_TOKEN_POW(O) md_pow_term(C). {
|
|
A = ex_ast_node_alloc_binary(O->text, MD_AST_NODE_TYPE_OPERATOR, B, C);
|
|
}
|
|
|
|
|
|
// ----------------------------------------------------------------
|
|
// In the grammar provided to the user, field names are of the form "$x". But
|
|
// within Miller internally, field names are of the form "x". We coded the
|
|
// lexer to give us field names with leading "$" so we can confidently strip it
|
|
// off here.
|
|
|
|
md_atom_or_fcn(A) ::= md_field_name(B). {
|
|
A = B;
|
|
}
|
|
md_field_name(A) ::= MD_TOKEN_FIELD_NAME(B). {
|
|
char* dollar_name = B->text;
|
|
char* no_dollar_name = &dollar_name[1];
|
|
A = ex_ast_node_alloc(no_dollar_name, B->type);
|
|
}
|
|
md_field_name(A) ::= MD_TOKEN_BRACED_FIELD_NAME(B). {
|
|
// Replace "${field.name}" with just "field.name"
|
|
char* dollar_name = B->text;
|
|
char* no_dollar_name = &dollar_name[2];
|
|
int len = strlen(no_dollar_name);
|
|
if (len > 0)
|
|
no_dollar_name[len-1] = 0;
|
|
A = ex_ast_node_alloc(no_dollar_name, B->type);
|
|
}
|
|
|
|
md_atom_or_fcn(A) ::= md_indirect_field_name(B). {
|
|
A = B;
|
|
}
|
|
md_indirect_field_name(A) ::= MD_TOKEN_DOLLAR_SIGN MD_TOKEN_LEFT_BRACKET md_rhs(B) MD_TOKEN_RIGHT_BRACKET. {
|
|
A = ex_ast_node_alloc_unary("indirect_field_name", MD_AST_NODE_TYPE_INDIRECT_FIELD_NAME, B);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_atom_or_fcn(A) ::= md_oosvar_keylist(B). {
|
|
A = B;
|
|
}
|
|
md_oosvar_keylist(A) ::= md_oosvar_basename(B). {
|
|
A = B;
|
|
}
|
|
md_oosvar_keylist(A) ::= md_oosvar_keylist(B) MD_TOKEN_LEFT_BRACKET md_rhs(C) MD_TOKEN_RIGHT_BRACKET. {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|
|
|
|
// E.g. @name
|
|
md_oosvar_basename(A) ::= MD_TOKEN_UNBRACED_OOSVAR_NAME(B). {
|
|
char* at_name = B->text;
|
|
char* no_at_name = &at_name[1];
|
|
A = ex_ast_node_alloc_unary("oosvar_keylist", MD_AST_NODE_TYPE_OOSVAR_KEYLIST,
|
|
ex_ast_node_alloc(no_at_name, B->type));
|
|
}
|
|
|
|
// E.g. @{name}
|
|
md_oosvar_basename(A) ::= MD_TOKEN_BRACED_OOSVAR_NAME(B). {
|
|
// Replace "@%{field.name}" with just "field.name"
|
|
char* at_name = B->text;
|
|
char* no_at_name = &at_name[2];
|
|
int len = strlen(no_at_name);
|
|
if (len > 0)
|
|
no_at_name[len-1] = 0;
|
|
A = ex_ast_node_alloc_unary("oosvar_keylist", MD_AST_NODE_TYPE_OOSVAR_KEYLIST,
|
|
ex_ast_node_alloc(no_at_name, B->type));
|
|
}
|
|
|
|
// E.g. @["name"]
|
|
md_oosvar_basename(A) ::= MD_TOKEN_AT_SIGN MD_TOKEN_LEFT_BRACKET md_rhs(B) MD_TOKEN_RIGHT_BRACKET. {
|
|
A = ex_ast_node_alloc_unary("oosvar_keylist", MD_AST_NODE_TYPE_OOSVAR_KEYLIST, B);
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
md_atom_or_fcn(A) ::= MD_TOKEN_NUMBER(B). {
|
|
A = B;
|
|
}
|
|
md_atom_or_fcn(A) ::= MD_TOKEN_TRUE(B). {
|
|
A = B;
|
|
}
|
|
md_atom_or_fcn(A) ::= MD_TOKEN_FALSE(B). {
|
|
A = B;
|
|
}
|
|
|
|
md_atom_or_fcn(A) ::= md_string(B). {
|
|
A = B;
|
|
}
|
|
md_atom_or_fcn(A) ::= md_regexi(B). {
|
|
A = B;
|
|
}
|
|
|
|
md_atom_or_fcn(A) ::= md_local_variable(B). {
|
|
A = B;
|
|
}
|
|
md_local_variable(A) ::= MD_TOKEN_NON_SIGIL_NAME(B). {
|
|
A = ex_ast_node_alloc(B->text, MD_AST_NODE_TYPE_NONINDEXED_LOCAL_VARIABLE);
|
|
}
|
|
|
|
md_string(A) ::= MD_TOKEN_STRING(B). {
|
|
char* input = B->text;
|
|
char* stripped = &input[1];
|
|
int len = strlen(input);
|
|
stripped[len-2] = 0;
|
|
A = ex_ast_node_alloc(mlr_alloc_unbackslash(stripped), B->type);
|
|
}
|
|
md_regexi(A) ::= MD_TOKEN_REGEXI(B). {
|
|
char* input = B->text;
|
|
char* stripped = &input[1];
|
|
int len = strlen(input);
|
|
stripped[len-3] = 0;
|
|
A = ex_ast_node_alloc(mlr_alloc_unbackslash(stripped), B->type);
|
|
}
|
|
|
|
md_atom_or_fcn(A) ::= MD_TOKEN_CONTEXT_VARIABLE(B). {
|
|
A = B;
|
|
}
|
|
md_atom_or_fcn(A) ::= MD_TOKEN_ENV(B) MD_TOKEN_LEFT_BRACKET md_rhs(C) MD_TOKEN_RIGHT_BRACKET. {
|
|
A = ex_ast_node_alloc_binary("env", MD_AST_NODE_TYPE_ENV, B, C);
|
|
}
|
|
|
|
md_atom_or_fcn(A) ::= MD_TOKEN_LPAREN md_rhs(B) MD_TOKEN_RPAREN. {
|
|
A = B;
|
|
}
|
|
|
|
// Given "f(a,b,c)": since this is a bottom-up parser, we get first the "a",
|
|
// then "a,b", then "a,b,c", then finally "f(a,b,c)". So:
|
|
// * On the "a" we make a function sub-AST called "anon(a)".
|
|
// * On the "b" we append the next argument to get "anon(a,b)".
|
|
// * On the "c" we append the next argument to get "anon(a,b,c)".
|
|
// * On the "f" we change the function name to get "f(a,b,c)".
|
|
|
|
md_atom_or_fcn(A) ::= MD_TOKEN_NON_SIGIL_NAME(O) MD_TOKEN_LPAREN md_fcn_args(B) MD_TOKEN_RPAREN. {
|
|
A = ex_ast_node_set_function_name(B, O->text);
|
|
}
|
|
// Need to invalidate "f(10,)" -- use some non-empty-args expr.
|
|
md_fcn_args(A) ::= . {
|
|
A = ex_ast_node_alloc_zary("anon", MD_AST_NODE_TYPE_NON_SIGIL_NAME);
|
|
}
|
|
md_fcn_args(A) ::= md_rhs(B). {
|
|
A = ex_ast_node_alloc_unary("anon", MD_AST_NODE_TYPE_NON_SIGIL_NAME, B);
|
|
}
|
|
md_fcn_args(A) ::= md_fcn_args(B) MD_TOKEN_COMMA md_rhs(C). {
|
|
A = ex_ast_node_append_arg(B, C);
|
|
}
|