Skip to content
This repository has been archived by the owner on Aug 23, 2023. It is now read-only.

Commit

Permalink
parsed upto Terrain
Browse files Browse the repository at this point in the history
  • Loading branch information
corwinn committed Feb 22, 2023
1 parent c6324c8 commit e95e677
Show file tree
Hide file tree
Showing 8 changed files with 688 additions and 101 deletions.
16 changes: 8 additions & 8 deletions map_grammar
Original file line number Diff line number Diff line change
Expand Up @@ -374,13 +374,13 @@ struct PlayerCanPlay
byte AllowedFactions
bool RandomFaction
bool HasMainTown
bool GenAtMT (HasMainTown && Version != ROE)
bool Gen2 (HasMainTown && Version != ROE) // No idea whats this
bool GenAtMT (HasMainTown && (Version != ROE))
bool Gen2 (HasMainTown && (Version != ROE)) // No idea whats this
Location MainTown (HasMainTown)
bool RandomHero
byte CutomHeroId
byte CutomHeroPortrait (CutomHeroId != MAP_DEFAULT_HERO_ID)
byte CutomHeroName (CutomHeroId != MAP_DEFAULT_HERO_ID)
MapString CutomHeroName (CutomHeroId != MAP_DEFAULT_HERO_ID)
byte NoIdea (Version != ROE)
AllowedHero AllowedHeroes[int] (Version != ROE)

Expand Down Expand Up @@ -526,21 +526,21 @@ format h3m
WinCondition SpecialWCon
LooseCondition SpecialLCon
//
byte Teams
byte Team[MAP_PLAYERS]
byte HasTeams
byte Team[MAP_PLAYERS] (HasTeams)
//
byte AllowedHeroes[16] (Version == ROE)
byte AllowedHeroes[20] (Version != ROE)
byte AllowedHeroesNoIdea[int] (Version > ROE)
//
NoIdeaHero MysteriousHeroes[byte]
NoIdeaHero MysteriousHeroes[byte] (Version >= SOD)
byte Unk1[31]
//
byte AllowedArtifacts[17] (Version == AB)
byte AllowedArtifacts[18] (Version > AB)
//
byte AllowedSpells[9]
byte AllowedAbilities[4]
byte AllowedSpells[9] (Version >= SOD)
byte AllowedAbilities[4] (Version >= SOD)
//
Rumor Rumors[int]
//
Expand Down
137 changes: 86 additions & 51 deletions utils/h3r_ffd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,9 @@ bool FFD::SNode::ParseMachType(FFDParser & parser)
if (parser.IsEol ()) return true; // completed
// There could be an expression
parser.SkipLineWhitespace ();
if (parser.AtExprStart ()) {
Expr = static_cast<String &&>(parser.ReadExpression ());
Dbg << "MachType: Expr: " << Expr << EOL;
}
if (parser.AtExprStart ())
Expr = static_cast<List<FFDParser::ExprToken> &&>(
parser.TokenizeExpression ());
// There could be a comment. But it is handled elsewhere for now.
return true;
}// FFD::SNode::ParseMachType()
Expand Down Expand Up @@ -220,10 +219,9 @@ bool FFD::SNode::ParseCompositeField(FFDParser & parser, int j)
Dbg << "Field: composite. DTypeName: " << DTypeName << EOL;
if (parser.IsEol ()) return true;
parser.SkipLineWhitespace ();
if (parser.AtExprStart ()) {
Expr = static_cast<String &&>(parser.ReadExpression ());
Dbg << "Field: composite. Expr: " << Expr << EOL;
}
if (parser.AtExprStart ())
Expr = static_cast<List<FFDParser::ExprToken> &&>(
parser.TokenizeExpression ());
// comment(s) and whitespace are handled by FFD::SNode::ParseField()
return true;
}
Expand Down Expand Up @@ -305,8 +303,20 @@ bool FFD::SNode::ParseField(FFDParser & parser)
H3R_ENSURE_FFD(! parser.IsEol (), "Incomplete array") // [EOL
Array = true;
for (int arr = 0; arr < 3; arr++) {
Arr[arr] = static_cast<String &&>(parser.ReadArrDim ());
Dbg << "Field: array[" << arr << "]=" << Arr[arr] << EOL;
if (parser.SymbolValid1st ())
Arr[arr].Name =
static_cast<String &&>(parser.ReadArrDim ());
else { // int literal; allow line whitespace around it
if (parser.IsLineWhitespace ()) // trim start
parser.SkipLineWhitespace ();
Arr[arr].Value = parser.ParseIntLiteral ();
if (parser.IsLineWhitespace ()) // trim end
parser.SkipLineWhitespace ();
H3R_ENSURE(parser.AtArrEnd (), "wrong arr dim")
parser.SkipOneByte (); // ']'.Next()
}
Dbg << "Field: array[" << arr << "]= ";
Arr[arr].DbgPrint (); Dbg << EOL;
if (! parser.HasMoreData ()) break; // foo[.*]EOF
if (! parser.AtArrStart ()) break;
else {
Expand All @@ -325,10 +335,9 @@ bool FFD::SNode::ParseField(FFDParser & parser)
if (! parser.HasMoreData ()) return true;
if (parser.IsEol ()) { parser.SkipEol () ; return true; }
parser.SkipLineWhitespace ();
if (parser.AtExprStart ()) {
Expr = static_cast<String &&>(parser.ReadExpression ());
Dbg << "Field: expr: " << Expr << EOL;
}
if (parser.AtExprStart ())
Expr = static_cast<List<FFDParser::ExprToken> &&>(
parser.TokenizeExpression ());
parser.SkipCommentWhitespaceSequence ();
return true;
}// FFD::SNode::ParseField()
Expand Down Expand Up @@ -356,10 +365,9 @@ bool FFD::SNode::ParseConst(FFDParser & parser)
}
if (parser.IsEol ()) { parser.SkipEol (); return true; }
parser.SkipLineWhitespace ();
if (parser.AtExprStart ()) {
Expr = static_cast<String &&>(parser.ReadExpression ());
Dbg << "Const: expr: " << Expr << EOL;
}
if (parser.AtExprStart ())
Expr = static_cast<List<FFDParser::ExprToken> &&>(
parser.TokenizeExpression ());
else
parser.SkipCommentWhitespaceSequence ();
return true;
Expand All @@ -385,10 +393,9 @@ bool FFD::SNode::ParseEnum(FFDParser & parser)
if (parser.IsEol ())
parser.SkipEol ();
else {
if (parser.AtExprStart ()) {
Expr = static_cast<String &&>(parser.ReadExpression ());
Dbg << "Enum: expr: " << Expr << EOL;
}
if (parser.AtExprStart ())
Expr = static_cast<List<FFDParser::ExprToken> &&>(
parser.TokenizeExpression ());
H3R_ENSURE_FFD(parser.HasMoreData (), "Incomplete enum") // foo.*)EOF
parser.SkipCommentWhitespaceSequence ();
}
Expand All @@ -408,10 +415,9 @@ bool FFD::SNode::ParseEnum(FFDParser & parser)
if (parser.IsEol ())
parser.SkipEol ();
else {
if (parser.AtExprStart ()) {
itm.Expr = static_cast<String &&>(parser.ReadExpression ());
Dbg << "EnumItem: expr: " << itm.Expr << EOL;
}
if (parser.AtExprStart ())
itm.Expr = static_cast<List<FFDParser::ExprToken> &&>(
parser.TokenizeExpression ());
else
parser.SkipCommentWhitespaceSequence ();
}
Expand Down Expand Up @@ -445,38 +451,65 @@ FFD::SNode * FFD::SNode::NodeByName(const String & query)
{
FFD::SNode * result = {};
WalkBackwards([&](FFD::SNode * node) {
if (node->Name == query) { result = node; return false; }
if (node->Name == query && node->Usable ()) {
result = node;
return false;
}
return true;
});
if (nullptr == result)
WalkForward([&](FFD::SNode * node) {
if (node->Name == query) { result = node; return false; }
if (nullptr == result && Next)
Next->WalkForward([&](FFD::SNode * node) {
if (node->Name == query && node->Usable ()) {
result = node;
return false;
}
return true;
});
return result;
}

FFD::EnumItem * FFD::SNode::FindEnumItem(const String & name)
{//TODO enum.Expr > 0
for (int i = 0; i < EnumItems.Count (); i++)
if (EnumItems[i].Name == name) return &(EnumItems[i]);
return nullptr;
}

List<FFD::SNode *> FFD::SNode::NodesByName(const String & query)
{
List<FFD::SNode *> result = {};
WalkBackwards([&](FFD::SNode * node) {
if (node->Name == query) result.Add (node);
return true;
});
if (Next)
Next->WalkForward([&](FFD::SNode * node) {
if (node->Name == query) result.Add (node);
return true;
});
return static_cast<List<FFD::SNode *> &&>(result);
}

// Debug purposes
static void print_node(FFD::SNode * n)
void FFD::SNode::DbgPrint()
{
Dbg << "+" << n->TypeToString () << ": ";
if (nullptr == n) { Dbg << "[null]" << EOL; return; }
if (n->HashKey) Dbg << "[hk]";
if (n->Array) Dbg << "[arr]";
if (n->Variadic) Dbg << "[var]";
if (n->VListItem) Dbg << "[vli]";
if (n->Composite) Dbg << "[comp]";
if (n->Signed) Dbg << "[signed]";
if (n->IsAttribute ())
Dbg << " Value: \"" << n->Attribute << "\"";
Dbg << "+" << TypeToString () << ": ";
if (HashKey) Dbg << "[hk]";
if (Array) Dbg << "[arr]";
if (Variadic) Dbg << "[var]";
if (VListItem) Dbg << "[vli]";
if (Composite) Dbg << "[comp]";
if (Signed) Dbg << "[signed]";
if (IsAttribute ())
Dbg << " Value: \"" << Attribute << "\"";
else
Dbg << " Name: \"" << n->Name << "\"";
Dbg << " Name: \"" << Name << "\"";
Dbg << ", DType: \"";
if (nullptr == n->DType) {
if (! n->NoDType ())
Dbg << "unresolved:" << n->DTypeName;
if (nullptr == DType) {
if (! NoDType ())
Dbg << "unresolved:" << DTypeName;
}
else Dbg << n->DType->Name;
else Dbg << DType->Name;
Dbg << "\"" << EOL;
}
static void print_tree(FFD::SNode * n)
Expand All @@ -487,9 +520,11 @@ static void print_tree(FFD::SNode * n)
}
Dbg << "The tree:" << EOL;
n->WalkForward ([&](FFD::SNode * n) -> bool {
print_node (n);
if (nullptr == n) { Dbg << "+[null]" << EOL; return true; }
n->DbgPrint ();
for (auto sn : n->Fields) {
Dbg << " "; print_node (sn);
if (nullptr == sn) { Dbg << "+[null]" << EOL; continue; }
Dbg << " "; sn->DbgPrint ();
}
return true;
});
Expand Down Expand Up @@ -578,7 +613,7 @@ static void resolve_all_types(FFD::SNode * n)
int h, usize, size = static_cast<int>(fh2.Size ());
Stream::Read (fh2, &h);
if (h != 0x88b1f)
Log::Info ("Unknown map format. Load could fail.");
Dbg << "Unknown map format. Load could fail." << EOL;
else {
Stream::Read (fh2.End ().Seek (-4), &usize);
H3R_ENSURE(usize > size && usize < H3M_MAX_FILE_SIZE,
Expand All @@ -592,10 +627,10 @@ static void resolve_all_types(FFD::SNode * n)
}
}
else
Log::Info ("zlibMapStream not found. Load could fail.");
Dbg << "zlibMapStream not found. Load could fail." << EOL;

FFDNode * data_root {};
Log::Info (String::Format ("Parsing %s" EOL, f.AsZStr ()));
Dbg << "Parsing " << f << EOL;
H3R_CREATE_OBJECT(data_root, FFDNode) {ffd._root, s};
if (s != &fh2) H3R_DESTROY_OBJECT(s, Stream)
return data_root;
Expand Down
70 changes: 65 additions & 5 deletions utils/h3r_ffd.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,20 @@ class FFD
{
public String Name {};
public int Value {};
public String Expr {};
public List<FFDParser::ExprToken> Expr {};
public bool Enabled {};
};
public class ArrDimItem final
{
public String Name {}; // Empty when Value is used
public int Value {}; // 0 when Name is used
public inline bool None() { return Name.Empty () && Value <= 0; }
public inline void DbgPrint()
{
if (None ()) return;
if (Value > 0) Dbg << "intlit: " << Value;
else Dbg << "symbol: " << Name;
}
};
// Syntax node - these are created as a result of parsing the description.
// Its concatenation of SType. It could become class hierarchy.
Expand All @@ -95,7 +108,13 @@ class FFD
if (nullptr == Prev) return;
Prev->WalkBackwards (on_node);
}
private SNode * NodeByName(const String &);

// Returns Usable() only! Means the SNode is enabled, and doesn't need
// evaluation.
public SNode * NodeByName(const String &);
// Returns all that match the name, regardless of flags.
public List<SNode *> NodesByName(const String &);

// Call after all nodes are parsed. Allows for dependency-independent
// order of things at the description.
public void ResolveTypes();
Expand All @@ -113,14 +132,14 @@ class FFD
public SNode * DType {}; // Data/dynamic type (Expr: resolved on parse)
public String DTypeName {}; // Prior resolve
public List<SNode *> Fields {};
public String Expr {};
public List<FFDParser::ExprToken> Expr {};
public String Comment {};

public bool HashKey {};
public String HashType {};

public bool Array {}; // Is it an array
public String Arr[3];
public ArrDimItem Arr[3] {};

public bool Variadic {}; // "..." Type == SType::Field
public bool VListItem {}; // Struct foo:value-list ; "foo" is at "Name"
Expand All @@ -132,12 +151,20 @@ class FFD
public String StringLiteral {};
public int IntLiteral {};

public bool Enabled {}; // true when Expr has evaluated to it
public bool Resolved {}; // true when Expr has been evaluated
public bool inline Usable() const
{
return Expr.Count () <= 0 || (Resolved && Enabled);
}

// Type == SType::MachType
public bool Signed {};
public int Size {};
// public SNode * Alias {}; // This could become useful later

public List<EnumItem> EnumItems {};
public EnumItem * FindEnumItem(const String &);

public bool Parse(FFDParser &);
public bool ParseMachType(FFDParser &);
Expand Down Expand Up @@ -173,6 +200,10 @@ class FFD
}
public inline bool IsEnum() const { return SType::Enum == Type; }
public inline bool IsField() const { return SType::Field == Type; }
public inline bool IsIntConst() const
{
return SType::Const == Type && SConstType::Int == Const;
}
// By value. Allow many attributes for custom extensions.
public SNode * GetAttr(const String & query)
{
Expand All @@ -196,7 +227,36 @@ class FFD
default: return "Unhandled";
};
}
public inline bool HasExpr() const { return ! Expr.Empty (); }
public inline bool HasExpr() const { return Expr.Count () > 0; }
public void DbgPrint();
// where there are no dynamic arrays and expressions
public int PrecomputeSize()
{
int result {};
for (auto f : Fields) {
if (! f->DType) return 0;
if (! f->Expr.Empty ()) return 0;
if (f->DType->IsStruct ()) return 0;
if (f->Array) {
int arr_result = 1, i {};
for (; i < 3 && ! Arr[i].None (); i++) {
if (! f->Arr[i].Name.Empty ()) {
H3R_ENSURE(nullptr != Base, "array node w/o Base?")
auto n = Base->NodeByName (f->Arr[i].Name);
if (n && ! n->IsIntConst ()) return 0;
arr_result *= n->IntLiteral;
}
else
arr_result *= f->Arr[i].Value;
}
H3R_ENSURE(i > 0, "array node w/o dimensions?")
result += arr_result;
}
else
result += f->DType->Size;
}
return result;
}// PrecomputeSize()
};// SNode

private SNode * _root {};
Expand Down

0 comments on commit e95e677

Please sign in to comment.