Skip to content

Instantly share code, notes, and snippets.

@UplinkCoder
Created June 6, 2023 16:14
Show Gist options
  • Save UplinkCoder/b3f13ab7db404090ae23871e63e8735a to your computer and use it in GitHub Desktop.
Save UplinkCoder/b3f13ab7db404090ae23871e63e8735a to your computer and use it in GitHub Desktop.
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