windows-nt/Source/XPSP1/NT/multimedia/directx/dmusic/dmscript/englog.cpp
2020-09-26 16:20:57 +08:00

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. // §§
#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);
}