378 lines
8.1 KiB
C++
378 lines
8.1 KiB
C++
|
// Copyright (c) 1999 Microsoft Corporation. All rights reserved.
|
|||
|
//
|
|||
|
// Helper functions for logging script parsing. Useful for debugging, but never turned on in released builds.
|
|||
|
//
|
|||
|
|
|||
|
#error This file should never be used in released builds. // <20><>
|
|||
|
|
|||
|
#include "stdinc.h"
|
|||
|
#include "englog.h"
|
|||
|
|
|||
|
void LogToken(Lexer &l)
|
|||
|
{
|
|||
|
char msg[500] = "";
|
|||
|
char type[500] = "";
|
|||
|
char more[500] = "";
|
|||
|
|
|||
|
switch (l)
|
|||
|
{
|
|||
|
case TOKEN_eof:
|
|||
|
if (l.error_num())
|
|||
|
{
|
|||
|
sprintf(msg, "%d(%d): error #%d - %s\n", l.line(), l.column(), l.error_num(), l.error_descr());
|
|||
|
OutputDebugString(msg);
|
|||
|
return;
|
|||
|
}
|
|||
|
strcpy(type, "end-of-file");
|
|||
|
break;
|
|||
|
case TOKEN_sub:
|
|||
|
strcpy(type, "sub");
|
|||
|
break;
|
|||
|
case TOKEN_dim:
|
|||
|
strcpy(type, "dim");
|
|||
|
break;
|
|||
|
case TOKEN_if:
|
|||
|
strcpy(type, "if");
|
|||
|
break;
|
|||
|
case TOKEN_then:
|
|||
|
strcpy(type, "then");
|
|||
|
break;
|
|||
|
case TOKEN_end:
|
|||
|
strcpy(type, "end");
|
|||
|
break;
|
|||
|
case TOKEN_elseif:
|
|||
|
strcpy(type, "elseif");
|
|||
|
break;
|
|||
|
case TOKEN_else:
|
|||
|
strcpy(type, "else");
|
|||
|
break;
|
|||
|
case TOKEN_set:
|
|||
|
strcpy(type, "set");
|
|||
|
break;
|
|||
|
case TOKEN_call:
|
|||
|
strcpy(type, "call");
|
|||
|
break;
|
|||
|
case TOKEN_lparen:
|
|||
|
strcpy(type, "(");
|
|||
|
break;
|
|||
|
case TOKEN_rparen:
|
|||
|
strcpy(type, ")");
|
|||
|
break;
|
|||
|
case TOKEN_comma:
|
|||
|
strcpy(type, ",");
|
|||
|
break;
|
|||
|
case TOKEN_op_minus:
|
|||
|
strcpy(type, "-");
|
|||
|
break;
|
|||
|
case TOKEN_op_not:
|
|||
|
strcpy(type, "not");
|
|||
|
break;
|
|||
|
case TOKEN_op_pow:
|
|||
|
strcpy(type, "^");
|
|||
|
break;
|
|||
|
case TOKEN_op_mult:
|
|||
|
strcpy(type, "*");
|
|||
|
break;
|
|||
|
case TOKEN_op_div:
|
|||
|
strcpy(type, "\\");
|
|||
|
break;
|
|||
|
case TOKEN_op_mod:
|
|||
|
strcpy(type, "mod");
|
|||
|
break;
|
|||
|
case TOKEN_op_plus:
|
|||
|
strcpy(type, "+");
|
|||
|
break;
|
|||
|
case TOKEN_op_lt:
|
|||
|
strcpy(type, "<");
|
|||
|
break;
|
|||
|
case TOKEN_op_leq:
|
|||
|
strcpy(type, "<=");
|
|||
|
break;
|
|||
|
case TOKEN_op_gt:
|
|||
|
strcpy(type, ">");
|
|||
|
break;
|
|||
|
case TOKEN_op_geq:
|
|||
|
strcpy(type, ">=");
|
|||
|
break;
|
|||
|
case TOKEN_op_eq:
|
|||
|
strcpy(type, "=");
|
|||
|
break;
|
|||
|
case TOKEN_op_neq:
|
|||
|
strcpy(type, "<>");
|
|||
|
break;
|
|||
|
case TOKEN_is:
|
|||
|
strcpy(type, "is");
|
|||
|
break;
|
|||
|
case TOKEN_and:
|
|||
|
strcpy(type, "and");
|
|||
|
break;
|
|||
|
case TOKEN_or:
|
|||
|
strcpy(type, "or");
|
|||
|
break;
|
|||
|
case TOKEN_linebreak:
|
|||
|
strcpy(type, "linebreak");
|
|||
|
break;
|
|||
|
case TOKEN_identifier:
|
|||
|
strcpy(type, "identifier");
|
|||
|
strcpy(more, l.identifier_name());
|
|||
|
break;
|
|||
|
case TOKEN_identifierdot:
|
|||
|
strcpy(type, "identifier.");
|
|||
|
strcpy(more, l.identifier_name());
|
|||
|
break;
|
|||
|
case TOKEN_stringliteral:
|
|||
|
strcpy(type, "string-literal");
|
|||
|
strcpy(more, l.stringliteral_text());
|
|||
|
break;
|
|||
|
case TOKEN_numericliteral:
|
|||
|
strcpy(type, "numeric-literal");
|
|||
|
_itoa(l.numericliteral_val(), more, 10);
|
|||
|
break;
|
|||
|
default:
|
|||
|
strcpy(type, "invalid token type!");
|
|||
|
break;
|
|||
|
}
|
|||
|
static const char format[] = "%d(%d): %s\n";
|
|||
|
static const char formatmore[] = "%d(%d): %s(%s)\n";
|
|||
|
sprintf(msg, *more ? formatmore : format, l.line(), l.column(), type, more);
|
|||
|
OutputDebugString(msg);
|
|||
|
}
|
|||
|
|
|||
|
SmartRef::AString GetVarrefName(Script &script, VariableReferences::index ivarref)
|
|||
|
{
|
|||
|
VariableReference r = script.varrefs[ivarref];
|
|||
|
|
|||
|
const char *pszKind;
|
|||
|
if (r.k == VariableReference::_global)
|
|||
|
pszKind = "G";
|
|||
|
else if (r.k == VariableReference::_local)
|
|||
|
pszKind = "L";
|
|||
|
|
|||
|
bool fFirst = true;
|
|||
|
char namebuf[500] = "";
|
|||
|
for (ReferenceNames::index irname = r.irname; script.rnames[irname].istrIdentifier != -1; ++irname)
|
|||
|
{
|
|||
|
if (fFirst)
|
|||
|
fFirst = false;
|
|||
|
else
|
|||
|
strcat(namebuf, ".");
|
|||
|
strcat(namebuf, script.strings[script.rnames[irname].istrIdentifier]);
|
|||
|
}
|
|||
|
|
|||
|
Variables::index islot = r.ivar;
|
|||
|
|
|||
|
// check if it's a dispatch item
|
|||
|
if (r.k == VariableReference::_global)
|
|||
|
{
|
|||
|
DISPID dispid = script.globals[islot].dispid;
|
|||
|
if (dispid != DISPID_UNKNOWN)
|
|||
|
{
|
|||
|
pszKind = "D";
|
|||
|
islot = dispid; // show the dispid instead of the slot
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
char buf[500];
|
|||
|
sprintf(buf, "{%s%d}%s", pszKind, islot, namebuf);
|
|||
|
|
|||
|
return buf;
|
|||
|
}
|
|||
|
|
|||
|
SmartRef::AString GetValueName(Script &script, Values::index ival)
|
|||
|
{
|
|||
|
const Value &v = script.vals[ival];
|
|||
|
|
|||
|
char buf[500];
|
|||
|
if (v.k == Value::_numvalue)
|
|||
|
{
|
|||
|
sprintf(buf, "%d", v.inumvalue);
|
|||
|
}
|
|||
|
else if (v.k == Value::_strvalue)
|
|||
|
{
|
|||
|
sprintf(buf, "\"%s\"", script.strings[v.istrvalue]);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
assert(v.k == Value::_varref);
|
|||
|
return GetVarrefName(script, v.ivarref);
|
|||
|
}
|
|||
|
|
|||
|
return buf;
|
|||
|
}
|
|||
|
|
|||
|
void Indent(int iNesting)
|
|||
|
{
|
|||
|
for (int i = 0; i < iNesting; ++i)
|
|||
|
OutputDebugString(" ");
|
|||
|
}
|
|||
|
|
|||
|
// forward declaration due to mutual recursion with LogExpression
|
|||
|
void LogCall(Script &script, Calls::index icall);
|
|||
|
|
|||
|
ExprBlocks::index LogExpression(Script &script, ExprBlocks::index _iexpr)
|
|||
|
{
|
|||
|
char msg[500] = "";
|
|||
|
|
|||
|
bool fFirst = true;
|
|||
|
for (ExprBlocks::index iexpr = _iexpr; script.exprs[iexpr]; ++iexpr)
|
|||
|
{
|
|||
|
ExprBlock expr = script.exprs[iexpr];
|
|||
|
|
|||
|
if (fFirst)
|
|||
|
fFirst = false;
|
|||
|
else
|
|||
|
OutputDebugString("|");
|
|||
|
|
|||
|
if (expr.k == ExprBlock::_op)
|
|||
|
{
|
|||
|
bool fUnary = false;
|
|||
|
const char *pszOp = "";
|
|||
|
switch (expr.op)
|
|||
|
{
|
|||
|
case TOKEN_sub: fUnary = true; pszOp = "-"; break;
|
|||
|
case TOKEN_op_not: fUnary = true; pszOp = "not"; break;
|
|||
|
case TOKEN_op_minus: pszOp = "-"; break;
|
|||
|
case TOKEN_op_pow: pszOp = "^"; break;
|
|||
|
case TOKEN_op_mult: pszOp = "*"; break;
|
|||
|
case TOKEN_op_div: pszOp = "\\"; break;
|
|||
|
case TOKEN_op_mod: pszOp = "mod"; break;
|
|||
|
case TOKEN_op_plus: pszOp = "+"; break;
|
|||
|
case TOKEN_op_lt: pszOp = "<"; break;
|
|||
|
case TOKEN_op_leq: pszOp = "<="; break;
|
|||
|
case TOKEN_op_gt: pszOp = ">"; break;
|
|||
|
case TOKEN_op_geq: pszOp = ">="; break;
|
|||
|
case TOKEN_op_eq: pszOp = "="; break;
|
|||
|
case TOKEN_op_neq: pszOp = "<>"; break;
|
|||
|
case TOKEN_is: pszOp = "is"; break;
|
|||
|
case TOKEN_and: pszOp = "and"; break;
|
|||
|
case TOKEN_or: pszOp = "or"; break;
|
|||
|
default: assert(false); break;
|
|||
|
}
|
|||
|
|
|||
|
if (fUnary)
|
|||
|
sprintf(msg, "%su", pszOp);
|
|||
|
else
|
|||
|
sprintf(msg, "%sb", pszOp);
|
|||
|
OutputDebugString(msg);
|
|||
|
}
|
|||
|
else if (expr.k == ExprBlock::_val)
|
|||
|
{
|
|||
|
SmartRef::AString astrVal = GetValueName(script, expr.ival);
|
|||
|
OutputDebugString(astrVal);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
assert(expr.k == ExprBlock::_call);
|
|||
|
LogCall(script, expr.icall);
|
|||
|
}
|
|||
|
}
|
|||
|
return iexpr;
|
|||
|
}
|
|||
|
|
|||
|
void LogCall(Script &script, Calls::index icall)
|
|||
|
{
|
|||
|
Call c = script.calls[icall];
|
|||
|
|
|||
|
if (c.k == Call::_global)
|
|||
|
{
|
|||
|
OutputDebugString(script.strings[c.istrname]);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
assert(c.k == Call::_dereferenced);
|
|||
|
SmartRef::AString astrCall = GetVarrefName(script, c.ivarref);
|
|||
|
OutputDebugString(astrCall);
|
|||
|
}
|
|||
|
|
|||
|
OutputDebugString("(");
|
|||
|
bool fFirst = true;
|
|||
|
for (ExprBlocks::index iexpr = c.iexprParams; script.exprs[iexpr]; ++iexpr)
|
|||
|
{
|
|||
|
if (fFirst)
|
|||
|
fFirst = false;
|
|||
|
else
|
|||
|
OutputDebugString(", ");
|
|||
|
iexpr = LogExpression(script, iexpr);
|
|||
|
}
|
|||
|
|
|||
|
OutputDebugString(")");
|
|||
|
}
|
|||
|
|
|||
|
void LogStatements(Script &script, Statements::index istmt, int iNesting)
|
|||
|
{
|
|||
|
char msg[500] = "";
|
|||
|
for (; script.statements[istmt].k; ++istmt)
|
|||
|
{
|
|||
|
Statement s = script.statements[istmt];
|
|||
|
if (s.k == Statement::_asgn)
|
|||
|
{
|
|||
|
Assignment a = script.asgns[s.iasgn];
|
|||
|
|
|||
|
SmartRef::AString astrLHS = GetVarrefName(script, a.ivarrefLHS);
|
|||
|
sprintf(msg, "%s = ", astrLHS);
|
|||
|
Indent(iNesting);
|
|||
|
OutputDebugString(msg);
|
|||
|
|
|||
|
LogExpression(script, a.iexprRHS);
|
|||
|
OutputDebugString("\n");
|
|||
|
}
|
|||
|
else if (s.k == Statement::_if)
|
|||
|
{
|
|||
|
bool fFirst = true;
|
|||
|
for (IfBlocks::index iif = s.iif; script.ifs[iif].k != IfBlock::_end; ++iif)
|
|||
|
{
|
|||
|
Indent(iNesting);
|
|||
|
|
|||
|
IfBlock ib = script.ifs[iif];
|
|||
|
if (fFirst)
|
|||
|
{
|
|||
|
assert(ib.k == IfBlock::_cond);
|
|||
|
OutputDebugString("if ");
|
|||
|
fFirst = false;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (ib.k == IfBlock::_cond)
|
|||
|
OutputDebugString("elseif ");
|
|||
|
else if (ib.k == IfBlock::_else)
|
|||
|
OutputDebugString("else");
|
|||
|
}
|
|||
|
|
|||
|
if (ib.k == IfBlock::_cond)
|
|||
|
{
|
|||
|
LogExpression(script, ib.iexprCondition);
|
|||
|
}
|
|||
|
|
|||
|
OutputDebugString("\n");
|
|||
|
LogStatements(script, ib.istmtBlock, iNesting + 3);
|
|||
|
}
|
|||
|
|
|||
|
istmt = s.istmtIfTail - 1; // -1 to offset the loop, which will increment it back
|
|||
|
}
|
|||
|
else if (s.k == Statement::_call)
|
|||
|
{
|
|||
|
Indent(iNesting);
|
|||
|
LogCall(script, s.icall);
|
|||
|
OutputDebugString("\n");
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
assert(false);
|
|||
|
Indent(iNesting);
|
|||
|
OutputDebugString(" Unknown statement type!\n");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void LogRoutine(Script &script, Routines::index irtn)
|
|||
|
{
|
|||
|
Routine r = script.routines[irtn];
|
|||
|
const char *pszName = script.strings[r.istrIdentifier];
|
|||
|
int cLocals = r.ivarNextLocal;
|
|||
|
|
|||
|
char msg[500] = "";
|
|||
|
sprintf(msg, "@ Sub %s (%d locals)\n", pszName, cLocals);
|
|||
|
OutputDebugString(msg);
|
|||
|
LogStatements(script, r.istmtBody, 3);
|
|||
|
}
|