diff --git a/examples/expr/expr_c_like.c b/examples/expr/expr_c_like.c index 44bcd1a..36713e6 100644 --- a/examples/expr/expr_c_like.c +++ b/examples/expr/expr_c_like.c @@ -1,7 +1,11 @@ /* ** Example: c like expressions ** -** TODO +** This example has the setup for parsing C expressions with the Metadesk +** expression parser. +** +** In the accompanying expr_c_like.mdesk there are more comments about using +** the expression system from the side of the Metadesk files. ** */ @@ -135,23 +139,24 @@ print_expression(FILE *out, MD_Expr *expr) case MD_ExprOprKind_Prefix: { - fprintf(out, "%.*s", MD_S8VArg(op->string)); + MD_Node *node = expr->md_node; + fprintf(out, "%.*s(", MD_S8VArg(op->string)); print_expression(out, expr->unary_operand); + fprintf(out, ")"); }break; case MD_ExprOprKind_Postfix: { + fprintf(out, "("); print_expression(out, expr->unary_operand); MD_String8 op_string = op->string; - // TODO(allen): formalize 'set delimiter mask' into the library - MD_u64 set_delimiter_mask = 0x3F; - if ((expr->md_node->flags & set_delimiter_mask) != 0) + if ((expr->md_node->flags & MD_NodeFlag_MaskSetDelimiters) != 0) { - fprintf(out, "%c...%c", op_string.str[0], op_string.str[1]); + fprintf(out, ")%c...%c", op_string.str[0], op_string.str[1]); } else { - fprintf(out, "%.*s", MD_S8VArg(op_string)); + fprintf(out, ")%.*s", MD_S8VArg(op_string)); } }break; diff --git a/examples/expr/expr_c_like.mdesk b/examples/expr/expr_c_like.mdesk index 00906d3..4f9dfe6 100644 --- a/examples/expr/expr_c_like.mdesk +++ b/examples/expr/expr_c_like.mdesk @@ -1,18 +1,72 @@ /* ** Example: c like expressions ** -** TODO +** Input for the expression parser in expr_c_like.c +** +** Many of the expressions in this example have to be expressed in slightly +** unusual ways (from the perspective of C) to make them work in the Metadesk +** grammar before the expression parser deals with them. Each of those cases in +** this file have comments explaining it. - The rule of thumb is that sometimes +** an expression needs to be placed in parentheses if it gets complicated. +** +** It may be useful to review intro/sets.mdesk to understand some the cases. */ a: 100; + +// @notes If we just have `b: array[a];` here the Metadesk parser will emit a +// warning and the tree won't have the shape we actually intend. We want: +// b: (array [a]) +// But we would actually get +// b: array +// [a] +// This happens because `b` is an "implicitly delimited" set, which _CANNOT_ +// contain explicitly delimited sets like `[a]` +// Adding the parentheses makes this into an "explicitly delimited" set which +// _CAN_ contain `[a]`. b: ( array[a] ); + + c: sizeof xyz; d: i*stride + j; e: 2.71828; + +// @notes The Metadesk expression parser uses parentheses like any common +// expression parser, but we have to remember that before the expression +// parser sees those parentheses, they actually get handled by the main +// Metadesk parser and turned into set nodes. +// +// If we just have `f: (H << 16) | (H >> 16);` here, then the tree we would +// get from the Metadesk parser is: +// f: (H << 16) +// | +// (H >> 16) +// +// Again the solution is to use an extra set of parentheses to tell the +// Metadesk parser that `(H << 16) | (H >> 16)` are all children of `f`. f: ( (H << 16) | (H >> 16) ); + +// @notes This time the problem is that we want the set delimiters `{}` to be +// visible to the expression parser. If we just have `g: {0, +1, -1}` then +// the shape of the tree becomes: +// g: (0, + 1, - 1) +// +// If we want to treat `{...}` as a leaf in an expression in this case we +// need an extra set of parentheses so that `{...}` is a child of g and not +// just the delimiters of the g node itself. g: ( {0, +1, -1} ); h: foo.bar; + +// @notes In these cases we want a nameless node that just contains an +// expression. We need parentheses so that these form sets. An alternative in +// this case is to have the C code do more work to use the `;` separators to +// find the beginning and ending of expressions like these. What we have here +// keeps things very simple. (i += 1); (j = 0); (k = i*stride + j); + +// @notes This one is pretty much the same as the first one, postfix index and +// postfix call operators both introduce an explicitly delimited set, which +// can't be contained in an implicitly delimited set. l: ( foo(bar, array[k], sizeof c) );