From dc502042d58ccfb3ad05d68c865a9079fe9015ec Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Dec 2017 11:52:52 -0500 Subject: [PATCH] translate-c: refactor prefix and suffix op C macro parsing --- src/c_tokenizer.cpp | 15 +++++++ src/c_tokenizer.hpp | 3 ++ src/translate_c.cpp | 98 +++++++++++++++++++++++++++++++-------------- 3 files changed, 87 insertions(+), 29 deletions(-) diff --git a/src/c_tokenizer.cpp b/src/c_tokenizer.cpp index 6be2cf991e..3746cf5853 100644 --- a/src/c_tokenizer.cpp +++ b/src/c_tokenizer.cpp @@ -121,6 +121,9 @@ static void begin_token(CTokenize *ctok, CTokId id) { case CTokIdRParen: case CTokIdEOF: case CTokIdDot: + case CTokIdAsterisk: + case CTokIdBang: + case CTokIdTilde: break; } } @@ -228,10 +231,22 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { begin_token(ctok, CTokIdRParen); end_token(ctok); break; + case '*': + begin_token(ctok, CTokIdAsterisk); + end_token(ctok); + break; case '-': begin_token(ctok, CTokIdMinus); end_token(ctok); break; + case '!': + begin_token(ctok, CTokIdBang); + end_token(ctok); + break; + case '~': + begin_token(ctok, CTokIdTilde); + end_token(ctok); + break; default: return mark_error(ctok); } diff --git a/src/c_tokenizer.hpp b/src/c_tokenizer.hpp index a3df2b94af..d7c9e53bcf 100644 --- a/src/c_tokenizer.hpp +++ b/src/c_tokenizer.hpp @@ -22,6 +22,9 @@ enum CTokId { CTokIdRParen, CTokIdEOF, CTokIdDot, + CTokIdAsterisk, + CTokIdBang, + CTokIdTilde, }; enum CNumLitSuffix { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 5082c37a61..9e73c08b84 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4000,6 +4000,10 @@ static void render_macros(Context *c) { } } +static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i); +static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i); +static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i); + static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { CTok *tok = &ctok->tokens.at(*tok_i); if (tok->id == CTokIdNumLitInt) { @@ -4027,7 +4031,7 @@ static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, b return nullptr; } -static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { +static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i) { CTok *tok = &ctok->tokens.at(*tok_i); switch (tok->id) { case CTokIdCharLit: @@ -4044,38 +4048,17 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { return parse_ctok_num_lit(c, ctok, tok_i, false); case CTokIdSymbol: { - bool need_symbol = false; - CTokId curr_id = CTokIdSymbol; + *tok_i += 1; Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); - AstNode *curr_node = trans_create_node_symbol(c, symbol_name); - AstNode *parent_node = curr_node; - do { - *tok_i += 1; - CTok* curr_tok = &ctok->tokens.at(*tok_i); - if (need_symbol) { - if (curr_tok->id == CTokIdSymbol) { - symbol_name = buf_create_from_buf(&curr_tok->data.symbol); - curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name)); - parent_node = curr_node; - need_symbol = false; - } else { - return nullptr; - } - } else { - if (curr_tok->id == CTokIdDot) { - need_symbol = true; - continue; - } else { - break; - } - } - } while (curr_id != CTokIdEOF); - return curr_node; + return trans_create_node_symbol(c, symbol_name); } case CTokIdLParen: { *tok_i += 1; - AstNode *inner_node = parse_ctok(c, ctok, tok_i); + AstNode *inner_node = parse_ctok_expr(c, ctok, tok_i); + if (inner_node == nullptr) { + return nullptr; + } CTok *next_tok = &ctok->tokens.at(*tok_i); if (next_tok->id != CTokIdRParen) { @@ -4087,12 +4070,69 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { case CTokIdDot: case CTokIdEOF: case CTokIdRParen: + case CTokIdAsterisk: + case CTokIdBang: + case CTokIdTilde: // not able to make sense of this return nullptr; } zig_unreachable(); } +static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i) { + return parse_ctok_prefix_op_expr(c, ctok, tok_i); +} + +static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { + AstNode *node = parse_ctok_primary_expr(c, ctok, tok_i); + if (node == nullptr) + return nullptr; + + while (true) { + CTok *first_tok = &ctok->tokens.at(*tok_i); + if (first_tok->id == CTokIdDot) { + *tok_i += 1; + + CTok *name_tok = &ctok->tokens.at(*tok_i); + if (name_tok->id != CTokIdSymbol) { + return nullptr; + } + *tok_i += 1; + + node = trans_create_node_field_access(c, node, buf_create_from_buf(&name_tok->data.symbol)); + } else if (first_tok->id == CTokIdAsterisk) { + *tok_i += 1; + + node = trans_create_node_addr_of(c, false, false, node); + } else { + return node; + } + } +} + +static PrefixOp ctok_to_prefix_op(CTok *token) { + switch (token->id) { + case CTokIdBang: return PrefixOpBoolNot; + case CTokIdMinus: return PrefixOpNegation; + case CTokIdTilde: return PrefixOpBinNot; + case CTokIdAsterisk: return PrefixOpDereference; + default: return PrefixOpInvalid; + } +} +static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { + CTok *op_tok = &ctok->tokens.at(*tok_i); + PrefixOp prefix_op = ctok_to_prefix_op(op_tok); + if (prefix_op == PrefixOpInvalid) { + return parse_ctok_suffix_op_expr(c, ctok, tok_i); + } + *tok_i += 1; + + AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i); + if (prefix_op_expr == nullptr) + return nullptr; + return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr); +} + static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { tokenize_c_macro(ctok, (const uint8_t *)char_ptr); @@ -4105,7 +4145,7 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); tok_i += 1; - AstNode *result_node = parse_ctok(c, ctok, &tok_i); + AstNode *result_node = parse_ctok_suffix_op_expr(c, ctok, &tok_i); if (result_node == nullptr) { return; }