Created
June 6, 2023 16:14
-
-
Save UplinkCoder/b3f13ab7db404090ae23871e63e8735a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
metac_expr_t* MetaCParser_ParseExpr2(metac_parser_t* self, parse_expr_flags_t flags) | |
{ | |
metac_expr_t* result = NULL; | |
metac_token_t* currentToken = NULL; | |
metac_token_enum_t tokenType = tok_invalid; | |
metac_expr_kind_t leftOp = expr_invalid; | |
metac_expr_kind_t op = expr_invalid; | |
uint32_t prec = 0; | |
uint32_t opPrec = 0; | |
parse_expr_flags_t eflags = flags; | |
metac_location_t loc = {0}; | |
MetaCParser_PushExprStackBottom(self, self->ExprParser.ExprStackCount); | |
MetaCParser_PushOpStackBottom(self, self->ExprParser.OpStackCount); | |
MetaCParser_PushOpenParens(self); | |
MetaCParser_PushFlags(self, flags); | |
currentToken = MetaCParser_PeekToken(self, 1); | |
if (currentToken && currentToken->TokenType == tok_dot) | |
{ | |
MetaCParser_Match(self, tok_dot); | |
result = ParseUnaryDotExpr(self); | |
MetaCParser_PushExpr(self, result); | |
} | |
for (;;) | |
{ | |
assert(self->ExprParser.OpStackCount < 20); | |
assert(self->ExprParser.ExprStackCount < 2000); | |
currentToken = MetaCParser_PeekToken(self, 1); | |
if (currentToken) | |
loc = LocationFromToken(self, currentToken); | |
tokenType = currentToken ? currentToken->TokenType : tok_invalid; | |
// TODO: nested ternary expressions | |
if (eflags & expr_flags_ternary) | |
{ | |
if (tokenType == tok_colon) | |
{ | |
MetaCParser_Match(self, tok_colon); | |
U32(eflags) &= (~expr_flags_ternary); | |
continue; | |
} | |
} | |
if (IsPrimaryExprToken(tokenType)) | |
{ | |
if (tokenType == tok_lParen && ShouldParseAsCall(self, eflags)) | |
{ | |
goto LParseCall; | |
} | |
metac_expr_t* e = MetaCParser_ParsePrimaryExpr(self, expr_flags_none); | |
MetaCParser_PushExpr(self, e); | |
U32(eflags) &= ~expr_flags_binary; | |
op = e->Kind; | |
goto LParsePostfix; | |
} | |
else if (tokenType == tok_question) | |
{ | |
leftOp = MetaCParser_TopOp(self); | |
prec = (leftOp == expr_invalid) ? 0 : OpToPrecedence(leftOp); | |
MetaCParser_Match(self, tok_question); | |
op = expr_ternary; | |
U32(eflags) |= expr_flags_ternary; | |
opPrec = OpToPrecedence(op); | |
if (opPrec > prec) | |
{ | |
// We are pushing the operator below | |
// So there's nothing to do here | |
} | |
else | |
{ | |
MetaCParser_ApplyOpsUntil(self, op); | |
} | |
MetaCParser_PushOp(self, expr_ternary); | |
continue; | |
} | |
else if (MetaCParser_TopExpr(self) && IsBinaryOperator(tokenType, eflags)) | |
{ | |
goto LParseBinary; | |
} | |
else if ((op = UnaExpTypeFromTokenType(tokenType, 0)) != expr_invalid) | |
{ | |
leftOp = MetaCParser_TopOp(self); | |
prec = (leftOp != expr_invalid) ? OpToPrecedence(leftOp) : 0; | |
if (prec > 12) | |
{ | |
// In this case, we have a deref | |
MetaCParser_ApplyOpsUntil(self, expr_deref); | |
leftOp = expr_deref; | |
prec = 0; | |
} | |
MetaCParser_Match(self, tokenType); | |
op = op_get; | |
opPrec = OpToPrecedence(op); | |
if (opPrec > prec) | |
{ | |
// We are pushing the operator below | |
// So there's nothing to do here | |
} | |
else | |
{ | |
MetaCParser_ApplyOpsUntil(self, op); | |
} | |
MetaCParser_PushOp(self, op); | |
continue; | |
} | |
if (tokenType == tok_rParen && IsOnExprStack(self)) | |
{ | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
MetaCParser_Match(self, tok_rParen); | |
if (eflags & expr_flags_unary) | |
{ | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
} | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
eflags = MetaCParser_PopFlags(self); | |
continue; | |
} | |
else if (tokenType == tok_rParen && IsOnOpenParensStack(self)) | |
{ | |
MetaCParser_PopOpenParens(self); | |
MetaCParser_Match(self, tok_rParen); | |
eflags = MetaCParser_PopFlags(self); | |
continue; | |
} | |
else if (tokenType == tok_rParen && ShouldParseAsCall(self, eflags)) | |
{ | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
MetaCParser_Match(self, tok_rParen); | |
if (eflags & expr_flags_unary) | |
{ | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
} | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
eflags = MetaCParser_PopFlags(self); | |
continue; | |
} | |
if (tokenType == tok_invalid || tokenType == tok_eof) | |
{ | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
break; | |
} | |
// Unknown token type, report error | |
MetaCParser_ReportError(self, "Unexpected token", &loc); | |
break; | |
LParseBinary: | |
leftOp = MetaCParser_TopOp(self); | |
prec = OpToPrecedence(leftOp); | |
op = BinExpTypeFromTokenType(tokenType); | |
opPrec = OpToPrecedence(op); | |
if (opPrec > prec) | |
{ | |
// We are pushing the operator below | |
// So there's nothing to do here | |
} | |
else | |
{ | |
MetaCParser_ApplyOpsUntil(self, op); | |
} | |
MetaCParser_PushOp(self, op); | |
U32(eflags) |= expr_flags_binary; | |
continue; | |
LParsePostfix: | |
for (;;) | |
{ | |
currentToken = MetaCParser_PeekToken(self, 1); | |
tokenType = currentToken ? currentToken->TokenType : tok_invalid; | |
if (tokenType == tok_lBracket) | |
{ | |
MetaCParser_Match(self, tok_lBracket); | |
metac_expr_t* index = MetaCParser_ParseExpr(self, expr_flags_none); | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
MetaCParser_Match(self, tok_rBracket); | |
result = CreateArrayRefExpr(self, MetaCParser_PopExpr(self), index); | |
MetaCParser_PushExpr(self, result); | |
} | |
else if (tokenType == tok_lParen) | |
{ | |
goto LParseCall; | |
} | |
else if (tokenType == tok_dot || tokenType == tok_arrow) | |
{ | |
metac_expr_kind_t memberOp = (tokenType == tok_dot) ? expr_dot : expr_arrow; | |
MetaCParser_Match(self, tokenType); | |
metac_expr_t* member = ParseDotExpr(self, memberOp); | |
MetaCParser_PushExpr(self, member); | |
} | |
else | |
{ | |
break; | |
} | |
} | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
break; | |
LParseCall: | |
MetaCParser_Match(self, tok_lParen); | |
metac_expr_list_t* args = CreateExprList(self); | |
while (MetaCParser_PeekToken(self, 1)->TokenType != tok_rParen) | |
{ | |
metac_expr_t* arg = MetaCParser_ParseExpr(self, expr_flags_none); | |
AddExprToList(args, arg); | |
if (MetaCParser_PeekToken(self, 1)->TokenType == tok_comma) | |
{ | |
MetaCParser_Match(self, tok_comma); | |
} | |
} | |
MetaCParser_Match(self, tok_rParen); | |
MetaCParser_ApplyOpsUntil(self, expr_invalid); | |
result = CreateCallExpr(self, MetaCParser_PopExpr(self), args); | |
MetaCParser_PushExpr(self, result); | |
} | |
MetaCParser_PopExprStackBottom(self); | |
MetaCParser_PopOpStackBottom(self); | |
MetaCParser_PopOpenParensStackBottom(self); | |
return MetaCParser_PopExpr(self); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment