/* ** Example: c like expressions ** ** 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. ** */ //~ 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) { 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 & NodeFlag_HasParenLeft) { c1 = '('; } if (node->flags & NodeFlag_HasBraceLeft) { c1 = '{'; } if (node->flags & NodeFlag_HasBracketLeft) { c1 = '['; } if (node->flags & NodeFlag_HasParenRight) { c2 = ')'; } if (node->flags & NodeFlag_HasBraceRight) { c2 = '}'; } if (node->flags & 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: { 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: { 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; if ((expr->md_node->flags & NodeFlag_MaskSetDelimiters) != 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, "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 Node *list = MD_MakeList(arena); for (int i = 1; i < argc; i += 1) { // parse the file MD_String8 file_name = MD_S8CString(argv[i]); 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_ExprBakeOprTableFromList(arena, &list); } // print the verbose parse results for (each_node(root_it, list->first_child)) { Node *root = MD_ResolveNodeFromReference(root_it); for (each_node(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; }