📄 parser.cpp
字号:
AddICodeJumpTarget ( g_iCurrScope, iStartTargetIndex );
// Read the opening parenthesis
ReadToken ( TOKEN_TYPE_DELIM_OPEN_PAREN );
// Parse the expression and leave the result on the stack
ParseExpr ();
// Read the closing parenthesis
ReadToken ( TOKEN_TYPE_DELIM_CLOSE_PAREN );
// Pop the result into _T0 and jump out of the loop if it's nonzero
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JE );
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
AddIntICodeOp ( g_iCurrScope, iInstrIndex, 0 );
AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iEndTargetIndex );
// Create a new loop instance structure
Loop * pLoop = ( Loop * ) malloc ( sizeof ( Loop ) );
// Set the starting and ending jump target indices
pLoop->iStartTargetIndex = iStartTargetIndex;
pLoop->iEndTargetIndex = iEndTargetIndex;
// Push the loop structure onto the stack
Push ( & g_LoopStack, pLoop );
// Parse the loop body
ParseStatement ();
// Pop the loop instance off the stack
Pop ( & g_LoopStack );
// Unconditionally jump back to the start of the loop
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JMP );
AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iStartTargetIndex );
// Set a jump target for the end of the loop
AddICodeJumpTarget ( g_iCurrScope, iEndTargetIndex );
}
/******************************************************************************************
*
* ParseFor ()
*
* Parses a for loop block.
*
* for ( <Initializer>; <Condition>; <Perpetuator> ) <Statement>
*/
void ParseFor ()
{
if ( g_iCurrScope == SCOPE_GLOBAL )
ExitOnCodeError ( "for illegal in global scope" );
// Annotate the line
AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );
/*
A for loop parser implementation could go here
*/
}
/******************************************************************************************
*
* ParseBreak ()
*
* Parses a break statement.
*/
void ParseBreak ()
{
// Make sure we're in a loop
if ( IsStackEmpty ( & g_LoopStack ) )
ExitOnCodeError ( "break illegal outside loops" );
// Annotate the line
AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );
// Attempt to read the semicolon
ReadToken ( TOKEN_TYPE_DELIM_SEMICOLON );
// Get the jump target index for the end of the loop
int iTargetIndex = ( ( Loop * ) Peek ( & g_LoopStack ) )->iEndTargetIndex;
// Unconditionally jump to the end of the loop
int iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JMP );
AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iTargetIndex );
}
/******************************************************************************************
*
* ParseContinue ()
*
* Parses a continue statement.
*/
void ParseContinue ()
{
// Make sure we're inside a function
if ( IsStackEmpty ( & g_LoopStack ) )
ExitOnCodeError ( "continue illegal outside loops" );
// Annotate the line
AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );
// Attempt to read the semicolon
ReadToken ( TOKEN_TYPE_DELIM_SEMICOLON );
// Get the jump target index for the start of the loop
int iTargetIndex = ( ( Loop * ) Peek ( & g_LoopStack ) )->iStartTargetIndex;
// Unconditionally jump to the end of the loop
int iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_JMP );
AddJumpTargetICodeOp ( g_iCurrScope, iInstrIndex, iTargetIndex );
}
/******************************************************************************************
*
* ParseReturn ()
*
* Parses a return statement.
*
* return;
* return <expr>;
*/
void ParseReturn ()
{
int iInstrIndex;
// Make sure we're inside a function
if ( g_iCurrScope == SCOPE_GLOBAL )
ExitOnCodeError ( "return illegal in global scope" );
// Annotate the line
AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );
// If a semicolon doesn't appear to follow, parse the expression and place it in
// _RetVal
if ( GetLookAheadChar () != ';' )
{
// Parse the expression to calculate the return value and leave the result on the stack.
ParseExpr ();
// Determine which function we're returning from
if ( g_ScriptHeader.iIsMainFuncPresent &&
g_ScriptHeader.iMainFuncIndex == g_iCurrScope )
{
// It is _Main (), so pop the result into _T0
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
}
else
{
// It's not _Main, so pop the result into the _RetVal register
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
AddRegICodeOp ( g_iCurrScope, iInstrIndex, REG_CODE_RETVAL );
}
}
else
{
// Clear _T0 in case we're exiting _Main ()
if ( g_ScriptHeader.iIsMainFuncPresent &&
g_ScriptHeader.iMainFuncIndex == g_iCurrScope )
{
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MOV );
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
AddIntICodeOp ( g_iCurrScope, iInstrIndex, 0 );
}
}
if ( g_ScriptHeader.iIsMainFuncPresent &&
g_ScriptHeader.iMainFuncIndex == g_iCurrScope )
{
// It's _Main, so exit the script with _T0 as the exit code
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_EXIT );
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
}
else
{
// It's not _Main, so return from the function
AddICodeInstr ( g_iCurrScope, INSTR_RET );
}
}
/******************************************************************************************
*
* ParseAssign ()
*
* Parses an assignment statement.
*
* <Ident> <Assign-Op> <Expr>;
*/
void ParseAssign ()
{
// Make sure we're inside a function
if ( g_iCurrScope == SCOPE_GLOBAL )
ExitOnCodeError ( "Assignment illegal in global scope" );
int iInstrIndex;
// Assignment operator
int iAssignOp;
// Annotate the line
AddICodeSourceLine ( g_iCurrScope, GetCurrSourceLine () );
// ---- Parse the variable or array
SymbolNode * pSymbol = GetSymbolByIdent ( GetCurrLexeme (), g_iCurrScope );
// Does an array index follow the identifier?
int iIsArray = FALSE;
if ( GetLookAheadChar () == '[' )
{
// Ensure the variable is an array
if ( pSymbol->iSize == 1 )
ExitOnCodeError ( "Invalid array" );
// Verify the opening brace
ReadToken ( TOKEN_TYPE_DELIM_OPEN_BRACE );
// Make sure an expression is present
if ( GetLookAheadChar () == ']' )
ExitOnCodeError ( "Invalid expression" );
// Parse the index as an expression
ParseExpr ();
// Make sure the index is closed
ReadToken ( TOKEN_TYPE_DELIM_CLOSE_BRACE );
// Set the array flag
iIsArray = TRUE;
}
else
{
// Make sure the variable isn't an array
if ( pSymbol->iSize > 1 )
ExitOnCodeError ( "Arrays must be indexed" );
}
// ---- Parse the assignment operator
if ( GetNextToken () != TOKEN_TYPE_OP &&
( GetCurrOp () != OP_TYPE_ASSIGN &&
GetCurrOp () != OP_TYPE_ASSIGN_ADD &&
GetCurrOp () != OP_TYPE_ASSIGN_SUB &&
GetCurrOp () != OP_TYPE_ASSIGN_MUL &&
GetCurrOp () != OP_TYPE_ASSIGN_DIV &&
GetCurrOp () != OP_TYPE_ASSIGN_MOD &&
GetCurrOp () != OP_TYPE_ASSIGN_EXP &&
GetCurrOp () != OP_TYPE_ASSIGN_CONCAT &&
GetCurrOp () != OP_TYPE_ASSIGN_AND &&
GetCurrOp () != OP_TYPE_ASSIGN_OR &&
GetCurrOp () != OP_TYPE_ASSIGN_XOR &&
GetCurrOp () != OP_TYPE_ASSIGN_SHIFT_LEFT &&
GetCurrOp () != OP_TYPE_ASSIGN_SHIFT_RIGHT ) )
ExitOnCodeError ( "Illegal assignment operator" );
else
iAssignOp = GetCurrOp ();
// ---- Parse the value expression
ParseExpr ();
// Validate the presence of the semicolon
ReadToken ( TOKEN_TYPE_DELIM_SEMICOLON );
// Pop the value into _T0
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
// If the variable was an array, pop the top of the stack into _T1 for use as the index
if ( iIsArray )
{
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_POP );
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar1SymbolIndex );
}
// ---- Generate the I-code for the assignment instruction
switch ( iAssignOp )
{
// =
case OP_TYPE_ASSIGN:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MOV );
break;
// +=
case OP_TYPE_ASSIGN_ADD:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_ADD );
break;
// -=
case OP_TYPE_ASSIGN_SUB:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_SUB );
break;
// *=
case OP_TYPE_ASSIGN_MUL:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MUL );
break;
// /=
case OP_TYPE_ASSIGN_DIV:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_DIV );
break;
// %=
case OP_TYPE_ASSIGN_MOD:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_MOD );
break;
// ^=
case OP_TYPE_ASSIGN_EXP:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_EXP );
break;
// $=
case OP_TYPE_ASSIGN_CONCAT:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_CONCAT );
break;
// &=
case OP_TYPE_ASSIGN_AND:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_AND );
break;
// |=
case OP_TYPE_ASSIGN_OR:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_OR );
break;
// #=
case OP_TYPE_ASSIGN_XOR:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_XOR );
break;
// <<=
case OP_TYPE_ASSIGN_SHIFT_LEFT:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_SHL );
break;
// >>=
case OP_TYPE_ASSIGN_SHIFT_RIGHT:
iInstrIndex = AddICodeInstr ( g_iCurrScope, INSTR_SHR );
break;
}
// Generate the destination operand
if ( iIsArray )
AddArrayIndexVarICodeOp ( g_iCurrScope, iInstrIndex, pSymbol->iIndex, g_iTempVar1SymbolIndex );
else
AddVarICodeOp ( g_iCurrScope, iInstrIndex, pSymbol->iIndex );
// Generate the source
AddVarICodeOp ( g_iCurrScope, iInstrIndex, g_iTempVar0SymbolIndex );
}
/******************************************************************************************
*
* ParseFuncCall ()
*
* Parses a function call
*
* <Ident> ( <Expr>, <Expr> );
*/
void ParseFuncCall ()
{
// Get the function by it's identifier
FuncNode * pFunc = GetFuncByName ( GetCurrLexeme () );
// It is, so start the parameter count at zero
int iParamCount = 0;
// Attempt to read the opening parenthesis
ReadToken ( TOKEN_TYPE_DELIM_OPEN_PAREN );
// Parse each parameter and push it onto the stack
while ( TRUE )
{
// Find out if there's another parameter to push
if ( GetLookAheadChar () != ')' )
{
// There is, so parse it as an expression
ParseExpr ();
// Increment the parameter count and make sure it's not greater than the amount
// accepted by the function (unless it's a host API function
++ iParamCount;
if ( ! pFunc->iIsHostAPI && iParamCount > pFunc->iParamCount )
ExitOnCodeError ( "Too many parameters" );
// Unless this is the final parameter, attempt to read a comma
if ( GetLookAheadChar () != ')' )
ReadToken ( TOKEN_TYPE_DELIM_COMMA );
}
else
{
// There isn't, so break the loop and complete the call
break;
}
}
// Attempt to read the closing parenthesis
ReadToken ( TOKEN_TYPE_DELIM_CLOSE_PAREN );
// Make sure the parameter wasn't passed too few parameters (unless
// it's a host API function)
if ( ! pFunc->iIsHostAPI && iParamCount < pFunc->iParamCount )
ExitOnCodeError ( "Too few parameters" );
// Call the function, but make sure the right call instruction is used
int iCallInstr = INSTR_CALL;
if ( pFunc->iIsHostAPI )
iCallInstr = INSTR_CALLHOST;
int iInstrIndex = AddICodeInstr ( g_iCurrScope, iCallInstr );
AddFuncICodeOp ( g_iCurrScope, iInstrIndex, pFunc->iIndex );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -