- started with cleanup and separation of DECORATE code.

* everything related to scripting is now placed in a subdirectory 'scripting', which itself is separated into DECORATE, ZSCRIPT, the VM and code generation.
 * a few items have been moved to different headers so that the DECORATE parser definitions can mostly be kept local. The only exception at the moment is the flags interface on which 3 source files depend.
This commit is contained in:
Christoph Oelckers 2016-10-12 19:22:33 +02:00
parent 6a8ab9a4d3
commit b1a83bfd26
132 changed files with 234 additions and 198 deletions

View file

@ -0,0 +1,904 @@
/*
** ast.cpp
**
**---------------------------------------------------------------------------
** Copyright -2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "dobject.h"
#include "sc_man.h"
#include "memarena.h"
#include "zcc_parser.h"
#include "zcc-parse.h"
class FLispString;
extern void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *);
static const char *BuiltInTypeNames[] =
{
"sint8", "uint8",
"sint16", "uint16",
"sint32", "uint32",
"intauto",
"bool",
"float32", "float64", "floatauto",
"string",
"vector2",
"vector3",
"vector4",
"name",
"color",
"state",
"sound",
"usertype",
};
class FLispString
{
public:
operator FString &() { return Str; }
FLispString()
{
NestDepth = Column = 0;
WrapWidth = 200;
NeedSpace = false;
ConsecOpens = 0;
}
void Open(const char *label)
{
size_t labellen = label != NULL ? strlen(label) : 0;
CheckWrap(labellen + 1 + NeedSpace);
if (NeedSpace)
{
Str << ' ';
ConsecOpens = 0;
}
Str << '(';
ConsecOpens++;
if (label != NULL)
{
Str.AppendCStrPart(label, labellen);
}
Column += labellen + 1 + NeedSpace;
NestDepth++;
NeedSpace = (label != NULL);
}
void Close()
{
assert(NestDepth != 0);
Str << ')';
Column++;
NestDepth--;
NeedSpace = true;
}
void Break()
{
// Don't break if not needed.
if (Column != NestDepth)
{
if (NeedSpace)
{
ConsecOpens = 0;
}
else
{ // Move hanging ( characters to the new line
Str.Truncate(long(Str.Len() - ConsecOpens));
NestDepth -= ConsecOpens;
}
Str << '\n';
Column = NestDepth;
NeedSpace = false;
if (NestDepth > 0)
{
Str.AppendFormat("%*s", (int)NestDepth, "");
}
if (ConsecOpens > 0)
{
for (size_t i = 0; i < ConsecOpens; ++i)
{
Str << '(';
}
NestDepth += ConsecOpens;
}
}
}
bool CheckWrap(size_t len)
{
if (len + Column > WrapWidth)
{
Break();
return true;
}
return false;
}
void Add(const char *str, size_t len)
{
CheckWrap(len + NeedSpace);
if (NeedSpace)
{
Str << ' ';
}
Str.AppendCStrPart(str, len);
Column += len + NeedSpace;
NeedSpace = true;
}
void Add(const char *str)
{
Add(str, strlen(str));
}
void Add(FString &str)
{
Add(str.GetChars(), str.Len());
}
void AddName(FName name)
{
size_t namelen = strlen(name.GetChars());
CheckWrap(namelen + 2 + NeedSpace);
if (NeedSpace)
{
NeedSpace = false;
Str << ' ';
}
Str << '\'' << name.GetChars() << '\'';
Column += namelen + 2 + NeedSpace;
NeedSpace = true;
}
void AddChar(char c)
{
Add(&c, 1);
}
void AddInt(int i, bool un=false)
{
char buf[16];
size_t len;
if (!un)
{
len = mysnprintf(buf, countof(buf), "%d", i);
}
else
{
len = mysnprintf(buf, countof(buf), "%uu", i);
}
Add(buf, len);
}
void AddHex(unsigned x)
{
char buf[10];
size_t len = mysnprintf(buf, countof(buf), "%08x", x);
Add(buf, len);
}
void AddFloat(double f, bool single)
{
char buf[32];
size_t len = mysnprintf(buf, countof(buf), "%.4f", f);
if (single)
{
buf[len++] = 'f';
buf[len] = '\0';
}
Add(buf, len);
}
private:
FString Str;
size_t NestDepth;
size_t Column;
size_t WrapWidth;
size_t ConsecOpens;
bool NeedSpace;
};
static void PrintNode(FLispString &out, ZCC_TreeNode *node)
{
assert(TreeNodePrinter[NUM_AST_NODE_TYPES-1] != NULL);
if (node->NodeType >= 0 && node->NodeType < NUM_AST_NODE_TYPES)
{
TreeNodePrinter[node->NodeType](out, node);
}
else
{
out.Open("unknown-node-type");
out.AddInt(node->NodeType);
out.Close();
}
}
static void PrintNodes(FLispString &out, ZCC_TreeNode *node, bool newlist=true, bool addbreaks=false)
{
ZCC_TreeNode *p;
if (node == NULL)
{
out.Add("nil", 3);
}
else
{
if (newlist)
{
out.Open(NULL);
}
p = node;
do
{
if (addbreaks)
{
out.Break();
}
PrintNode(out, p);
p = p->SiblingNext;
} while (p != node);
if (newlist)
{
out.Close();
}
}
}
static void PrintBuiltInType(FLispString &out, EZCCBuiltinType type)
{
assert(ZCC_NUM_BUILT_IN_TYPES == countof(BuiltInTypeNames));
if (unsigned(type) >= unsigned(ZCC_NUM_BUILT_IN_TYPES))
{
char buf[30];
size_t len = mysnprintf(buf, countof(buf), "bad-type-%u", type);
out.Add(buf, len);
}
else
{
out.Add(BuiltInTypeNames[type]);
}
}
static void PrintIdentifier(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Identifier *inode = (ZCC_Identifier *)node;
out.Open("identifier");
out.AddName(inode->Id);
out.Close();
}
static void PrintStringConst(FLispString &out, FString str)
{
FString outstr;
outstr << '"';
for (size_t i = 0; i < str.Len(); ++i)
{
if (str[i] == '"')
{
outstr << "\"";
}
else if (str[i] == '\\')
{
outstr << "\\\\";
}
else if (str[i] >= 32)
{
outstr << str[i];
}
else
{
outstr.AppendFormat("\\x%02X", str[i]);
}
}
outstr << '"';
out.Add(outstr);
}
static void PrintClass(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Class *cnode = (ZCC_Class *)node;
out.Break();
out.Open("class");
out.AddName(cnode->NodeName);
PrintNodes(out, cnode->ParentName);
PrintNodes(out, cnode->Replaces);
out.AddHex(cnode->Flags);
PrintNodes(out, cnode->Body, false, true);
out.Close();
}
static void PrintStruct(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Struct *snode = (ZCC_Struct *)node;
out.Break();
out.Open("struct");
out.AddName(snode->NodeName);
PrintNodes(out, snode->Body, false, true);
out.Close();
}
static void PrintEnum(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Enum *enode = (ZCC_Enum *)node;
out.Break();
out.Open("enum");
out.AddName(enode->NodeName);
PrintBuiltInType(out, enode->EnumType);
out.Add(enode->Elements == NULL ? "nil" : "...", 3);
out.Close();
}
static void PrintEnumTerminator(FLispString &out, ZCC_TreeNode *node)
{
out.Open("enum-term");
out.Close();
}
static void PrintStates(FLispString &out, ZCC_TreeNode *node)
{
ZCC_States *snode = (ZCC_States *)node;
out.Break();
out.Open("states");
PrintNodes(out, snode->Body, false, true);
out.Close();
}
static void PrintStatePart(FLispString &out, ZCC_TreeNode *node)
{
out.Open("state-part");
out.Close();
}
static void PrintStateLabel(FLispString &out, ZCC_TreeNode *node)
{
ZCC_StateLabel *snode = (ZCC_StateLabel *)node;
out.Open("state-label");
out.AddName(snode->Label);
out.Close();
}
static void PrintStateStop(FLispString &out, ZCC_TreeNode *node)
{
out.Open("state-stop");
out.Close();
}
static void PrintStateWait(FLispString &out, ZCC_TreeNode *node)
{
out.Open("state-wait");
out.Close();
}
static void PrintStateFail(FLispString &out, ZCC_TreeNode *node)
{
out.Open("state-fail");
out.Close();
}
static void PrintStateLoop(FLispString &out, ZCC_TreeNode *node)
{
out.Open("state-loop");
out.Close();
}
static void PrintStateGoto(FLispString &out, ZCC_TreeNode *node)
{
ZCC_StateGoto *snode = (ZCC_StateGoto *)node;
out.Open("state-goto");
PrintNodes(out, snode->Qualifier);
PrintNodes(out, snode->Label);
PrintNodes(out, snode->Offset);
out.Close();
}
static void PrintStateLine(FLispString &out, ZCC_TreeNode *node)
{
ZCC_StateLine *snode = (ZCC_StateLine *)node;
out.Open("state-line");
out.Add(*(snode->Sprite));
PrintNodes(out, snode->Duration);
if (snode->bNoDelay) out.Add("nodelay", 7);
if (snode->bBright) out.Add("bright", 6);
if (snode->bFast) out.Add("fast", 4);
if (snode->bSlow) out.Add("slow", 4);
if (snode->bCanRaise) out.Add("canraise", 8);
out.Add(*(snode->Frames));
PrintNodes(out, snode->Offset);
PrintNodes(out, snode->Action, false);
out.Close();
}
static void PrintVarName(FLispString &out, ZCC_TreeNode *node)
{
ZCC_VarName *vnode = (ZCC_VarName *)node;
out.Open("var-name");
PrintNodes(out, vnode->ArraySize);
out.AddName(vnode->Name);
out.Close();
}
static void PrintType(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Type *tnode = (ZCC_Type *)node;
out.Open("bad-type");
PrintNodes(out, tnode->ArraySize);
out.Close();
}
static void PrintBasicType(FLispString &out, ZCC_TreeNode *node)
{
ZCC_BasicType *tnode = (ZCC_BasicType *)node;
out.Open("basic-type");
PrintNodes(out, tnode->ArraySize);
PrintBuiltInType(out, tnode->Type);
if (tnode->Type == ZCC_UserType)
{
PrintNodes(out, tnode->UserType, false);
}
out.Close();
}
static void PrintMapType(FLispString &out, ZCC_TreeNode *node)
{
ZCC_MapType *tnode = (ZCC_MapType *)node;
out.Open("map-type");
PrintNodes(out, tnode->ArraySize);
PrintNodes(out, tnode->KeyType);
PrintNodes(out, tnode->ValueType);
out.Close();
}
static void PrintDynArrayType(FLispString &out, ZCC_TreeNode *node)
{
ZCC_DynArrayType *tnode = (ZCC_DynArrayType *)node;
out.Open("dyn-array-type");
PrintNodes(out, tnode->ArraySize);
PrintNodes(out, tnode->ElementType);
out.Close();
}
static void PrintClassType(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ClassType *tnode = (ZCC_ClassType *)node;
out.Open("class-type");
PrintNodes(out, tnode->ArraySize);
PrintNodes(out, tnode->Restriction);
out.Close();
}
static void OpenExprType(FLispString &out, EZCCExprType type)
{
char buf[32];
if (unsigned(type) < PEX_COUNT_OF)
{
mysnprintf(buf, countof(buf), "expr-%s", ZCC_OpInfo[type].OpName);
}
else
{
mysnprintf(buf, countof(buf), "bad-pex-%u", type);
}
out.Open(buf);
}
static void PrintExpression(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Expression *enode = (ZCC_Expression *)node;
OpenExprType(out, enode->Operation);
out.Close();
}
static void PrintExprID(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprID *enode = (ZCC_ExprID *)node;
assert(enode->Operation == PEX_ID);
out.Open("expr-id");
out.AddName(enode->Identifier);
out.Close();
}
static void PrintExprTypeRef(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprTypeRef *enode = (ZCC_ExprTypeRef *)node;
assert(enode->Operation == PEX_TypeRef);
out.Open("expr-type-ref");
if (enode->RefType == TypeSInt8) { out.Add("sint8"); }
else if (enode->RefType == TypeUInt8) { out.Add("uint8"); }
else if (enode->RefType == TypeSInt16) { out.Add("sint16"); }
else if (enode->RefType == TypeSInt32) { out.Add("sint32"); }
else if (enode->RefType == TypeFloat32) { out.Add("float32"); }
else if (enode->RefType == TypeFloat64) { out.Add("float64"); }
else if (enode->RefType == TypeString) { out.Add("string"); }
else if (enode->RefType == TypeName) { out.Add("name"); }
else if (enode->RefType == TypeColor) { out.Add("color"); }
else if (enode->RefType == TypeSound) { out.Add("sound"); }
else { out.Add("other"); }
out.Close();
}
static void PrintExprConstant(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprConstant *enode = (ZCC_ExprConstant *)node;
assert(enode->Operation == PEX_ConstValue);
out.Open("expr-const");
if (enode->Type == TypeString)
{
PrintStringConst(out, *enode->StringVal);
}
else if (enode->Type == TypeFloat64)
{
out.AddFloat(enode->DoubleVal, false);
}
else if (enode->Type == TypeFloat32)
{
out.AddFloat(enode->DoubleVal, true);
}
else if (enode->Type == TypeName)
{
out.AddName(ENamedName(enode->IntVal));
}
else if (enode->Type->IsKindOf(RUNTIME_CLASS(PInt)))
{
out.AddInt(enode->IntVal, static_cast<PInt *>(enode->Type)->Unsigned);
}
out.Close();
}
static void PrintExprFuncCall(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprFuncCall *enode = (ZCC_ExprFuncCall *)node;
assert(enode->Operation == PEX_FuncCall);
out.Open("expr-func-call");
PrintNodes(out, enode->Function);
PrintNodes(out, enode->Parameters, false);
out.Close();
}
static void PrintExprMemberAccess(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprMemberAccess *enode = (ZCC_ExprMemberAccess *)node;
assert(enode->Operation == PEX_MemberAccess);
out.Open("expr-member-access");
PrintNodes(out, enode->Left);
out.AddName(enode->Right);
out.Close();
}
static void PrintExprUnary(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprUnary *enode = (ZCC_ExprUnary *)node;
OpenExprType(out, enode->Operation);
PrintNodes(out, enode->Operand, false);
out.Close();
}
static void PrintExprBinary(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprBinary *enode = (ZCC_ExprBinary *)node;
OpenExprType(out, enode->Operation);
PrintNodes(out, enode->Left);
PrintNodes(out, enode->Right);
out.Close();
}
static void PrintExprTrinary(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExprTrinary *enode = (ZCC_ExprTrinary *)node;
OpenExprType(out, enode->Operation);
PrintNodes(out, enode->Test);
PrintNodes(out, enode->Left);
PrintNodes(out, enode->Right);
out.Close();
}
static void PrintFuncParam(FLispString &out, ZCC_TreeNode *node)
{
ZCC_FuncParm *pnode = (ZCC_FuncParm *)node;
out.Break();
out.Open("func-parm");
out.AddName(pnode->Label);
PrintNodes(out, pnode->Value, false);
out.Close();
}
static void PrintStatement(FLispString &out, ZCC_TreeNode *node)
{
out.Open("statement");
out.Close();
}
static void PrintCompoundStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_CompoundStmt *snode = (ZCC_CompoundStmt *)node;
out.Break();
out.Open("compound-stmt");
PrintNodes(out, snode->Content, false, true);
out.Close();
}
static void PrintDefault(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Default *snode = (ZCC_Default *)node;
out.Break();
out.Open("default");
PrintNodes(out, snode->Content, false, true);
out.Close();
}
static void PrintContinueStmt(FLispString &out, ZCC_TreeNode *node)
{
out.Break();
out.Open("continue-stmt");
out.Close();
}
static void PrintBreakStmt(FLispString &out, ZCC_TreeNode *node)
{
out.Break();
out.Open("break-stmt");
out.Close();
}
static void PrintReturnStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ReturnStmt *snode = (ZCC_ReturnStmt *)node;
out.Break();
out.Open("return-stmt");
PrintNodes(out, snode->Values, false);
out.Close();
}
static void PrintExpressionStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ExpressionStmt *snode = (ZCC_ExpressionStmt *)node;
out.Break();
out.Open("expression-stmt");
PrintNodes(out, snode->Expression, false);
out.Close();
}
static void PrintIterationStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_IterationStmt *snode = (ZCC_IterationStmt *)node;
out.Break();
out.Open("iteration-stmt");
out.Add((snode->CheckAt == ZCC_IterationStmt::Start) ? "start" : "end");
out.Break();
PrintNodes(out, snode->LoopCondition);
out.Break();
PrintNodes(out, snode->LoopBumper);
out.Break();
PrintNodes(out, snode->LoopStatement);
out.Close();
}
static void PrintIfStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_IfStmt *snode = (ZCC_IfStmt *)node;
out.Break();
out.Open("if-stmt");
PrintNodes(out, snode->Condition);
out.Break();
PrintNodes(out, snode->TruePath);
out.Break();
PrintNodes(out, snode->FalsePath);
out.Close();
}
static void PrintSwitchStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_SwitchStmt *snode = (ZCC_SwitchStmt *)node;
out.Break();
out.Open("switch-stmt");
PrintNodes(out, snode->Condition);
out.Break();
PrintNodes(out, snode->Content, false);
out.Close();
}
static void PrintCaseStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_CaseStmt *snode = (ZCC_CaseStmt *)node;
out.Break();
out.Open("case-stmt");
PrintNodes(out, snode->Condition, false);
out.Close();
}
static void BadAssignOp(FLispString &out, int op)
{
char buf[32];
size_t len = mysnprintf(buf, countof(buf), "assign-op-%d", op);
out.Add(buf, len);
}
static void PrintAssignStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_AssignStmt *snode = (ZCC_AssignStmt *)node;
out.Open("assign-stmt");
switch (snode->AssignOp)
{
case ZCC_EQ: out.AddChar('='); break;
case ZCC_MULEQ: out.Add("*=", 2); break;
case ZCC_DIVEQ: out.Add("/=", 2); break;
case ZCC_MODEQ: out.Add("%=", 2); break;
case ZCC_ADDEQ: out.Add("+=", 2); break;
case ZCC_SUBEQ: out.Add("-=", 2); break;
case ZCC_LSHEQ: out.Add("<<=", 2); break;
case ZCC_RSHEQ: out.Add(">>=", 2); break;
case ZCC_ANDEQ: out.Add("&=", 2); break;
case ZCC_OREQ: out.Add("|=", 2); break;
case ZCC_XOREQ: out.Add("^=", 2); break;
default: BadAssignOp(out, snode->AssignOp); break;
}
PrintNodes(out, snode->Dests);
PrintNodes(out, snode->Sources);
out.Close();
}
static void PrintLocalVarStmt(FLispString &out, ZCC_TreeNode *node)
{
ZCC_LocalVarStmt *snode = (ZCC_LocalVarStmt *)node;
out.Open("local-var-stmt");
PrintNodes(out, snode->Type);
PrintNodes(out, snode->Vars);
PrintNodes(out, snode->Inits);
out.Close();
}
static void PrintFuncParamDecl(FLispString &out, ZCC_TreeNode *node)
{
ZCC_FuncParamDecl *dnode = (ZCC_FuncParamDecl *)node;
out.Break();
out.Open("func-param-decl");
PrintNodes(out, dnode->Type);
out.AddName(dnode->Name);
out.AddHex(dnode->Flags);
PrintNodes(out, dnode->Default);
out.Close();
}
static void PrintConstantDef(FLispString &out, ZCC_TreeNode *node)
{
ZCC_ConstantDef *dnode = (ZCC_ConstantDef *)node;
out.Break();
out.Open("constant-def");
out.AddName(dnode->NodeName);
PrintNodes(out, dnode->Value, false);
out.Close();
}
static void PrintDeclarator(FLispString &out, ZCC_TreeNode *node)
{
ZCC_Declarator *dnode = (ZCC_Declarator *)node;
out.Break();
out.Open("declarator");
out.AddHex(dnode->Flags);
PrintNodes(out, dnode->Type);
out.Close();
}
static void PrintVarDeclarator(FLispString &out, ZCC_TreeNode *node)
{
ZCC_VarDeclarator *dnode = (ZCC_VarDeclarator *)node;
out.Break();
out.Open("var-declarator");
out.AddHex(dnode->Flags);
PrintNodes(out, dnode->Type);
PrintNodes(out, dnode->Names);
out.Close();
}
static void PrintFuncDeclarator(FLispString &out, ZCC_TreeNode *node)
{
ZCC_FuncDeclarator *dnode = (ZCC_FuncDeclarator *)node;
out.Break();
out.Open("func-declarator");
out.AddHex(dnode->Flags);
PrintNodes(out, dnode->Type);
out.AddName(dnode->Name);
PrintNodes(out, dnode->Params);
PrintNodes(out, dnode->Body, false);
out.Close();
}
static void PrintFlagStmt(FLispString &out, ZCC_TreeNode *node)
{
auto dnode = (ZCC_FlagStmt *)node;
out.Break();
out.Open("flag-stmt");
PrintNodes(out, dnode->name, false);
out.AddInt(dnode->set);
out.Close();
}
static void PrintPropertyStmt(FLispString &out, ZCC_TreeNode *node)
{
auto dnode = (ZCC_PropertyStmt *)node;
out.Break();
out.Open("property-stmt");
PrintNodes(out, dnode->Prop, false);
PrintNodes(out, dnode->Values, false);
out.Close();
}
void (* const TreeNodePrinter[NUM_AST_NODE_TYPES])(FLispString &, ZCC_TreeNode *) =
{
PrintIdentifier,
PrintClass,
PrintStruct,
PrintEnum,
PrintEnumTerminator,
PrintStates,
PrintStatePart,
PrintStateLabel,
PrintStateStop,
PrintStateWait,
PrintStateFail,
PrintStateLoop,
PrintStateGoto,
PrintStateLine,
PrintVarName,
PrintType,
PrintBasicType,
PrintMapType,
PrintDynArrayType,
PrintClassType,
PrintExpression,
PrintExprID,
PrintExprTypeRef,
PrintExprConstant,
PrintExprFuncCall,
PrintExprMemberAccess,
PrintExprUnary,
PrintExprBinary,
PrintExprTrinary,
PrintFuncParam,
PrintStatement,
PrintCompoundStmt,
PrintContinueStmt,
PrintBreakStmt,
PrintReturnStmt,
PrintExpressionStmt,
PrintIterationStmt,
PrintIfStmt,
PrintSwitchStmt,
PrintCaseStmt,
PrintAssignStmt,
PrintLocalVarStmt,
PrintFuncParamDecl,
PrintConstantDef,
PrintDeclarator,
PrintVarDeclarator,
PrintFuncDeclarator,
PrintDefault,
PrintFlagStmt,
PrintPropertyStmt
};
FString ZCC_PrintAST(ZCC_TreeNode *root)
{
FLispString out;
PrintNodes(out, root);
return out;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,149 @@
#ifndef ZCC_COMPILE_H
#define ZCC_COMPILE_H
struct Baggage;
struct FPropertyInfo;
class AActor;
class FxExpression;
struct ZCC_StructWork
{
PSymbolTable TreeNodes;
ZCC_Struct *strct;
ZCC_Class *OuterDef;
PClass *Outer;
PSymbolTreeNode *node;
TArray<ZCC_Enum *> Enums;
TArray<ZCC_ConstantDef *> Constants;
TArray<ZCC_VarDeclarator *> Fields;
ZCC_StructWork(ZCC_Struct * s, PSymbolTreeNode *n, ZCC_Class *outer)
{
strct = s;
node = n;
OuterDef = outer;
Outer = nullptr;
};
FName NodeName() const
{
return strct->NodeName;
}
PStruct *Type()
{
return strct->Type;
}
};
struct ZCC_ClassWork
{
ZCC_Class *cls;
PSymbolTable TreeNodes;
PSymbolTreeNode *node;
TArray<ZCC_Enum *> Enums;
TArray<ZCC_ConstantDef *> Constants;
TArray<ZCC_VarDeclarator *> Fields;
TArray<ZCC_Default *> Defaults;
TArray<ZCC_FuncDeclarator *> Functions;
TArray<ZCC_States *> States;
ZCC_ClassWork(ZCC_Class * s, PSymbolTreeNode *n)
{
cls = s;
node = n;
}
FName NodeName() const
{
return cls->NodeName;
}
PClass *Type()
{
return cls->Type;
}
};
struct ZCC_ConstantWork
{
ZCC_ConstantDef *node;
PSymbolTable *outputtable;
};
class ZCCCompiler
{
public:
ZCCCompiler(ZCC_AST &tree, DObject *outer, PSymbolTable &symbols, PSymbolTable &outsymbols);
~ZCCCompiler();
int Compile();
private:
void ProcessClass(ZCC_Class *node, PSymbolTreeNode *tnode);
void ProcessStruct(ZCC_Struct *node, PSymbolTreeNode *tnode, ZCC_Class *outer);
void CreateStructTypes();
void CreateClassTypes();
void CopyConstants(TArray<ZCC_ConstantWork> &dest, TArray<ZCC_ConstantDef*> &Constants, PSymbolTable *ot);
void CompileAllConstants();
void AddConstant(ZCC_ConstantWork &constant);
bool CompileConstant(ZCC_ConstantDef *def, PSymbolTable *Symbols);
void CompileAllFields();
bool CompileFields(PStruct *type, TArray<ZCC_VarDeclarator *> &Fields, PClass *Outer, PSymbolTable *TreeNodes, bool forstruct);
FString FlagsToString(uint32_t flags);
PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes);
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PSymbolTable *sym);
PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym);
void InitDefaults();
void ProcessDefaultFlag(PClassActor *cls, ZCC_FlagStmt *flg);
void ProcessDefaultProperty(PClassActor *cls, ZCC_PropertyStmt *flg, Baggage &bag);
void DispatchProperty(FPropertyInfo *prop, ZCC_PropertyStmt *pex, AActor *defaults, Baggage &bag);
int GetInt(ZCC_Expression *expr);
double GetDouble(ZCC_Expression *expr);
const char *GetString(ZCC_Expression *expr, bool silent = false);
void InitFunctions();
void CompileStates();
FxExpression *SetupActionFunction(PClassActor *cls, ZCC_TreeNode *sl);
TArray<ZCC_ConstantDef *> Constants;
TArray<ZCC_StructWork *> Structs;
TArray<ZCC_ClassWork *> Classes;
PSymbolTreeNode *AddTreeNode(FName name, ZCC_TreeNode *node, PSymbolTable *treenodes, bool searchparents = false);
ZCC_Expression *Simplify(ZCC_Expression *root, PSymbolTable *Symbols);
ZCC_Expression *SimplifyUnary(ZCC_ExprUnary *unary, PSymbolTable *Symbols);
ZCC_Expression *SimplifyBinary(ZCC_ExprBinary *binary, PSymbolTable *Symbols);
ZCC_Expression *SimplifyMemberAccess(ZCC_ExprMemberAccess *dotop, PSymbolTable *Symbols);
ZCC_Expression *SimplifyFunctionCall(ZCC_ExprFuncCall *callop, PSymbolTable *Symbols);
ZCC_OpProto *PromoteUnary(EZCCExprType op, ZCC_Expression *&expr);
ZCC_OpProto *PromoteBinary(EZCCExprType op, ZCC_Expression *&left, ZCC_Expression *&right);
ZCC_Expression *ApplyConversion(ZCC_Expression *expr, const PType::Conversion **route, int routelen);
ZCC_Expression *AddCastNode(PType *type, ZCC_Expression *expr);
ZCC_Expression *IdentifyIdentifier(ZCC_ExprID *idnode, PSymbolTable *sym);
ZCC_Expression *NodeFromSymbol(PSymbol *sym, ZCC_Expression *source, PSymbolTable *table);
ZCC_ExprConstant *NodeFromSymbolConst(PSymbolConst *sym, ZCC_Expression *idnode);
ZCC_ExprTypeRef *NodeFromSymbolType(PSymbolType *sym, ZCC_Expression *idnode);
void Warn(ZCC_TreeNode *node, const char *msg, ...);
void Error(ZCC_TreeNode *node, const char *msg, ...);
void MessageV(ZCC_TreeNode *node, const char *txtcolor, const char *msg, va_list argptr);
DObject *Outer;
PSymbolTable *GlobalTreeNodes;
PSymbolTable *OutputSymbols;
ZCC_AST &AST;
int ErrorCount;
int WarnCount;
};
void ZCC_InitConversions();
#endif

View file

@ -0,0 +1,517 @@
/*
** zcc_expr.cpp
**
**---------------------------------------------------------------------------
** Copyright -2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include <math.h>
#include "dobject.h"
#include "sc_man.h"
#include "c_console.h"
#include "c_dispatch.h"
#include "w_wad.h"
#include "cmdlib.h"
#include "m_alloc.h"
#include "zcc_parser.h"
#include "templates.h"
#define luai_nummod(a,b) ((a) - floor((a)/(b))*(b))
static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena);
ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF] =
{
#define xx(a,z) { #a, NULL },
#include "zcc_exprlist.h"
};
// Structures used for initializing operator overloads
struct OpProto1
{
EZCCExprType Op;
PType **Type;
EvalConst1op EvalConst;
};
struct OpProto2
{
EZCCExprType Op;
PType **Res, **Ltype, **Rtype;
EvalConst2op EvalConst;
};
static struct FreeOpInfoProtos
{
~FreeOpInfoProtos()
{
for (size_t i = 0; i < countof(ZCC_OpInfo); ++i)
{
ZCC_OpInfo[i].FreeAllProtos();
}
}
} ProtoFreeer;
void ZCC_OpInfoType::FreeAllProtos()
{
for (ZCC_OpProto *proto = Protos, *next = NULL; proto != NULL; proto = next)
{
next = proto->Next;
delete proto;
}
Protos = NULL;
}
void ZCC_OpInfoType::AddProto(PType *res, PType *optype, EvalConst1op evalconst)
{
ZCC_OpProto *proto = new ZCC_OpProto(res, optype, NULL);
proto->EvalConst1 = evalconst;
proto->Next = Protos;
Protos = proto;
}
void ZCC_OpInfoType::AddProto(PType *res, PType *ltype, PType *rtype, EvalConst2op evalconst)
{
assert(ltype != NULL);
ZCC_OpProto *proto = new ZCC_OpProto(res, ltype, rtype);
proto->EvalConst2 = evalconst;
proto->Next = Protos;
Protos = proto;
}
//==========================================================================
//
// ZCC_OpInfoType :: FindBestProto (Unary)
//
// Finds the "best" prototype for this operand type. Best is defined as the
// one that requires the fewest conversions. Also returns the conversion
// route necessary to get from the input type to the desired type.
//
//==========================================================================
ZCC_OpProto *ZCC_OpInfoType::FindBestProto(PType *optype, const PType::Conversion **route, int &numslots)
{
assert(optype != NULL);
const PType::Conversion *routes[2][CONVERSION_ROUTE_SIZE];
const PType::Conversion **best_route = NULL;
int cur_route = 0;
ZCC_OpProto *best_proto = NULL;
int best_dist = INT_MAX;
// Find the best prototype.
for (ZCC_OpProto *proto = Protos; best_dist != 0 && proto != NULL; proto = proto->Next)
{
if (proto->Type2 != NULL)
{ // Not a unary prototype.
continue;
}
int dist = optype->FindConversion(proto->Type1, routes[cur_route], CONVERSION_ROUTE_SIZE);
if (dist >= 0 && dist < best_dist)
{
best_dist = dist;
best_proto = proto;
best_route = routes[cur_route];
cur_route ^= 1;
}
}
// Copy best conversion route to the caller's array.
if (best_route != NULL && route != NULL && numslots > 0)
{
numslots = MIN(numslots, best_dist);
if (numslots > 0)
{
memcpy(route, best_route, sizeof(*route) * numslots);
}
}
return best_proto;
}
//==========================================================================
//
// ZCC_OpInfoType :: FindBestProto (Binary)
//
// Finds the "best" prototype for the given operand types. Here, best is
// defined as the one that requires the fewest conversions for *one* of the
// operands. For prototypes with matching distances, the first one found
// is used. ZCC_InitOperators() initializes the prototypes in order such
// that this will result in the precedences: double > uint > int
//
//==========================================================================
ZCC_OpProto *ZCC_OpInfoType::FindBestProto(
PType *left, const PType::Conversion **route1, int &numslots1,
PType *right, const PType::Conversion **route2, int &numslots2)
{
assert(left != NULL && right != NULL);
const PType::Conversion *routes[2][2][CONVERSION_ROUTE_SIZE];
const PType::Conversion **best_route1 = NULL, **best_route2 = NULL;
int cur_route1 = 0, cur_route2 = 0;
int best_dist1 = INT_MAX, best_dist2 = INT_MAX;
ZCC_OpProto *best_proto = NULL;
int best_low_dist = INT_MAX;
for (ZCC_OpProto *proto = Protos; best_low_dist != 0 && proto != NULL; proto = proto->Next)
{
if (proto->Type2 == NULL)
{ // Not a binary prototype
continue;
}
int dist1 = left->FindConversion(proto->Type1, routes[0][cur_route1], CONVERSION_ROUTE_SIZE);
int dist2 = right->FindConversion(proto->Type2, routes[1][cur_route2], CONVERSION_ROUTE_SIZE);
if (dist1 < 0 || dist2 < 0)
{ // one or both operator types are unreachable
continue;
}
// Do not count F32->F64 conversions in the distance comparisons. If we do, then
// [[float32 (op) int]] will choose the integer version instead of the floating point
// version, which we do not want.
int test_dist1 = dist1, test_dist2 = dist2;
if (test_dist1 > 0 && routes[0][cur_route1][0]->ConvertConstant == FtoD)
{
test_dist1--;
}
if (test_dist2 > 0 && routes[1][cur_route2][0]->ConvertConstant == FtoD)
{
test_dist2--;
}
int dist = MIN(test_dist1, test_dist2);
if (dist < best_low_dist)
{
best_low_dist = dist;
best_proto = proto;
best_dist1 = dist1;
best_dist2 = dist2;
best_route1 = routes[0][cur_route1];
best_route2 = routes[1][cur_route2];
cur_route1 ^= 1;
cur_route2 ^= 1;
}
}
// Copy best conversion route to the caller's arrays.
if (best_route1 != NULL && route1 != NULL && numslots1 > 0)
{
numslots1 = MIN(numslots1, best_dist1);
if (numslots1 > 0)
{
memcpy(route1, best_route1, sizeof(*route1) * numslots1);
}
}
if (best_route2 != NULL && route2 != NULL && numslots2 > 0)
{
numslots2 = MIN(numslots2, best_dist2);
if (numslots2 > 0)
{
memcpy(route2, best_route2, sizeof(*route2) * numslots2);
}
}
return best_proto;
}
static ZCC_ExprConstant *EvalIdentity(ZCC_ExprConstant *val)
{
return val;
}
static ZCC_ExprConstant *EvalConcat(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &strings)
{
FString str = *l->StringVal + *r->StringVal;
l->StringVal = strings.Alloc(str);
return l;
}
static ZCC_ExprConstant *EvalLTGTEQSInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
{
l->IntVal = l->IntVal < r->IntVal ? -1 : l->IntVal == r->IntVal ? 0 : 1;
return l;
}
static ZCC_ExprConstant *EvalLTGTEQUInt32(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
{
l->IntVal = l->UIntVal < r->UIntVal ? -1 : l->UIntVal == r->UIntVal ? 0 : 1;
l->Type = TypeSInt32;
return l;
}
static ZCC_ExprConstant *EvalLTGTEQFloat64(ZCC_ExprConstant *l, ZCC_ExprConstant *r, FSharedStringArena &)
{
l->IntVal = l->DoubleVal < r->DoubleVal ? -1 : l->DoubleVal == r->DoubleVal ? 0 : 1;
l->Type = TypeSInt32;
return l;
}
void ZCC_InitOperators()
{
// Prototypes are added from lowest to highest conversion precedence.
// Unary operators
static const OpProto1 UnaryOpInit[] =
{
{ PEX_PostInc , (PType **)&TypeSInt32, EvalIdentity },
{ PEX_PostInc , (PType **)&TypeUInt32, EvalIdentity },
{ PEX_PostInc , (PType **)&TypeFloat64, EvalIdentity },
{ PEX_PostDec , (PType **)&TypeSInt32, EvalIdentity },
{ PEX_PostDec , (PType **)&TypeUInt32, EvalIdentity },
{ PEX_PostDec , (PType **)&TypeFloat64, EvalIdentity },
{ PEX_PreInc , (PType **)&TypeSInt32, [](auto *val) { val->IntVal += 1; return val; } },
{ PEX_PreInc , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal += 1; return val; } },
{ PEX_PreInc , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal += 1; return val; } },
{ PEX_PreDec , (PType **)&TypeSInt32, [](auto *val) { val->IntVal -= 1; return val; } },
{ PEX_PreDec , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal -= 1; return val; } },
{ PEX_PreDec , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal -= 1; return val; } },
{ PEX_Negate , (PType **)&TypeSInt32, [](auto *val) { val->IntVal = -val->IntVal; return val; } },
{ PEX_Negate , (PType **)&TypeFloat64, [](auto *val) { val->DoubleVal = -val->DoubleVal; return val; } },
{ PEX_AntiNegate , (PType **)&TypeSInt32, EvalIdentity },
{ PEX_AntiNegate , (PType **)&TypeUInt32, EvalIdentity },
{ PEX_AntiNegate , (PType **)&TypeFloat64, EvalIdentity },
{ PEX_BitNot , (PType **)&TypeSInt32, [](auto *val) { val->IntVal = ~val->IntVal; return val; } },
{ PEX_BitNot , (PType **)&TypeUInt32, [](auto *val) { val->UIntVal = ~val->UIntVal; return val; } },
{ PEX_BoolNot , (PType **)&TypeBool, [](auto *val) { val->IntVal = !val->IntVal; return val; } },
};
for (size_t i = 0; i < countof(UnaryOpInit); ++i)
{
ZCC_OpInfo[UnaryOpInit[i].Op].AddProto(*UnaryOpInit[i].Type, *UnaryOpInit[i].Type, UnaryOpInit[i].EvalConst);
}
// Binary operators
static const OpProto2 BinaryOpInit[] =
{
{ PEX_Add , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal += r->IntVal; return l; } },
{ PEX_Add , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal += r->UIntVal; return l; } },
{ PEX_Add , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal += r->DoubleVal; return l; } },
{ PEX_Sub , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal -= r->IntVal; return l; } },
{ PEX_Sub , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal -= r->UIntVal; return l; } },
{ PEX_Sub , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal -= r->DoubleVal; return l; } },
{ PEX_Mul , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal *= r->IntVal; return l; } },
{ PEX_Mul , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal *= r->UIntVal; return l; } },
{ PEX_Mul , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal *= r->DoubleVal; return l; } },
{ PEX_Div , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal /= r->IntVal; return l; } },
{ PEX_Div , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal /= r->UIntVal; return l; } },
{ PEX_Div , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal /= r->DoubleVal; return l; } },
{ PEX_Mod , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal %= r->IntVal; return l; } },
{ PEX_Mod , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal %= r->UIntVal; return l; } },
{ PEX_Mod , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = luai_nummod(l->DoubleVal, r->DoubleVal); return l; } },
{ PEX_Pow , (PType **)&TypeFloat64, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->DoubleVal = pow(l->DoubleVal, r->DoubleVal); return l; } },
{ PEX_Concat , (PType **)&TypeString, (PType **)&TypeString, (PType **)&TypeString, EvalConcat },
{ PEX_BitAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal &= r->IntVal; return l; } },
{ PEX_BitAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal &= r->UIntVal; return l; } },
{ PEX_BitOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal |= r->IntVal; return l; } },
{ PEX_BitOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal |= r->UIntVal; return l; } },
{ PEX_BitXor , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal ^= r->IntVal; return l; } },
{ PEX_BitXor , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal ^= r->UIntVal; return l; } },
{ PEX_BoolAnd , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal && r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_BoolAnd , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal && r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_BoolOr , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal || r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_BoolOr , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal || r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_LeftShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal <<= r->UIntVal; return l; } },
{ PEX_LeftShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal <<= r->UIntVal; return l; } },
{ PEX_RightShift , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal >>= r->UIntVal; return l; } },
{ PEX_RightShift , (PType **)&TypeUInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->UIntVal >>= r->UIntVal; return l; } },
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal < r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal < r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_LT , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal < r->DoubleVal; l->Type = TypeBool; return l; } },
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal <= r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal <= r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_LTEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal <= r->DoubleVal; l->Type = TypeBool; return l; } },
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeSInt32, (PType **)&TypeSInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->IntVal == r->IntVal; l->Type = TypeBool; return l; } },
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeUInt32, (PType **)&TypeUInt32, [](auto *l, auto *r, auto &) { l->IntVal = l->UIntVal == r->UIntVal; l->Type = TypeBool; return l; } },
{ PEX_EQEQ , (PType **)&TypeBool, (PType **)&TypeFloat64, (PType **)&TypeFloat64, [](auto *l, auto *r, auto &) { l->IntVal = l->DoubleVal == r->DoubleVal; l->Type = TypeBool; return l; } },
{ PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeSInt32, (PType **)&TypeSInt32, EvalLTGTEQSInt32 },
{ PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeUInt32, (PType **)&TypeUInt32, EvalLTGTEQUInt32 },
{ PEX_LTGTEQ , (PType **)&TypeSInt32, (PType **)&TypeFloat64, (PType **)&TypeFloat64, EvalLTGTEQFloat64 },
};
for (size_t i = 0; i < countof(BinaryOpInit); ++i)
{
ZCC_OpInfo[BinaryOpInit[i].Op].AddProto(*BinaryOpInit[i].Res, *BinaryOpInit[i].Ltype, *BinaryOpInit[i].Rtype, BinaryOpInit[i].EvalConst);
}
}
static void IntToS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
// Integers always fill out the full sized 32-bit field, so converting
// from a smaller sized integer to a 32-bit one is as simple as changing
// the type field.
expr->Type = TypeSInt32;
}
static void S32toS8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->IntVal = ((expr->IntVal << 24) >> 24);
expr->Type = TypeSInt8;
}
static void S32toS16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->IntVal = ((expr->IntVal << 16) >> 16);
expr->Type = TypeSInt16;
}
static void S32toU8(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->IntVal &= 0xFF;
expr->Type = TypeUInt8;
}
static void S32toU16(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->IntVal &= 0xFFFF;
expr->Type = TypeUInt16;
}
static void S32toU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->Type = TypeUInt32;
}
static void S32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->DoubleVal = expr->IntVal;
expr->Type = TypeFloat64;
}
static void DtoS32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->IntVal = (int)expr->DoubleVal;
expr->Type = TypeSInt32;
}
static void U32toD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->DoubleVal = expr->UIntVal;
expr->Type = TypeFloat64;
}
static void DtoU32(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
expr->UIntVal = (unsigned int)expr->DoubleVal;
expr->Type = TypeUInt32;
}
static void FtoD(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
// Constant single precision numbers are stored as doubles.
assert(expr->Type == TypeFloat32);
expr->Type = TypeFloat64;
}
static void DtoF(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
// Truncate double precision to single precision.
float poop = (float)expr->DoubleVal;
expr->DoubleVal = poop;
expr->Type = TypeFloat32;
}
static void S32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
char str[16];
int len = mysnprintf(str, countof(str), "%i", expr->IntVal);
expr->StringVal = str_arena.Alloc(str, len);
expr->Type = TypeString;
}
static void U32toS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
char str[16];
int len = mysnprintf(str, countof(str), "%u", expr->UIntVal);
expr->StringVal = str_arena.Alloc(str, len);
expr->Type = TypeString;
}
static void DtoS(ZCC_ExprConstant *expr, FSharedStringArena &str_arena)
{
// Convert to a string with enough precision such that converting
// back to a double will not lose any data.
char str[64];
IGNORE_FORMAT_PRE
int len = mysnprintf(str, countof(str), "%H", expr->DoubleVal);
IGNORE_FORMAT_POST
expr->StringVal = str_arena.Alloc(str, len);
expr->Type = TypeString;
}
//==========================================================================
//
// ZCC_InitConversions
//
//==========================================================================
void ZCC_InitConversions()
{
TypeUInt8->AddConversion(TypeSInt32, IntToS32);
TypeSInt8->AddConversion(TypeSInt32, IntToS32);
TypeUInt16->AddConversion(TypeSInt32, IntToS32);
TypeSInt16->AddConversion(TypeSInt32, IntToS32);
TypeUInt32->AddConversion(TypeSInt32, IntToS32);
TypeUInt32->AddConversion(TypeFloat64, U32toD);
TypeUInt32->AddConversion(TypeString, U32toS);
TypeSInt32->AddConversion(TypeUInt8, S32toU8);
TypeSInt32->AddConversion(TypeSInt8, S32toS8);
TypeSInt32->AddConversion(TypeSInt16, S32toS16);
TypeSInt32->AddConversion(TypeUInt16, S32toU16);
TypeSInt32->AddConversion(TypeUInt32, S32toU32);
TypeSInt32->AddConversion(TypeFloat64, S32toD);
TypeSInt32->AddConversion(TypeString, S32toS);
TypeFloat32->AddConversion(TypeFloat64, FtoD);
TypeFloat64->AddConversion(TypeUInt32, DtoU32);
TypeFloat64->AddConversion(TypeSInt32, DtoS32);
TypeFloat64->AddConversion(TypeFloat32, DtoF);
TypeFloat64->AddConversion(TypeString, DtoS);
}

View file

@ -0,0 +1,57 @@
// Name n-ary
xx(Nil, )
xx(ID, )
xx(Super, )
xx(Self, )
xx(ConstValue, )
xx(FuncCall, )
xx(ArrayAccess, )
xx(MemberAccess, )
xx(TypeRef, )
xx(PostInc, )
xx(PostDec, )
xx(PreInc, )
xx(PreDec, )
xx(Negate, )
xx(AntiNegate, )
xx(BitNot, )
xx(BoolNot, )
xx(SizeOf, )
xx(AlignOf, )
xx(Add, )
xx(Sub, )
xx(Mul, )
xx(Div, )
xx(Mod, )
xx(Pow, )
xx(CrossProduct, )
xx(DotProduct, )
xx(LeftShift, )
xx(RightShift, )
xx(Concat, )
xx(LT, )
xx(LTEQ, )
xx(LTGTEQ, )
xx(Is, )
xx(EQEQ, )
xx(APREQ, )
xx(BitAnd, )
xx(BitOr, )
xx(BitXor, )
xx(BoolAnd, )
xx(BoolOr, )
xx(Scope, )
xx(Trinary, )
xx(Cast, )
#undef xx

View file

@ -0,0 +1,412 @@
/*
** zcc_expr.cpp
**
**---------------------------------------------------------------------------
** Copyright -2016 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "dobject.h"
#include "sc_man.h"
#include "c_console.h"
#include "c_dispatch.h"
#include "w_wad.h"
#include "cmdlib.h"
#include "m_alloc.h"
#include "i_system.h"
#include "zcc_parser.h"
#include "zcc_compile.h"
static FString ZCCTokenName(int terminal);
#include "zcc-parse.h"
#include "zcc-parse.c"
struct TokenMapEntry
{
SWORD TokenType;
WORD TokenName;
TokenMapEntry(SWORD a, WORD b)
: TokenType(a), TokenName(b)
{ }
};
static TMap<SWORD, TokenMapEntry> TokenMap;
static SWORD BackTokenMap[YYERRORSYMBOL]; // YYERRORSYMBOL immediately follows the terminals described by the grammar
#define TOKENDEF2(sc, zcc, name) { TokenMapEntry tme(zcc, name); TokenMap.Insert(sc, tme); } BackTokenMap[zcc] = sc
#define TOKENDEF(sc, zcc) TOKENDEF2(sc, zcc, NAME_None)
static void InitTokenMap()
{
TOKENDEF ('=', ZCC_EQ);
TOKENDEF (TK_MulEq, ZCC_MULEQ);
TOKENDEF (TK_DivEq, ZCC_DIVEQ);
TOKENDEF (TK_ModEq, ZCC_MODEQ);
TOKENDEF (TK_AddEq, ZCC_ADDEQ);
TOKENDEF (TK_SubEq, ZCC_SUBEQ);
TOKENDEF (TK_LShiftEq, ZCC_LSHEQ);
TOKENDEF (TK_RShiftEq, ZCC_RSHEQ);
TOKENDEF (TK_AndEq, ZCC_ANDEQ);
TOKENDEF (TK_OrEq, ZCC_OREQ);
TOKENDEF (TK_XorEq, ZCC_XOREQ);
TOKENDEF ('?', ZCC_QUESTION);
TOKENDEF (':', ZCC_COLON);
TOKENDEF (TK_OrOr, ZCC_OROR);
TOKENDEF (TK_AndAnd, ZCC_ANDAND);
TOKENDEF (TK_Eq, ZCC_EQEQ);
TOKENDEF (TK_Neq, ZCC_NEQ);
TOKENDEF (TK_ApproxEq, ZCC_APPROXEQ);
TOKENDEF ('<', ZCC_LT);
TOKENDEF ('>', ZCC_GT);
TOKENDEF (TK_Leq, ZCC_LTEQ);
TOKENDEF (TK_Geq, ZCC_GTEQ);
TOKENDEF (TK_LtGtEq, ZCC_LTGTEQ);
TOKENDEF (TK_Is, ZCC_IS);
TOKENDEF (TK_DotDot, ZCC_DOTDOT);
TOKENDEF (TK_Ellipsis, ZCC_ELLIPSIS);
TOKENDEF ('|', ZCC_OR);
TOKENDEF ('^', ZCC_XOR);
TOKENDEF ('&', ZCC_AND);
TOKENDEF (TK_LShift, ZCC_LSH);
TOKENDEF (TK_RShift, ZCC_RSH);
TOKENDEF ('-', ZCC_SUB);
TOKENDEF ('+', ZCC_ADD);
TOKENDEF ('*', ZCC_MUL);
TOKENDEF ('/', ZCC_DIV);
TOKENDEF ('%', ZCC_MOD);
TOKENDEF (TK_Cross, ZCC_CROSSPROD);
TOKENDEF (TK_Dot, ZCC_DOTPROD);
TOKENDEF (TK_MulMul, ZCC_POW);
TOKENDEF (TK_Incr, ZCC_ADDADD);
TOKENDEF (TK_Decr, ZCC_SUBSUB);
TOKENDEF ('.', ZCC_DOT);
TOKENDEF ('(', ZCC_LPAREN);
TOKENDEF (')', ZCC_RPAREN);
TOKENDEF (TK_ColonColon, ZCC_SCOPE);
TOKENDEF (';', ZCC_SEMICOLON);
TOKENDEF (',', ZCC_COMMA);
TOKENDEF (TK_Class, ZCC_CLASS);
TOKENDEF (TK_Abstract, ZCC_ABSTRACT);
TOKENDEF (TK_Native, ZCC_NATIVE);
TOKENDEF (TK_Action, ZCC_ACTION);
TOKENDEF (TK_Replaces, ZCC_REPLACES);
TOKENDEF (TK_Static, ZCC_STATIC);
TOKENDEF (TK_Private, ZCC_PRIVATE);
TOKENDEF (TK_Protected, ZCC_PROTECTED);
TOKENDEF (TK_Latent, ZCC_LATENT);
TOKENDEF (TK_Final, ZCC_FINAL);
TOKENDEF (TK_Meta, ZCC_META);
TOKENDEF (TK_Deprecated, ZCC_DEPRECATED);
TOKENDEF (TK_ReadOnly, ZCC_READONLY);
TOKENDEF ('{', ZCC_LBRACE);
TOKENDEF ('}', ZCC_RBRACE);
TOKENDEF (TK_Struct, ZCC_STRUCT);
TOKENDEF (TK_Enum, ZCC_ENUM);
TOKENDEF2(TK_SByte, ZCC_SBYTE, NAME_sByte);
TOKENDEF2(TK_Byte, ZCC_BYTE, NAME_Byte);
TOKENDEF2(TK_Short, ZCC_SHORT, NAME_Short);
TOKENDEF2(TK_UShort, ZCC_USHORT, NAME_uShort);
TOKENDEF2(TK_Int, ZCC_INT, NAME_Int);
TOKENDEF2(TK_UInt, ZCC_UINT, NAME_uInt);
TOKENDEF2(TK_Bool, ZCC_BOOL, NAME_Bool);
TOKENDEF2(TK_Float, ZCC_FLOAT, NAME_Float);
TOKENDEF2(TK_Double, ZCC_DOUBLE, NAME_Double);
TOKENDEF2(TK_String, ZCC_STRING, NAME_String);
TOKENDEF2(TK_Vector, ZCC_VECTOR, NAME_Vector);
TOKENDEF2(TK_Name, ZCC_NAME, NAME_Name);
TOKENDEF2(TK_Map, ZCC_MAP, NAME_Map);
TOKENDEF2(TK_Array, ZCC_ARRAY, NAME_Array);
TOKENDEF (TK_Void, ZCC_VOID);
TOKENDEF (TK_True, ZCC_TRUE);
TOKENDEF (TK_False, ZCC_FALSE);
TOKENDEF ('[', ZCC_LBRACKET);
TOKENDEF (']', ZCC_RBRACKET);
TOKENDEF (TK_In, ZCC_IN);
TOKENDEF (TK_Out, ZCC_OUT);
TOKENDEF (TK_Optional, ZCC_OPTIONAL);
TOKENDEF (TK_Super, ZCC_SUPER);
TOKENDEF (TK_Self, ZCC_SELF);
TOKENDEF ('~', ZCC_TILDE);
TOKENDEF ('!', ZCC_BANG);
TOKENDEF (TK_SizeOf, ZCC_SIZEOF);
TOKENDEF (TK_AlignOf, ZCC_ALIGNOF);
TOKENDEF (TK_Continue, ZCC_CONTINUE);
TOKENDEF (TK_Break, ZCC_BREAK);
TOKENDEF (TK_Return, ZCC_RETURN);
TOKENDEF (TK_Do, ZCC_DO);
TOKENDEF (TK_For, ZCC_FOR);
TOKENDEF (TK_While, ZCC_WHILE);
TOKENDEF (TK_Until, ZCC_UNTIL);
TOKENDEF (TK_If, ZCC_IF);
TOKENDEF (TK_Else, ZCC_ELSE);
TOKENDEF (TK_Switch, ZCC_SWITCH);
TOKENDEF (TK_Case, ZCC_CASE);
TOKENDEF2(TK_Default, ZCC_DEFAULT, NAME_Default);
TOKENDEF (TK_Const, ZCC_CONST);
TOKENDEF (TK_Stop, ZCC_STOP);
TOKENDEF (TK_Wait, ZCC_WAIT);
TOKENDEF (TK_Fail, ZCC_FAIL);
TOKENDEF (TK_Loop, ZCC_LOOP);
TOKENDEF (TK_Goto, ZCC_GOTO);
TOKENDEF (TK_States, ZCC_STATES);
TOKENDEF (TK_State, ZCC_STATE);
TOKENDEF (TK_Color, ZCC_COLOR);
TOKENDEF (TK_Sound, ZCC_SOUND);
TOKENDEF (TK_Identifier, ZCC_IDENTIFIER);
TOKENDEF (TK_StringConst, ZCC_STRCONST);
TOKENDEF (TK_NameConst, ZCC_NAMECONST);
TOKENDEF (TK_IntConst, ZCC_INTCONST);
TOKENDEF (TK_UIntConst, ZCC_UINTCONST);
TOKENDEF (TK_FloatConst, ZCC_FLOATCONST);
TOKENDEF (TK_NonWhitespace, ZCC_NWS);
TOKENDEF (TK_Bright, ZCC_BRIGHT);
TOKENDEF (TK_Slow, ZCC_SLOW);
TOKENDEF (TK_Fast, ZCC_FAST);
TOKENDEF (TK_NoDelay, ZCC_NODELAY);
TOKENDEF (TK_Offset, ZCC_OFFSET);
TOKENDEF (TK_CanRaise, ZCC_CANRAISE);
TOKENDEF (TK_Light, ZCC_LIGHT);
ZCC_InitOperators();
ZCC_InitConversions();
}
#undef TOKENDEF
#undef TOKENDEF2
static void ParseSingleFile(const char *filename, void *parser, ZCCParseState &state)
{
int tokentype;
int lump;
//bool failed;
ZCCToken value;
FScanner sc;
lump = Wads.CheckNumForFullName(filename, true);
if (lump >= 0)
{
sc.OpenLumpNum(lump);
}
else
{
Printf("Could not find script lump '%s'\n", filename);
return;
}
state.sc = &sc;
while (sc.GetToken())
{
value.SourceLoc = sc.GetMessageLine();
switch (sc.TokenType)
{
case TK_StringConst:
value.String = state.Strings.Alloc(sc.String, sc.StringLen);
tokentype = ZCC_STRCONST;
break;
case TK_NameConst:
value.Int = sc.Name;
tokentype = ZCC_NAMECONST;
break;
case TK_IntConst:
value.Int = sc.Number;
tokentype = ZCC_INTCONST;
break;
case TK_UIntConst:
value.Int = sc.Number;
tokentype = ZCC_UINTCONST;
break;
case TK_FloatConst:
value.Float = sc.Float;
tokentype = ZCC_FLOATCONST;
break;
case TK_Identifier:
value.Int = FName(sc.String);
tokentype = ZCC_IDENTIFIER;
break;
case TK_NonWhitespace:
value.Int = FName(sc.String);
tokentype = ZCC_NWS;
break;
default:
TokenMapEntry *zcctoken = TokenMap.CheckKey(sc.TokenType);
if (zcctoken != nullptr)
{
tokentype = zcctoken->TokenType;
value.Int = zcctoken->TokenName;
}
else
{
sc.ScriptMessage("Unexpected token %s.\n", sc.TokenName(sc.TokenType).GetChars());
goto parse_end;
}
break;
}
ZCCParse(parser, tokentype, value, &state);
}
parse_end:
value.Int = -1;
ZCCParse(parser, ZCC_EOF, value, &state);
state.sc = nullptr;
}
static void DoParse(int lumpnum)
{
if (TokenMap.CountUsed() == 0)
{
InitTokenMap();
}
FScanner sc;
void *parser;
ZCCToken value;
parser = ZCCParseAlloc(malloc);
ZCCParseState state;
#ifdef _DEBUG
FILE *f = fopen("trace.txt", "w");
char prompt = '\0';
ZCCParseTrace(f, &prompt);
#endif
sc.OpenLumpNum(lumpnum);
// parse all files from this list in one go.
while (sc.GetString())
{
if (Wads.GetLumpFile(sc.LumpNum) == 0)
{
int includefile = Wads.GetLumpFile(Wads.CheckNumForFullName(sc.String, true));
if (includefile != 0)
{
I_FatalError("File %s is overriding core lump %s.",
Wads.GetWadFullName(includefile), sc.String);
}
}
ParseSingleFile(sc.String, parser, state);
}
value.Int = -1;
value.SourceLoc = sc.GetMessageLine();
ZCCParse(parser, 0, value, &state);
ZCCParseFree(parser, free);
{
// Make a dump of the AST before running the compiler for diagnostic purposes.
#ifdef _DEBUG
if (f != NULL)
{
fclose(f);
}
FString ast = ZCC_PrintAST(state.TopNode);
FString filename = Wads.GetLumpFullName(lumpnum);
FString astfile = ExtractFileBase(filename, false);
astfile << "-before.ast";
f = fopen(astfile, "w");
if (f != NULL)
{
fputs(ast.GetChars(), f);
fclose(f);
}
#endif
}
PSymbolTable symtable;
symtable.SetName("Global_Node");
ZCCCompiler cc(state, NULL, symtable, GlobalSymbols);
cc.Compile();
}
void ParseScripts()
{
int lump, lastlump = 0;
while ((lump = Wads.FindLump("ZSCRIPT", &lastlump)) != -1)
{
DoParse(lump);
}
}
/*
CCMD(parse)
{
if (argv.argc() == 2)
{
DoParse(argv[1]);
}
}
*/
static FString ZCCTokenName(int terminal)
{
if (terminal == ZCC_EOF)
{
return "end of file";
}
int sc_token;
if (terminal > 0 && terminal < (int)countof(BackTokenMap))
{
sc_token = BackTokenMap[terminal];
if (sc_token == 0)
{ // This token was not initialized. Whoops!
sc_token = -terminal;
}
}
else
{ // This should never happen.
sc_token = -terminal;
}
return FScanner::TokenName(sc_token);
}
ZCC_TreeNode *ZCC_AST::InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis)
{
ZCC_TreeNode *node = (ZCC_TreeNode *)SyntaxArena.Alloc(size);
node->SiblingNext = node;
node->SiblingPrev = node;
node->NodeType = type;
if (basis != NULL)
{
node->SourceName = basis->SourceName;
node->SourceLoc = basis->SourceLoc;
}
return node;
}
ZCC_TreeNode *ZCCParseState::InitNode(size_t size, EZCCTreeNodeType type)
{
ZCC_TreeNode *node = ZCC_AST::InitNode(size, type, NULL);
node->SourceName = Strings.Alloc(sc->ScriptName);
return node;
}

