382 lines
7.8 KiB
C
382 lines
7.8 KiB
C
//
|
|
// Copyright (c) Microsoft Corporation 1995
|
|
//
|
|
// codegen.c
|
|
//
|
|
// This file contains the code-generating functions.
|
|
//
|
|
// The "code" is actually just an intermediate representation.
|
|
// Currently this is an array of ASTs.
|
|
//
|
|
// History:
|
|
// 06-18-95 ScottH Created
|
|
//
|
|
|
|
|
|
#include "proj.h"
|
|
#include "rcids.h"
|
|
|
|
RES PRIVATE Stmt_Codegen(PSTMT this, PASTEXEC pastexec, PSYMTAB pst);
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Generate code for the 'while' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE WhileStmt_Codegen(
|
|
PSTMT this,
|
|
PASTEXEC pastexec,
|
|
PSYMTAB pst)
|
|
{
|
|
RES res;
|
|
LPSTR pszTop;
|
|
LPSTR pszEnd;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pastexec);
|
|
ASSERT(AT_WHILE_STMT == Ast_GetType(this));
|
|
|
|
pszTop = WhileStmt_GetTopLabel(this);
|
|
pszEnd = WhileStmt_GetEndLabel(this);
|
|
|
|
res = Astexec_InsertLabel(pastexec, pszTop, pst);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// add the 'while' statement for the test expression
|
|
res = Astexec_Add(pastexec, this);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// add the statements in the statement block
|
|
DWORD i;
|
|
DWORD cstmts;
|
|
HPA hpaStmts = WhileStmt_GetStmtBlock(this);
|
|
|
|
res = RES_OK;
|
|
|
|
cstmts = PAGetCount(hpaStmts);
|
|
|
|
// Add each statement
|
|
for (i = 0; i < cstmts; i++)
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(hpaStmts, i);
|
|
|
|
res = Stmt_Codegen(pstmt, pastexec, pst);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// add the end label
|
|
res = Astexec_InsertLabel(pastexec, pszEnd, pst);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Generate code for the 'if' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE IfStmt_Codegen(
|
|
PSTMT this,
|
|
PASTEXEC pastexec,
|
|
PSYMTAB pst)
|
|
{
|
|
RES res;
|
|
LPSTR pszElse;
|
|
LPSTR pszEnd;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pastexec);
|
|
ASSERT(AT_IF_STMT == Ast_GetType(this));
|
|
|
|
pszElse = IfStmt_GetElseLabel(this);
|
|
pszEnd = IfStmt_GetEndLabel(this);
|
|
|
|
// add the 'if' statement for the test expression
|
|
res = Astexec_Add(pastexec, this);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// add the statements in the 'then' statement block
|
|
DWORD i;
|
|
DWORD cstmts;
|
|
HPA hpaStmts = IfStmt_GetStmtBlock(this);
|
|
|
|
res = RES_OK;
|
|
|
|
cstmts = PAGetCount(hpaStmts);
|
|
|
|
// Add each statement
|
|
for (i = 0; i < cstmts; i++)
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(hpaStmts, i);
|
|
|
|
res = Stmt_Codegen(pstmt, pastexec, pst);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// add the else label
|
|
res = Astexec_InsertLabel(pastexec, pszElse, pst);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Generate code for the label statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE LabelStmt_Codegen(
|
|
PSTMT this,
|
|
PASTEXEC pastexec,
|
|
PSYMTAB pst)
|
|
{
|
|
LPSTR pszIdent;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pastexec);
|
|
ASSERT(AT_LABEL_STMT == Ast_GetType(this));
|
|
|
|
pszIdent = LabelStmt_GetIdent(this);
|
|
|
|
return Astexec_InsertLabel(pastexec, pszIdent, pst);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Generate code for the 'set' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE SetStmt_Codegen(
|
|
PSTMT this,
|
|
PASTEXEC pastexec,
|
|
PSYMTAB pst)
|
|
{
|
|
RES res = RES_OK;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pastexec);
|
|
ASSERT(AT_SET_STMT == Ast_GetType(this));
|
|
|
|
switch (SetStmt_GetType(this))
|
|
{
|
|
case ST_IPADDR:
|
|
case ST_PORT:
|
|
case ST_SCREEN:
|
|
res = Astexec_Add(pastexec, this);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Generate code for a statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE Stmt_Codegen(
|
|
PSTMT this,
|
|
PASTEXEC pastexec,
|
|
PSYMTAB pst)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pastexec);
|
|
|
|
switch (Ast_GetType(this))
|
|
{
|
|
case AT_ENTER_STMT:
|
|
case AT_LEAVE_STMT:
|
|
case AT_HALT_STMT:
|
|
case AT_TRANSMIT_STMT:
|
|
case AT_WAITFOR_STMT:
|
|
case AT_DELAY_STMT:
|
|
case AT_GOTO_STMT:
|
|
case AT_ASSIGN_STMT:
|
|
res = Astexec_Add(pastexec, this);
|
|
break;
|
|
|
|
case AT_WHILE_STMT:
|
|
res = WhileStmt_Codegen(this, pastexec, pst);
|
|
break;
|
|
|
|
case AT_IF_STMT:
|
|
res = IfStmt_Codegen(this, pastexec, pst);
|
|
break;
|
|
|
|
case AT_SET_STMT:
|
|
res = SetStmt_Codegen(this, pastexec, pst);
|
|
break;
|
|
|
|
case AT_LABEL_STMT:
|
|
res = LabelStmt_Codegen(this, pastexec, pst);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Generate code for a procedure declaration.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE ProcDecl_Codegen(
|
|
PPROCDECL this,
|
|
PASTEXEC pastexec)
|
|
{
|
|
RES res = RES_OK;
|
|
DWORD i;
|
|
DWORD cstmts;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pastexec);
|
|
|
|
cstmts = PAGetCount(this->hpaStmts);
|
|
|
|
// Generate for each statement
|
|
for (i = 0; i < cstmts; i++)
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(this->hpaStmts, i);
|
|
|
|
res = Stmt_Codegen(pstmt, pastexec, this->pst);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Find the proc decl that has the given identifier.
|
|
|
|
Returns: TRUE (if found)
|
|
|
|
Cond: --
|
|
*/
|
|
BOOL PRIVATE FindProc(
|
|
PMODULEDECL pmd,
|
|
LPCSTR pszIdent,
|
|
PPROCDECL * ppprocdecl)
|
|
{
|
|
DWORD i;
|
|
DWORD cprocs = PAGetCount(pmd->hpaProcs);
|
|
|
|
*ppprocdecl = NULL;
|
|
|
|
for (i = 0; i < cprocs; i++)
|
|
{
|
|
PPROCDECL pprocdecl = PAFastGetPtr(pmd->hpaProcs, i);
|
|
|
|
if (IsSzEqualC(ProcDecl_GetIdent(pprocdecl), pszIdent))
|
|
{
|
|
*ppprocdecl = pprocdecl;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return NULL != *ppprocdecl;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Generate code for the module declaration.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC ModuleDecl_Codegen(
|
|
PMODULEDECL this,
|
|
PASTEXEC pastexec)
|
|
{
|
|
RES res = RES_OK;
|
|
DWORD i;
|
|
DWORD cprocs;
|
|
PPROCDECL ppdMain;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pastexec);
|
|
|
|
TRACE_MSG(TF_GENERAL, "Generating code...");
|
|
|
|
cprocs = PAGetCount(this->hpaProcs);
|
|
|
|
// Generate code for the main proc first.
|
|
if (FindProc(this, "main", &ppdMain))
|
|
{
|
|
res = ProcDecl_Codegen(ppdMain, pastexec);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// Generate code for the rest of the procs
|
|
for (i = 0; i < cprocs; i++)
|
|
{
|
|
PPROCDECL pprocdecl = PAFastGetPtr(this->hpaProcs, i);
|
|
|
|
if (pprocdecl != ppdMain)
|
|
{
|
|
res = ProcDecl_Codegen(pprocdecl, pastexec);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Typechecking should have guaranteed that the main
|
|
// proc was here
|
|
ASSERT(0);
|
|
res = RES_E_FAIL;
|
|
}
|
|
|
|
return res;
|
|
}
|