diff --git a/bin/build_examples.sh b/bin/build_examples.sh index 414f54a..2bd4f5a 100755 --- a/bin/build_examples.sh +++ b/bin/build_examples.sh @@ -12,6 +12,7 @@ bin/bld_core.sh show_ctx examps="examples" bin/bld_core.sh unit expr_intro $examps/expr/expr_intro.c +bin/bld_core.sh unit expr_c_like $examps/expr/expr_c_like.c exit diff --git a/bin/run_examples.sh b/bin/run_examples.sh index 8756617..c507880 100755 --- a/bin/run_examples.sh +++ b/bin/run_examples.sh @@ -12,6 +12,10 @@ echo ~~~ Running Expression Intro ~~~ $build_path/expr_intro.exe $examps/expr/expr_intro.mdesk echo +echo ~~~ Running C Like Expression ~~~ +$build_path/expr_c_like.exe $examps/expr/expr_c_like.mdesk +echo + exit echo ~~~ Running Type Metadata Generator Example ~~~ diff --git a/examples/expr/expr_c_like.c b/examples/expr/expr_c_like.c new file mode 100644 index 0000000..44bcd1a --- /dev/null +++ b/examples/expr/expr_c_like.c @@ -0,0 +1,259 @@ +/* +** Example: c like expressions +** +** TODO +** +*/ + +//~ includes and globals ////////////////////////////////////////////////////// + +#include "md.h" +#include "md.c" + +static MD_Arena *arena = 0; + +//~ expression setup and helpers ////////////////////////////////////////////// + +#define C_LIKE_OPS_NO_SIDE_EFFECTS(X) \ +X(ArraySubscript, "[]", Postfix, 18) \ +X(Member, ".", Binary, 18) \ +X(PointerMember, "->", Binary, 18) \ +X(UnaryPlus, "+", Prefix, 17) \ +X(UnaryMinus, "-", Prefix, 17) \ +X(LogicalNot, "!", Prefix, 17) \ +X(BitwiseNot, "~", Prefix, 17) \ +X(Dereference, "*", Prefix, 17) \ +X(AddressOf, "&", Prefix, 17) \ +X(SizeOf, "sizeof", Prefix, 17) \ +X(Multiplication, "*", Binary, 15) \ +X(Division, "/", Binary, 15) \ +X(Modulo, "%", Binary, 15) \ +X(Addition, "+", Binary, 14) \ +X(Subtraction, "-", Binary, 14) \ +X(LeftShift, "<<", Binary, 13) \ +X(RightShift, ">>", Binary, 13) \ +X(LessThan, "<", Binary, 11) \ +X(LessThanOrEqual, "<=", Binary, 11) \ +X(GreaterThan, ">", Binary, 11) \ +X(GreaterThanOrEqual, ">=", Binary, 11) \ +X(Equal, "==", Binary, 10) \ +X(NotEqual, "!=", Binary, 10) \ +X(BitwiseAnd, "&", Binary, 9) \ +X(BitwiseXor, "^", Binary, 8) \ +X(BitwiseOr, "|", Binary, 7) \ +X(LogicalAnd, "&&", Binary, 6) \ +X(LogicalOr, "||", Binary, 5) + +#define C_LIKE_OPS_CALLS(X) \ +X(Call, "()", Postfix, 18) + +#define C_LIKE_OPS_WITH_SIDE_EFFECTS(X) \ +X(PostFixIncrement, "++", Postfix, 18) \ +X(PostFixDecrement, "--", Postfix, 18) \ +X(PreFixIncrement, "++", Prefix, 17) \ +X(PreFixDecrement, "--", Prefix, 17) \ +X(Assign, "=", BinaryRightAssociative, 3) \ +X(AssignAddition, "+=", BinaryRightAssociative, 3) \ +X(AssignSubtraction, "-=", BinaryRightAssociative, 3) \ +X(AssignMultiplication,"*=", BinaryRightAssociative, 3) \ +X(AssignDivision, "/=", BinaryRightAssociative, 3) \ +X(AssignModulo, "%=", BinaryRightAssociative, 3) \ +X(AssignLeftShift, "<<=", BinaryRightAssociative, 3) \ +X(AssignRightShift, ">>=", BinaryRightAssociative, 3) \ +X(AssignBitwiseAnd, "&=", BinaryRightAssociative, 3) \ +X(AssignBitwiseXor, "^=", BinaryRightAssociative, 3) \ +X(AssignBitwiseOr, "|=", BinaryRightAssociative, 3) + +enum Op +{ +#define DEF_ENUM(e,t,k,p) Op##e, + C_LIKE_OPS_NO_SIDE_EFFECTS(DEF_ENUM) + C_LIKE_OPS_CALLS(DEF_ENUM) + C_LIKE_OPS_WITH_SIDE_EFFECTS(DEF_ENUM) +#undef DEF_ENUM +}; + +void +print_expression(FILE *out, MD_Expr *expr) +{ + MD_ExprOpr *op = expr->op; + if (op == 0) + { + MD_Node *node = expr->md_node; + if (node->raw_string.size != 0) + { + fprintf(out, "%.*s", MD_S8VArg(node->raw_string)); + } + else if (!MD_NodeIsNil(node->first_child)) + { + char c1 = 0; + char c2 = 0; + if (node->flags & MD_NodeFlag_HasParenLeft) + { + c1 = '('; + } + if (node->flags & MD_NodeFlag_HasBraceLeft) + { + c1 = '{'; + } + if (node->flags & MD_NodeFlag_HasBracketLeft) + { + c1 = '['; + } + if (node->flags & MD_NodeFlag_HasParenRight) + { + c2 = ')'; + } + if (node->flags & MD_NodeFlag_HasBraceRight) + { + c2 = '}'; + } + if (node->flags & MD_NodeFlag_HasBracketRight) + { + c2 = ']'; + } + fprintf(out, "%c...%c", c1, c2); + } + else + { + MD_CodeLoc loc = MD_CodeLocFromNode(node); + MD_PrintMessage(stderr, loc, MD_MessageKind_Error, + MD_S8Lit("the expression system does not expect this kind of node")); + } + } + else + { + switch (op->kind) + { + default: + { + MD_Node *node = expr->md_node; + MD_CodeLoc loc = MD_CodeLocFromNode(node); + MD_PrintMessage(stderr, loc, MD_MessageKind_FatalError, + MD_S8Lit("this is an unknown kind of operator")); + }break; + + case MD_ExprOprKind_Prefix: + { + fprintf(out, "%.*s", MD_S8VArg(op->string)); + print_expression(out, expr->unary_operand); + }break; + + case MD_ExprOprKind_Postfix: + { + 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) + { + fprintf(out, "%c...%c", op_string.str[0], op_string.str[1]); + } + else + { + fprintf(out, "%.*s", MD_S8VArg(op_string)); + } + }break; + + case MD_ExprOprKind_Binary: + case MD_ExprOprKind_BinaryRightAssociative: + { + fprintf(out, "("); + print_expression(out, expr->left); + fprintf(out, " %.*s ", MD_S8VArg(op->string)); + print_expression(out, expr->right); + fprintf(out, ")"); + }break; + } + } +} + + +//~ main ////////////////////////////////////////////////////////////////////// + +int main(int argc, char **argv) +{ +#if 1 + char *argv_dummy[2] = { + 0, + "W:\\metadesk\\examples\\expr\\expr_c_like.mdesk", + }; + argc = 2; + argv = argv_dummy; +#endif + + // setup the global arena + arena = MD_ArenaAlloc(); + + // parse all files passed to the command line + MD_Node *list = MD_MakeList(arena); + for (int i = 1; i < argc; i += 1) + { + + // parse the file + MD_String8 file_name = MD_S8CString(argv[i]); + MD_ParseResult parse_result = MD_ParseWholeFile(arena, file_name); + + // print metadesk errors + for (MD_Message *message = parse_result.errors.first; + message != 0; + message = message->next) + { + MD_CodeLoc code_loc = MD_CodeLocFromNode(message->node); + MD_PrintMessage(stdout, code_loc, message->kind, message->string); + } + + // save to parse results list + if (parse_result.errors.max_message_kind < MD_MessageKind_Error) + { + MD_PushNewReference(arena, list, parse_result.node); + } + } + + // setup the expression system + MD_ExprOprTable table = {0}; + { + MD_ExprOprList list = {0}; + +#define PUSH_OP(e,t,k,p) \ +MD_ExprOprPush(arena, &list, MD_ExprOprKind_##k, p, MD_S8Lit(t), Op##e, 0); + C_LIKE_OPS_NO_SIDE_EFFECTS(PUSH_OP); + C_LIKE_OPS_CALLS(PUSH_OP); + C_LIKE_OPS_WITH_SIDE_EFFECTS(PUSH_OP); +#undef PUSH_OP + + table = MD_ExprBakeOperatorTableFromList(arena, &list); + } + + // print the verbose parse results + for (MD_EachNode(root_it, list->first_child)) + { + MD_Node *root = MD_ResolveNodeFromReference(root_it); + for (MD_EachNode(node, root->first_child)) + { + MD_ExprParseResult parse = MD_ExprParse(arena, &table, node->first_child, MD_NilNode()); + + // print errors + for (MD_Message *message = parse.errors.first; + message != 0; + message = message->next) + { + MD_CodeLoc code_loc = MD_CodeLocFromNode(message->node); + MD_PrintMessage(stdout, code_loc, message->kind, message->string); + } + + // print the expression + if (parse.expr != 0) + { + if (node->string.size != 0) + { + fprintf(stdout, "%.*s = ", MD_S8VArg(node->string)); + } + print_expression(stdout, parse.expr); + fprintf(stdout, ";\n"); + } + } + } + + return 0; +} diff --git a/examples/expr/expr_c_like.mdesk b/examples/expr/expr_c_like.mdesk new file mode 100644 index 0000000..00906d3 --- /dev/null +++ b/examples/expr/expr_c_like.mdesk @@ -0,0 +1,18 @@ +/* +** Example: c like expressions +** +** TODO +*/ + +a: 100; +b: ( array[a] ); +c: sizeof xyz; +d: i*stride + j; +e: 2.71828; +f: ( (H << 16) | (H >> 16) ); +g: ( {0, +1, -1} ); +h: foo.bar; +(i += 1); +(j = 0); +(k = i*stride + j); +l: ( foo(bar, array[k], sizeof c) ); diff --git a/examples/expr/expr_intro.c b/examples/expr/expr_intro.c index 66966e7..a214c1c 100644 --- a/examples/expr/expr_intro.c +++ b/examples/expr/expr_intro.c @@ -111,7 +111,10 @@ int main(int argc, char **argv) } // print the expression - fprintf(stdout, "%.*s = ", MD_S8VArg(node->string)); + if (node->string.size != 0) + { + fprintf(stdout, "%.*s = ", MD_S8VArg(node->string)); + } print_expression(stdout, parse.expr); fprintf(stdout, ";\n"); } diff --git a/examples/expr/expr_intro.mdesk b/examples/expr/expr_intro.mdesk index 90cc1fc..8bebe5f 100644 --- a/examples/expr/expr_intro.mdesk +++ b/examples/expr/expr_intro.mdesk @@ -9,6 +9,6 @@ b: 2; c: 3; w: 100; -x: a*w + b; -y: b*w + c; -z: c*w + a; +x: a; +y: b + w*a; +z: (c + w*(b + w*a)); diff --git a/source/md.h b/source/md.h index 28cff5e..7045ba6 100644 --- a/source/md.h +++ b/source/md.h @@ -790,7 +790,11 @@ typedef struct MD_Expr MD_Expr; struct MD_Expr { struct MD_Expr *parent; - struct MD_Expr *left; + union + { + struct MD_Expr *left; + struct MD_Expr *unary_operand; + }; struct MD_Expr *right; MD_ExprOpr *op; MD_Node *md_node; diff --git a/tests/expression_tests.c b/tests/expression_tests.c index 9de772c..b20bda2 100644 --- a/tests/expression_tests.c +++ b/tests/expression_tests.c @@ -62,26 +62,22 @@ X(BitwiseXor, "^", Binary, 8) \ X(BitwiseOr, "|", Binary, 7) \ X(LogicalAnd, "&&", Binary, 6) \ X(LogicalOr, "||", Binary, 5) \ -X(Assign, "=", BinaryRightAssociative, 4) \ -X(AssignAddition, "+=", BinaryRightAssociative, 4) \ -X(AssignSubtraction, "-=", BinaryRightAssociative, 4) \ -X(AssignMultiplication,"*=", BinaryRightAssociative, 4) \ -X(AssignDivision, "/=", BinaryRightAssociative, 4) \ -X(AssignModulo, "%=", BinaryRightAssociative, 4) \ -X(AssignLeftShift, "<<=", BinaryRightAssociative, 4) \ -X(AssignRightShift, ">>=", BinaryRightAssociative, 4) \ -X(AssignBitwiseAnd, "&=", BinaryRightAssociative, 4) \ -X(AssignBitwiseXor, "^=", BinaryRightAssociative, 4) \ -X(AssignBitwiseOr, "|=", BinaryRightAssociative, 4) \ +X(Assign, "=", BinaryRightAssociative, 3) \ +X(AssignAddition, "+=", BinaryRightAssociative, 3) \ +X(AssignSubtraction, "-=", BinaryRightAssociative, 3) \ +X(AssignMultiplication,"*=", BinaryRightAssociative, 3) \ +X(AssignDivision, "/=", BinaryRightAssociative, 3) \ +X(AssignModulo, "%=", BinaryRightAssociative, 3) \ +X(AssignLeftShift, "<<=", BinaryRightAssociative, 3) \ +X(AssignRightShift, ">>=", BinaryRightAssociative, 3) \ +X(AssignBitwiseAnd, "&=", BinaryRightAssociative, 3) \ +X(AssignBitwiseXor, "^=", BinaryRightAssociative, 3) \ +X(AssignBitwiseOr, "|=", BinaryRightAssociative, 3) \ /* NOTE(mal): These are not in C */ \ X(PostfixBraceBrace, "{}", Postfix, 18) \ X(PostfixBracketParen, "[)", Postfix, 18) \ X(PostfixParenBracket, "(]", Postfix, 18) \ -// TODO(allen): I don't think we want to do this -// X(Cast "()", Prefix, 17) -// X(Comma, ",", Binary, 3) - #define X(name, token, kind, prec) Op_##name, typedef enum{ Op_Null,