View file

@ -0,0 +1,564 @@
#ifndef ZCC_PARSER_H
#define ZCC_PARSER_H
#include "memarena.h"
#include "sc_man.h"
struct ZCCToken
{
union
{
int Int;
double Float;
FString *String;
};
int SourceLoc;
ENamedName Name() { return ENamedName(Int); }
};
// Variable / Function / Class modifiers
enum
{
ZCC_Native = 1 << 0,
ZCC_Static = 1 << 1,
ZCC_Private = 1 << 2,
ZCC_Protected = 1 << 3,
ZCC_Latent = 1 << 4,
ZCC_Final = 1 << 5,
ZCC_Meta = 1 << 6,
ZCC_Action = 1 << 7,
ZCC_Deprecated = 1 << 8,
ZCC_ReadOnly = 1 << 9,
ZCC_FuncConst = 1 << 10,
ZCC_Abstract = 1 << 11,
};
// Function parameter modifiers
enum
{
ZCC_In = 1 << 0,
ZCC_Out = 1 << 1,
ZCC_Optional = 1 << 2,
};
// Syntax tree structures.
enum EZCCTreeNodeType
{
AST_Identifier,
AST_Class,
AST_Struct,
AST_Enum,
AST_EnumTerminator,
AST_States,
AST_StatePart,
AST_StateLabel,
AST_StateStop,
AST_StateWait,
AST_StateFail,
AST_StateLoop,
AST_StateGoto,
AST_StateLine,
AST_VarName,
AST_Type,
AST_BasicType,
AST_MapType,
AST_DynArrayType,
AST_ClassType,
AST_Expression,
AST_ExprID,
AST_ExprTypeRef,
AST_ExprConstant,
AST_ExprFuncCall,
AST_ExprMemberAccess,
AST_ExprUnary,
AST_ExprBinary,
AST_ExprTrinary,
AST_FuncParm,
AST_Statement,
AST_CompoundStmt,
AST_ContinueStmt,
AST_BreakStmt,
AST_ReturnStmt,
AST_ExpressionStmt,
AST_IterationStmt,
AST_IfStmt,
AST_SwitchStmt,
AST_CaseStmt,
AST_AssignStmt,
AST_LocalVarStmt,
AST_FuncParamDecl,
AST_ConstantDef,
AST_Declarator,
AST_VarDeclarator,
AST_FuncDeclarator,
AST_Default,
AST_FlagStmt,
AST_PropertyStmt,
NUM_AST_NODE_TYPES
};
enum EZCCBuiltinType
{
ZCC_SInt8,
ZCC_UInt8,
ZCC_SInt16,
ZCC_UInt16,
ZCC_SInt32,
ZCC_UInt32,
ZCC_IntAuto, // for enums, autoselect appropriately sized int
ZCC_Bool,
ZCC_Float32,
ZCC_Float64,
ZCC_FloatAuto, // 32-bit in structs/classes, 64-bit everywhere else
ZCC_String,
ZCC_Vector2,
ZCC_Vector3,
ZCC_Vector4,
ZCC_Name,
ZCC_Color, // special types for ZDoom.
ZCC_State,
ZCC_Sound,
ZCC_UserType,
ZCC_NUM_BUILT_IN_TYPES
};
enum EZCCExprType
{
#define xx(a,z) PEX_##a,
#include "zcc_exprlist.h"
PEX_COUNT_OF
};
struct ZCC_TreeNode
{
// This tree node's siblings are stored in a circular linked list.
// When you get back to this node, you know you've been through
// the whole list.
ZCC_TreeNode *SiblingNext;
ZCC_TreeNode *SiblingPrev;
// can't use FScriptPosition, because the string wouldn't have a chance to
// destruct if we did that.
FString *SourceName;
int SourceLoc;
// Node type is one of the node types above, which corresponds with
// one of the structures below.
EZCCTreeNodeType NodeType;
// Appends a sibling to this node's sibling list.
void AppendSibling(ZCC_TreeNode *sibling)
{
if (sibling == NULL)
{
return;
}
// Check integrity of our sibling list.
assert(SiblingPrev->SiblingNext == this);
assert(SiblingNext->SiblingPrev == this);
// Check integrity of new sibling list.
assert(sibling->SiblingPrev->SiblingNext == sibling);
assert(sibling->SiblingNext->SiblingPrev == sibling);
ZCC_TreeNode *siblingend = sibling->SiblingPrev;
SiblingPrev->SiblingNext = sibling;
sibling->SiblingPrev = SiblingPrev;
SiblingPrev = siblingend;
siblingend->SiblingNext = this;
}
operator FScriptPosition()
{
return FScriptPosition(*SourceName, SourceLoc);
}
};
struct ZCC_Identifier : ZCC_TreeNode
{
ENamedName Id;
};
struct ZCC_NamedNode : ZCC_TreeNode
{
ENamedName NodeName;
PSymbolType *Symbol;
};
struct ZCC_Class : ZCC_NamedNode
{
ZCC_Identifier *ParentName;
ZCC_Identifier *Replaces;
VM_UWORD Flags;
ZCC_TreeNode *Body;
PClass *Type;
};
struct ZCC_Struct : ZCC_NamedNode
{
ZCC_TreeNode *Body;
PStruct *Type;
};
struct ZCC_Enum : ZCC_NamedNode
{
EZCCBuiltinType EnumType;
struct ZCC_ConstantDef *Elements;
};
struct ZCC_EnumTerminator : ZCC_TreeNode
{
};
struct ZCC_States : ZCC_TreeNode
{
struct ZCC_StatePart *Body;
};
struct ZCC_StatePart : ZCC_TreeNode
{
};
struct ZCC_StateLabel : ZCC_StatePart
{
ENamedName Label;
};
struct ZCC_StateStop : ZCC_StatePart
{
};
struct ZCC_StateWait : ZCC_StatePart
{
};
struct ZCC_StateFail : ZCC_StatePart
{
};
struct ZCC_StateLoop : ZCC_StatePart
{
};
struct ZCC_Expression : ZCC_TreeNode
{
EZCCExprType Operation;
PType *Type;
// Repurposes this node as an error node
void ToErrorNode()
{
Type = TypeError;
Operation = PEX_Nil;
NodeType = AST_Expression;
}
};
struct ZCC_StateGoto : ZCC_StatePart
{
ZCC_Identifier *Qualifier;
ZCC_Identifier *Label;
ZCC_Expression *Offset;
};
struct ZCC_StateLine : ZCC_StatePart
{
FString *Sprite;
BITFIELD bBright : 1;
BITFIELD bFast : 1;
BITFIELD bSlow : 1;
BITFIELD bNoDelay : 1;
BITFIELD bCanRaise : 1;
FString *Frames;
ZCC_Expression *Duration;
ZCC_Expression *Offset;
ZCC_ExprConstant *Lights;
ZCC_TreeNode *Action;
};
struct ZCC_VarName : ZCC_TreeNode
{
ENamedName Name;
ZCC_Expression *ArraySize; // NULL if not an array
};
struct ZCC_Type : ZCC_TreeNode
{
ZCC_Expression *ArraySize; // NULL if not an array
};
struct ZCC_BasicType : ZCC_Type
{
EZCCBuiltinType Type;
ZCC_Identifier *UserType;
};
struct ZCC_MapType : ZCC_Type
{
ZCC_Type *KeyType;
ZCC_Type *ValueType;
};
struct ZCC_DynArrayType : ZCC_Type
{
ZCC_Type *ElementType;
};
struct ZCC_ClassType : ZCC_Type
{
ZCC_Identifier *Restriction;
};
struct ZCC_ExprID : ZCC_Expression
{
ENamedName Identifier;
};
struct ZCC_ExprTypeRef : ZCC_Expression
{
PType *RefType;
};
struct ZCC_ExprConstant : ZCC_Expression
{
union
{
FString *StringVal;
int IntVal;
unsigned int UIntVal;
double DoubleVal;
};
};
struct ZCC_FuncParm : ZCC_TreeNode
{
ZCC_Expression *Value;
ENamedName Label;
};
struct ZCC_ExprFuncCall : ZCC_Expression
{
ZCC_Expression *Function;
ZCC_FuncParm *Parameters;
};
struct ZCC_ExprMemberAccess : ZCC_Expression
{
ZCC_Expression *Left;
ENamedName Right;
};
struct ZCC_ExprUnary : ZCC_Expression
{
ZCC_Expression *Operand;
};
struct ZCC_ExprBinary : ZCC_Expression
{
ZCC_Expression *Left;
ZCC_Expression *Right;
};
struct ZCC_ExprTrinary : ZCC_Expression
{
ZCC_Expression *Test;
ZCC_Expression *Left;
ZCC_Expression *Right;
};
struct ZCC_Statement : ZCC_TreeNode
{
};
struct ZCC_CompoundStmt : ZCC_Statement
{
ZCC_Statement *Content;
};
struct ZCC_ContinueStmt : ZCC_Statement
{
};
struct ZCC_BreakStmt : ZCC_Statement
{
};
struct ZCC_ReturnStmt : ZCC_Statement
{
ZCC_Expression *Values;
};
struct ZCC_ExpressionStmt : ZCC_Statement
{
ZCC_Expression *Expression;
};
struct ZCC_IterationStmt : ZCC_Statement
{
ZCC_Expression *LoopCondition;
ZCC_Statement *LoopStatement;
ZCC_Statement *LoopBumper;
// Should the loop condition be checked at the
// start of the loop (before the LoopStatement)
// or at the end (after the LoopStatement)?
enum { Start, End } CheckAt;
};
struct ZCC_IfStmt : ZCC_Statement
{
ZCC_Expression *Condition;
ZCC_Statement *TruePath;
ZCC_Statement *FalsePath;
};
struct ZCC_SwitchStmt : ZCC_Statement
{
ZCC_Expression *Condition;
ZCC_Statement *Content;
};
struct ZCC_CaseStmt : ZCC_Statement
{
// A NULL Condition represents the default branch
ZCC_Expression *Condition;
};
struct ZCC_AssignStmt : ZCC_Statement
{
ZCC_Expression *Dests;
ZCC_Expression *Sources;
int AssignOp;
};
struct ZCC_LocalVarStmt : ZCC_Statement
{
ZCC_Type *Type;
ZCC_VarName *Vars;
ZCC_Expression *Inits;
};
struct ZCC_FuncParamDecl : ZCC_TreeNode
{
ZCC_Type *Type;
ZCC_Expression *Default;
ENamedName Name;
int Flags;
};
struct ZCC_ConstantDef : ZCC_NamedNode
{
ZCC_Expression *Value;
PSymbolConst *Symbol;
ZCC_Enum *Type; // gets set when the constant originates from an enum.
};
struct ZCC_Declarator : ZCC_TreeNode
{
ZCC_Type *Type;
int Flags;
};
// A variable in a class or struct.
struct ZCC_VarDeclarator : ZCC_Declarator
{
ZCC_VarName *Names;
};
// A function in a class.
struct ZCC_FuncDeclarator : ZCC_Declarator
{
ZCC_FuncParamDecl *Params;
ENamedName Name;
ZCC_Statement *Body;
};
struct ZCC_Default : ZCC_CompoundStmt
{
};
struct ZCC_PropertyStmt : ZCC_Statement
{
ZCC_Identifier *Prop;
ZCC_Expression *Values;
};
struct ZCC_FlagStmt : ZCC_Statement
{
ZCC_Identifier *name;
bool set;
};
typedef ZCC_ExprConstant *(*EvalConst1op)(ZCC_ExprConstant *);
typedef ZCC_ExprConstant *(*EvalConst2op)(ZCC_ExprConstant *, ZCC_ExprConstant *, FSharedStringArena &);
struct ZCC_OpProto
{
ZCC_OpProto *Next;
PType *ResType;
PType *Type1;
PType *Type2;
union
{
EvalConst1op EvalConst1;
EvalConst2op EvalConst2;
};
ZCC_OpProto(PType *res, PType *t1, PType *t2)
: ResType(res), Type1(t1), Type2(t2) {}
};
struct ZCC_OpInfoType
{
const char *OpName;
ZCC_OpProto *Protos;
void AddProto(PType *res, PType *optype, EvalConst1op evalconst);
void AddProto(PType *res, PType *left, PType *right, EvalConst2op evalconst);
ZCC_OpProto *FindBestProto(PType *optype, const PType::Conversion **route, int &numslots);
ZCC_OpProto *FindBestProto(PType *left, const PType::Conversion **route1, int &numslots,
PType *right, const PType::Conversion **route2, int &numslots2);
void FreeAllProtos();
};
#define CONVERSION_ROUTE_SIZE 8
FString ZCC_PrintAST(ZCC_TreeNode *root);
void ZCC_InitOperators();
extern ZCC_OpInfoType ZCC_OpInfo[PEX_COUNT_OF];
struct ZCC_AST
{
ZCC_AST() : TopNode(NULL) {}
ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type, ZCC_TreeNode *basis);
FSharedStringArena Strings;
FMemArena SyntaxArena;
struct ZCC_TreeNode *TopNode;
};
struct ZCCParseState : public ZCC_AST
{
ZCCParseState(FScanner *scanner = nullptr) : sc(scanner) {}
ZCC_TreeNode *InitNode(size_t size, EZCCTreeNodeType type);
FScanner *sc;
};
#endif