mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-03-24 00:13:48 +08:00
3557 lines
136 KiB
C++
3557 lines
136 KiB
C++
/***********************************************************************
|
|
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
|
|
DEVELOPER: Zihan Chen(vczh)
|
|
***********************************************************************/
|
|
#include "VlppReflection.h"
|
|
#include "VlppOS.h"
|
|
#include "Vlpp.h"
|
|
#include "VlppRegex.h"
|
|
|
|
/***********************************************************************
|
|
.\PARSINGTREE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_PARSINGTREE
|
|
#define VCZH_PARSING_PARSINGTREE
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
|
|
/***********************************************************************
|
|
Location
|
|
***********************************************************************/
|
|
|
|
/// <summary>A type representing text position.</summary>
|
|
struct ParsingTextPos
|
|
{
|
|
static const vint UnknownValue=-2;
|
|
/// <summary>Character index, begins at 0.</summary>
|
|
vint index;
|
|
/// <summary>Row number, begins at 0.</summary>
|
|
vint row;
|
|
/// <summary>Column number, begins at 0.</summary>
|
|
vint column;
|
|
|
|
ParsingTextPos()
|
|
:index(UnknownValue)
|
|
,row(UnknownValue)
|
|
,column(UnknownValue)
|
|
{
|
|
}
|
|
|
|
ParsingTextPos(vint _index)
|
|
:index(_index)
|
|
,row(UnknownValue)
|
|
,column(UnknownValue)
|
|
{
|
|
}
|
|
|
|
ParsingTextPos(vint _row, vint _column)
|
|
:index(UnknownValue)
|
|
,row(_row)
|
|
,column(_column)
|
|
{
|
|
}
|
|
|
|
ParsingTextPos(vint _index, vint _row, vint _column)
|
|
:index(_index)
|
|
,row(_row)
|
|
,column(_column)
|
|
{
|
|
}
|
|
|
|
/// <summary>Test if this position a valid position.</summary>
|
|
/// <returns>Returns true if this position is a valid position.</returns>
|
|
bool IsInvalid()const
|
|
{
|
|
return index < 0 && row < 0 && column < 0;
|
|
}
|
|
|
|
static vint Compare(const ParsingTextPos& a, const ParsingTextPos& b)
|
|
{
|
|
if (a.IsInvalid() && b.IsInvalid())
|
|
{
|
|
return 0;
|
|
}
|
|
else if (a.IsInvalid())
|
|
{
|
|
return -1;
|
|
}
|
|
else if (b.IsInvalid())
|
|
{
|
|
return 1;
|
|
}
|
|
else if (a.index >= 0 && b.index >= 0)
|
|
{
|
|
return a.index - b.index;
|
|
}
|
|
else if (a.row >= 0 && a.column >= 0 && b.row >= 0 && b.column >= 0)
|
|
{
|
|
if (a.row == b.row)
|
|
{
|
|
return a.column - b.column;
|
|
}
|
|
else
|
|
{
|
|
return a.row - b.row;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool operator==(const ParsingTextPos& pos)const{return Compare(*this, pos)==0;}
|
|
bool operator!=(const ParsingTextPos& pos)const{return Compare(*this, pos)!=0;}
|
|
bool operator<(const ParsingTextPos& pos)const{return Compare(*this, pos)<0;}
|
|
bool operator<=(const ParsingTextPos& pos)const{return Compare(*this, pos)<=0;}
|
|
bool operator>(const ParsingTextPos& pos)const{return Compare(*this, pos)>0;}
|
|
bool operator>=(const ParsingTextPos& pos)const{return Compare(*this, pos)>=0;}
|
|
};
|
|
|
|
/// <summary>A type representing text range.</summary>
|
|
struct ParsingTextRange
|
|
{
|
|
/// <summary>Text position for the first character.</summary>
|
|
ParsingTextPos start;
|
|
/// <summary>Text position for the last character.</summary>
|
|
ParsingTextPos end;
|
|
/// <summary>Code index, refer to [F:vl.regex.RegexToken.codeIndex]</summary>
|
|
vint codeIndex;
|
|
|
|
ParsingTextRange()
|
|
:codeIndex(-1)
|
|
{
|
|
end.index=-1;
|
|
end.column=-1;
|
|
}
|
|
|
|
ParsingTextRange(const ParsingTextPos& _start, const ParsingTextPos& _end, vint _codeIndex = -1)
|
|
:start(_start)
|
|
, end(_end)
|
|
, codeIndex(_codeIndex)
|
|
{
|
|
}
|
|
|
|
ParsingTextRange(const regex::RegexToken* startToken, const regex::RegexToken* endToken)
|
|
:codeIndex(startToken->codeIndex)
|
|
{
|
|
start.index=startToken->start;
|
|
start.row=startToken->rowStart;
|
|
start.column=startToken->columnStart;
|
|
end.index=endToken->start+endToken->length-1;
|
|
end.row=endToken->rowEnd;
|
|
end.column=endToken->columnEnd;
|
|
}
|
|
|
|
bool operator==(const ParsingTextRange& range)const{return start==range.start && end==range.end;}
|
|
bool operator!=(const ParsingTextRange& range)const{return start!=range.start || end!=range.end;}
|
|
bool Contains(const ParsingTextPos& pos)const{return start<=pos && pos<=end;}
|
|
bool Contains(const ParsingTextRange& range)const{return start<=range.start && range.end<=end;}
|
|
};
|
|
}
|
|
|
|
namespace stream
|
|
{
|
|
namespace internal
|
|
{
|
|
BEGIN_SERIALIZATION(parsing::ParsingTextPos)
|
|
SERIALIZE(index)
|
|
SERIALIZE(row)
|
|
SERIALIZE(column)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(parsing::ParsingTextRange)
|
|
SERIALIZE(start)
|
|
SERIALIZE(end)
|
|
SERIALIZE(codeIndex)
|
|
END_SERIALIZATION
|
|
}
|
|
}
|
|
|
|
namespace parsing
|
|
{
|
|
/***********************************************************************
|
|
General Syntax Tree
|
|
***********************************************************************/
|
|
|
|
class ParsingTreeNode;
|
|
class ParsingTreeToken;
|
|
class ParsingTreeObject;
|
|
class ParsingTreeArray;
|
|
|
|
/// <summary>Abstract syntax tree, usually created by a sub class of <see cref="tabling::ParsingGeneralParser"/></summary>
|
|
class ParsingTreeNode : public Object, public reflection::Description<ParsingTreeNode>
|
|
{
|
|
public:
|
|
class IVisitor : public Interface
|
|
{
|
|
public:
|
|
virtual void Visit(ParsingTreeToken* node)=0;
|
|
virtual void Visit(ParsingTreeObject* node)=0;
|
|
virtual void Visit(ParsingTreeArray* node)=0;
|
|
};
|
|
|
|
class TraversalVisitor : public Object, public IVisitor
|
|
{
|
|
public:
|
|
enum TraverseDirection
|
|
{
|
|
ByTextPosition,
|
|
ByStorePosition
|
|
};
|
|
protected:
|
|
TraverseDirection direction;
|
|
public:
|
|
TraversalVisitor(TraverseDirection _direction);
|
|
|
|
virtual void BeforeVisit(ParsingTreeToken* node);
|
|
virtual void AfterVisit(ParsingTreeToken* node);
|
|
virtual void BeforeVisit(ParsingTreeObject* node);
|
|
virtual void AfterVisit(ParsingTreeObject* node);
|
|
virtual void BeforeVisit(ParsingTreeArray* node);
|
|
virtual void AfterVisit(ParsingTreeArray* node);
|
|
|
|
virtual void Visit(ParsingTreeToken* node)override;
|
|
virtual void Visit(ParsingTreeObject* node)override;
|
|
virtual void Visit(ParsingTreeArray* node)override;
|
|
};
|
|
protected:
|
|
typedef collections::List<Ptr<ParsingTreeNode>> NodeList;
|
|
|
|
ParsingTextRange codeRange;
|
|
ParsingTreeNode* parent;
|
|
NodeList cachedOrderedSubNodes;
|
|
|
|
virtual const NodeList& GetSubNodesInternal()=0;
|
|
bool BeforeAddChild(Ptr<ParsingTreeNode> node);
|
|
void AfterAddChild(Ptr<ParsingTreeNode> node);
|
|
bool BeforeRemoveChild(Ptr<ParsingTreeNode> node);
|
|
void AfterRemoveChild(Ptr<ParsingTreeNode> node);
|
|
public:
|
|
ParsingTreeNode(const ParsingTextRange& _codeRange);
|
|
~ParsingTreeNode();
|
|
|
|
virtual void Accept(IVisitor* visitor)=0;
|
|
virtual Ptr<ParsingTreeNode> Clone()=0;
|
|
ParsingTextRange GetCodeRange();
|
|
void SetCodeRange(const ParsingTextRange& range);
|
|
|
|
/// <summary>Cache necessary data to improve searching performance for this node and all child nodes.</summary>
|
|
void InitializeQueryCache();
|
|
/// <summary>Clear all cache made by <see cref="InitializeQueryCache"/>.</summary>
|
|
void ClearQueryCache();
|
|
/// <summary>Get the parent node. Using this function requires <see cref="InitializeQueryCache"/> to be called.</summary>
|
|
/// <returns>The parent node.</returns>
|
|
ParsingTreeNode* GetParent();
|
|
/// <summary>Get the child nodes. Using this function requires <see cref="InitializeQueryCache"/> to be called.</summary>
|
|
/// <returns>The child nodes.</returns>
|
|
const NodeList& GetSubNodes();
|
|
|
|
/// <summary>Find a direct child node at the position. Using this function requires <see cref="InitializeQueryCache"/> to be called.</summary>
|
|
/// <returns>The found node.</returns>
|
|
/// <param name="position">The position.</param>
|
|
ParsingTreeNode* FindSubNode(const ParsingTextPos& position);
|
|
/// <summary>Find a direct child node at the range. Using this function requires <see cref="InitializeQueryCache"/> to be called.</summary>
|
|
/// <returns>The found node.</returns>
|
|
/// <param name="range">The range.</param>
|
|
ParsingTreeNode* FindSubNode(const ParsingTextRange& range);
|
|
/// <summary>Find a most deepest indirect child node at the position. Using this function requires <see cref="InitializeQueryCache"/> to be called.</summary>
|
|
/// <returns>The found node.</returns>
|
|
/// <param name="position">The position.</param>
|
|
ParsingTreeNode* FindDeepestNode(const ParsingTextPos& position);
|
|
/// <summary>Find a most deepest indirect child node at the range. Using this function requires <see cref="InitializeQueryCache"/> to be called.</summary>
|
|
/// <returns>The found node.</returns>
|
|
/// <param name="range">The range.</param>
|
|
ParsingTreeNode* FindDeepestNode(const ParsingTextRange& range);
|
|
};
|
|
|
|
/// <summary>Representing a token node in an abstract syntax tree.</summary>
|
|
class ParsingTreeToken : public ParsingTreeNode, public reflection::Description<ParsingTreeToken>
|
|
{
|
|
protected:
|
|
WString value;
|
|
vint tokenIndex;
|
|
|
|
const NodeList& GetSubNodesInternal()override;
|
|
public:
|
|
ParsingTreeToken(const WString& _value, vint _tokenIndex=-1, const ParsingTextRange& _codeRange=ParsingTextRange());
|
|
~ParsingTreeToken();
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
Ptr<ParsingTreeNode> Clone()override;
|
|
vint GetTokenIndex();
|
|
void SetTokenIndex(vint _tokenIndex);
|
|
/// <summary>Get the content of the token.</summary>
|
|
/// <returns>The content of the token.</returns>
|
|
const WString& GetValue();
|
|
void SetValue(const WString& _value);
|
|
};
|
|
|
|
/// <summary>Representing an object node in an abstract syntax tree.</summary>
|
|
class ParsingTreeObject : public ParsingTreeNode, public reflection::Description<ParsingTreeObject>
|
|
{
|
|
protected:
|
|
typedef collections::Dictionary<WString, Ptr<ParsingTreeNode>> NodeMap;
|
|
typedef collections::SortedList<WString> NameList;
|
|
typedef collections::List<WString> RuleList;
|
|
|
|
WString type;
|
|
NodeMap members;
|
|
RuleList rules;
|
|
|
|
const NodeList& GetSubNodesInternal()override;
|
|
public:
|
|
ParsingTreeObject(const WString& _type=L"", const ParsingTextRange& _codeRange=ParsingTextRange());
|
|
~ParsingTreeObject();
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
Ptr<ParsingTreeNode> Clone()override;
|
|
/// <summary>Get the type name of the object.</summary>
|
|
/// <returns>The type name of the object.</returns>
|
|
const WString& GetType();
|
|
void SetType(const WString& _type);
|
|
/// <summary>Get all fields of the object.</summary>
|
|
/// <returns>All fields of the object.</returns>
|
|
NodeMap& GetMembers();
|
|
/// <summary>Get a field of the object by the field name.</summary>
|
|
/// <returns>The field of the object.</returns>
|
|
/// <param name="name">The field name.</param>
|
|
Ptr<ParsingTreeNode> GetMember(const WString& name);
|
|
bool SetMember(const WString& name, Ptr<ParsingTreeNode> node);
|
|
bool RemoveMember(const WString& name);
|
|
/// <summary>Get all field names.</summary>
|
|
/// <returns>All field names of the object.</returns>
|
|
const NameList& GetMemberNames();
|
|
/// <summary>Get names of all rules that return this object.</summary>
|
|
/// <returns>Names of all rules.</returns>
|
|
RuleList& GetCreatorRules();
|
|
};
|
|
|
|
/// <summary>Representing an array node in an abstract syntax tree.</summary>
|
|
class ParsingTreeArray : public ParsingTreeNode, public reflection::Description<ParsingTreeArray>
|
|
{
|
|
protected:
|
|
typedef collections::List<Ptr<ParsingTreeNode>> NodeArray;
|
|
|
|
WString elementType;
|
|
NodeArray items;
|
|
|
|
const NodeList& GetSubNodesInternal()override;
|
|
public:
|
|
ParsingTreeArray(const WString& _elementType=L"", const ParsingTextRange& _codeRange=ParsingTextRange());
|
|
~ParsingTreeArray();
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
Ptr<ParsingTreeNode> Clone()override;
|
|
/// <summary>Get the type of all elements. It could be different from any actual element's type, but it should at least be the base types of them.</summary>
|
|
/// <returns>The type of all elements.</returns>
|
|
const WString& GetElementType();
|
|
void SetElementType(const WString& _elementType);
|
|
/// <summary>Get all elements in this array.</summary>
|
|
/// <returns>All elements in this array.</returns>
|
|
NodeArray& GetItems();
|
|
/// <summary>Get a specified element in this array by the index.</summary>
|
|
/// <returns>The element.</returns>
|
|
/// <param name="index">The index of the element.</param>
|
|
Ptr<ParsingTreeNode> GetItem(vint index);
|
|
bool SetItem(vint index, Ptr<ParsingTreeNode> node);
|
|
bool AddItem(Ptr<ParsingTreeNode> node);
|
|
bool InsertItem(vint index, Ptr<ParsingTreeNode> node);
|
|
bool RemoveItem(vint index);
|
|
bool RemoveItem(ParsingTreeNode* node);
|
|
vint IndexOfItem(ParsingTreeNode* node);
|
|
bool ContainsItem(ParsingTreeNode* node);
|
|
vint Count();
|
|
bool Clear();
|
|
};
|
|
|
|
/***********************************************************************
|
|
AST Building Block
|
|
***********************************************************************/
|
|
|
|
/// <summary>Base type of all strong typed syntax tree. Normally all strong typed syntax tree are generated from a grammar file using ParserGen.exe in Tools project. See [T:vl.parsing.tabling.ParsingTable] for details.</summary>
|
|
class ParsingTreeCustomBase : public Object, public reflection::Description<ParsingTreeCustomBase>
|
|
{
|
|
public:
|
|
/// <summary>Range of all tokens that form this object.</summary>
|
|
ParsingTextRange codeRange;
|
|
/// <summary>Names of all rules that return this object.</summary>
|
|
collections::List<WString> creatorRules;
|
|
};
|
|
|
|
/// <summary>Strong typed token syntax node, for all class fields of type "token" in the grammar file. See [T:vl.parsing.tabling.ParsingTable] for details.</summary>
|
|
class ParsingToken : public ParsingTreeCustomBase, public reflection::Description<ParsingToken>
|
|
{
|
|
public:
|
|
/// <summary>Type of the token, representing the index of a regular expression that creates this token in the regular expression list in the grammar file.</summary>
|
|
vint tokenIndex;
|
|
/// <summary>Content of the token.</summary>
|
|
WString value;
|
|
|
|
ParsingToken():tokenIndex(-1){}
|
|
};
|
|
|
|
/// <summary>Error.</summary>
|
|
class ParsingError : public Object, public reflection::Description<ParsingError>
|
|
{
|
|
public:
|
|
/// <summary>Range where the error happens.</summary>
|
|
ParsingTextRange codeRange;
|
|
/// <summary>Token at which the error happens.</summary>
|
|
const regex::RegexToken* token;
|
|
/// <summary>A syntax tree that contains this error.</summary>
|
|
ParsingTreeCustomBase* parsingTree;
|
|
/// <summary>The error message.</summary>
|
|
WString errorMessage;
|
|
|
|
ParsingError();
|
|
ParsingError(const WString& _errorMessage);
|
|
ParsingError(const regex::RegexToken* _token, const WString& _errorMessage);
|
|
ParsingError(ParsingTreeCustomBase* _parsingTree, const WString& _errorMessage);
|
|
~ParsingError();
|
|
};
|
|
|
|
/***********************************************************************
|
|
Syntax Tree Serialization Helper
|
|
***********************************************************************/
|
|
|
|
class ParsingTreeConverter : public Object
|
|
{
|
|
public:
|
|
typedef collections::List<regex::RegexToken> TokenList;
|
|
|
|
virtual Ptr<ParsingTreeCustomBase> ConvertClass(Ptr<ParsingTreeObject> obj, const TokenList& tokens)=0;
|
|
|
|
bool SetMember(ParsingToken& member, Ptr<ParsingTreeNode> node, const TokenList& tokens)
|
|
{
|
|
Ptr<ParsingTreeToken> token=node.Cast<ParsingTreeToken>();
|
|
if(token)
|
|
{
|
|
member.tokenIndex=token->GetTokenIndex();
|
|
member.value=token->GetValue();
|
|
member.codeRange=token->GetCodeRange();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename T>
|
|
bool SetMember(collections::List<T>& member, Ptr<ParsingTreeNode> node, const TokenList& tokens)
|
|
{
|
|
Ptr<ParsingTreeArray> arr=node.Cast<ParsingTreeArray>();
|
|
if(arr)
|
|
{
|
|
member.Clear();
|
|
vint count=arr->Count();
|
|
for(vint i=0;i<count;i++)
|
|
{
|
|
T t;
|
|
SetMember(t, arr->GetItem(i), tokens);
|
|
member.Add(t);
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
template<typename T>
|
|
bool SetMember(Ptr<T>& member, Ptr<ParsingTreeNode> node, const TokenList& tokens)
|
|
{
|
|
Ptr<ParsingTreeObject> obj=node.Cast<ParsingTreeObject>();
|
|
if(obj)
|
|
{
|
|
Ptr<ParsingTreeCustomBase> tree=ConvertClass(obj, tokens);
|
|
if(tree)
|
|
{
|
|
tree->codeRange=node->GetCodeRange();
|
|
member=tree.Cast<T>();
|
|
return member;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Logging
|
|
***********************************************************************/
|
|
|
|
class IParsingPrintNodeRecorder : public virtual Interface
|
|
{
|
|
public:
|
|
virtual void Record(ParsingTreeCustomBase* node, const ParsingTextRange& range) = 0;
|
|
};
|
|
|
|
class ParsingEmptyPrintNodeRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
public:
|
|
ParsingEmptyPrintNodeRecorder();
|
|
~ParsingEmptyPrintNodeRecorder();
|
|
|
|
void Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingMultiplePrintNodeRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
typedef collections::List<Ptr<IParsingPrintNodeRecorder>> RecorderList;
|
|
protected:
|
|
RecorderList recorders;
|
|
|
|
public:
|
|
ParsingMultiplePrintNodeRecorder();
|
|
~ParsingMultiplePrintNodeRecorder();
|
|
|
|
void AddRecorder(Ptr<IParsingPrintNodeRecorder> recorder);
|
|
void Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingOriginalLocationRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
protected:
|
|
Ptr<IParsingPrintNodeRecorder> recorder;
|
|
|
|
public:
|
|
ParsingOriginalLocationRecorder(Ptr<IParsingPrintNodeRecorder> _recorder);
|
|
~ParsingOriginalLocationRecorder();
|
|
|
|
void Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingGeneratedLocationRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
typedef collections::Dictionary<ParsingTreeCustomBase*, ParsingTextRange> RangeMap;
|
|
protected:
|
|
RangeMap& rangeMap;
|
|
|
|
public:
|
|
ParsingGeneratedLocationRecorder(RangeMap& _rangeMap);
|
|
~ParsingGeneratedLocationRecorder();
|
|
|
|
void Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingUpdateLocationRecorder : public Object, public virtual IParsingPrintNodeRecorder
|
|
{
|
|
public:
|
|
ParsingUpdateLocationRecorder();
|
|
~ParsingUpdateLocationRecorder();
|
|
|
|
void Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)override;
|
|
};
|
|
|
|
class ParsingWriter : public stream::TextWriter
|
|
{
|
|
typedef collections::Pair<ParsingTreeCustomBase*, ParsingTextPos> NodePosPair;
|
|
typedef collections::List<NodePosPair> NodePosList;
|
|
protected:
|
|
stream::TextWriter& writer;
|
|
Ptr<IParsingPrintNodeRecorder> recorder;
|
|
vint codeIndex;
|
|
ParsingTextPos lastPos;
|
|
ParsingTextPos currentPos;
|
|
NodePosList nodePositions;
|
|
|
|
void HandleChar(wchar_t c);
|
|
public:
|
|
ParsingWriter(stream::TextWriter& _writer, Ptr<IParsingPrintNodeRecorder> _recorder = nullptr, vint _codeIndex = -1);
|
|
~ParsingWriter();
|
|
|
|
using stream::TextWriter::WriteString;
|
|
void WriteChar(wchar_t c)override;
|
|
void WriteString(const wchar_t* string, vint charCount)override;
|
|
void BeforePrint(ParsingTreeCustomBase* node);
|
|
void AfterPrint(ParsingTreeCustomBase* node);
|
|
};
|
|
|
|
extern void Log(ParsingTreeNode* node, const WString& originalInput, stream::TextWriter& writer, const WString& prefix=L"");
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\PARSINGDEFINITIONS.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_PARSINGDEFINITIONS
|
|
#define VCZH_PARSING_PARSINGDEFINITIONS
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace definitions
|
|
{
|
|
|
|
/***********************************************************************
|
|
Attributes
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionAttribute : public ParsingTreeCustomBase
|
|
{
|
|
public:
|
|
WString name;
|
|
collections::List<WString> arguments;
|
|
};
|
|
|
|
class ParsingDefinitionBase : public ParsingTreeCustomBase
|
|
{
|
|
typedef collections::List<Ptr<ParsingDefinitionAttribute>> AttributeList;
|
|
public:
|
|
AttributeList attributes;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Type
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionPrimitiveType;
|
|
class ParsingDefinitionTokenType;
|
|
class ParsingDefinitionSubType;
|
|
class ParsingDefinitionArrayType;
|
|
|
|
class ParsingDefinitionType : public ParsingTreeCustomBase
|
|
{
|
|
public:
|
|
class IVisitor : public Interface
|
|
{
|
|
public:
|
|
virtual void Visit(ParsingDefinitionPrimitiveType* node)=0;
|
|
virtual void Visit(ParsingDefinitionTokenType* node)=0;
|
|
virtual void Visit(ParsingDefinitionSubType* node)=0;
|
|
virtual void Visit(ParsingDefinitionArrayType* node)=0;
|
|
};
|
|
|
|
virtual void Accept(IVisitor* visitor)=0;
|
|
};
|
|
|
|
class ParsingDefinitionPrimitiveType : public ParsingDefinitionType
|
|
{
|
|
public:
|
|
WString name;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionTokenType : public ParsingDefinitionType
|
|
{
|
|
public:
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionSubType : public ParsingDefinitionType
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionType> parentType;
|
|
WString subTypeName;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionArrayType : public ParsingDefinitionType
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionType> elementType;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Type Definition
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionClassMemberDefinition;
|
|
class ParsingDefinitionClassDefinition;
|
|
class ParsingDefinitionEnumMemberDefinition;
|
|
class ParsingDefinitionEnumDefinition;
|
|
|
|
class ParsingDefinitionTypeDefinition : public ParsingDefinitionBase
|
|
{
|
|
public:
|
|
class IVisitor : public Interface
|
|
{
|
|
public:
|
|
virtual void Visit(ParsingDefinitionClassMemberDefinition* node)=0;
|
|
virtual void Visit(ParsingDefinitionClassDefinition* node)=0;
|
|
virtual void Visit(ParsingDefinitionEnumMemberDefinition* node)=0;
|
|
virtual void Visit(ParsingDefinitionEnumDefinition* node)=0;
|
|
};
|
|
|
|
virtual void Accept(IVisitor* visitor)=0;
|
|
public:
|
|
WString name;
|
|
};
|
|
|
|
class ParsingDefinitionClassMemberDefinition : public ParsingDefinitionTypeDefinition
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionType> type;
|
|
WString unescapingFunction;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionClassDefinition : public ParsingDefinitionTypeDefinition
|
|
{
|
|
public:
|
|
typedef collections::List<Ptr<ParsingDefinitionClassMemberDefinition>> MemberList;
|
|
typedef collections::List<Ptr<ParsingDefinitionTypeDefinition>> TypeList;
|
|
|
|
Ptr<ParsingDefinitionType> ambiguousType;
|
|
Ptr<ParsingDefinitionType> parentType;
|
|
MemberList members;
|
|
TypeList subTypes;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionEnumMemberDefinition : public ParsingDefinitionTypeDefinition
|
|
{
|
|
public:
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionEnumDefinition : public ParsingDefinitionTypeDefinition
|
|
{
|
|
public:
|
|
typedef collections::List<Ptr<ParsingDefinitionEnumMemberDefinition>> MemberList;
|
|
|
|
MemberList members;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Grammar
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionPrimitiveGrammar;
|
|
class ParsingDefinitionTextGrammar;
|
|
class ParsingDefinitionSequenceGrammar;
|
|
class ParsingDefinitionAlternativeGrammar;
|
|
class ParsingDefinitionLoopGrammar;
|
|
class ParsingDefinitionOptionalGrammar;
|
|
class ParsingDefinitionCreateGrammar;
|
|
class ParsingDefinitionAssignGrammar;
|
|
class ParsingDefinitionUseGrammar;
|
|
class ParsingDefinitionSetterGrammar;
|
|
|
|
class ParsingDefinitionGrammar : public ParsingTreeCustomBase
|
|
{
|
|
public:
|
|
class IVisitor : public Interface
|
|
{
|
|
public:
|
|
virtual void Visit(ParsingDefinitionPrimitiveGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionTextGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionSequenceGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionAlternativeGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionLoopGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionOptionalGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionCreateGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionAssignGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionUseGrammar* node)=0;
|
|
virtual void Visit(ParsingDefinitionSetterGrammar* node)=0;
|
|
};
|
|
|
|
virtual void Accept(IVisitor* visitor)=0;
|
|
};
|
|
|
|
class ParsingDefinitionPrimitiveGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
WString name;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionTextGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
WString text;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionSequenceGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> first;
|
|
Ptr<ParsingDefinitionGrammar> second;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionAlternativeGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> first;
|
|
Ptr<ParsingDefinitionGrammar> second;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionLoopGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> grammar;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionOptionalGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> grammar;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionCreateGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> grammar;
|
|
Ptr<ParsingDefinitionType> type;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionAssignGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> grammar;
|
|
WString memberName;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionUseGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> grammar;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
class ParsingDefinitionSetterGrammar : public ParsingDefinitionGrammar
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinitionGrammar> grammar;
|
|
WString memberName;
|
|
WString value;
|
|
|
|
void Accept(IVisitor* visitor)override;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Token and Rule
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionTokenDefinition : public ParsingDefinitionBase
|
|
{
|
|
public:
|
|
WString name;
|
|
WString regex;
|
|
bool discard;
|
|
};
|
|
|
|
class ParsingDefinitionRuleDefinition : public ParsingDefinitionBase
|
|
{
|
|
public:
|
|
WString name;
|
|
Ptr<ParsingDefinitionType> type;
|
|
collections::List<Ptr<ParsingDefinitionGrammar>> grammars;
|
|
};
|
|
|
|
class ParsingDefinition : public ParsingTreeCustomBase
|
|
{
|
|
public:
|
|
collections::List<Ptr<ParsingDefinitionTypeDefinition>> types;
|
|
collections::List<Ptr<ParsingDefinitionTokenDefinition>> tokens;
|
|
collections::List<Ptr<ParsingDefinitionRuleDefinition>> rules;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Attribute Writer
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionAttributeWriter : public Object
|
|
{
|
|
friend ParsingDefinitionAttributeWriter Attribute(const WString& name);
|
|
protected:
|
|
Ptr<ParsingDefinitionAttribute> attribute;
|
|
|
|
ParsingDefinitionAttributeWriter(const WString& name);
|
|
public:
|
|
ParsingDefinitionAttributeWriter(const ParsingDefinitionAttributeWriter& attributeWriter);
|
|
|
|
ParsingDefinitionAttributeWriter& Argument(const WString& argument);
|
|
Ptr<ParsingDefinitionAttribute> Attribute()const;
|
|
};
|
|
|
|
extern ParsingDefinitionAttributeWriter Attribute(const WString& name);
|
|
|
|
/***********************************************************************
|
|
Type Writer
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionTypeWriter : public Object
|
|
{
|
|
friend ParsingDefinitionTypeWriter Type(const WString& name);
|
|
friend ParsingDefinitionTypeWriter TokenType();
|
|
protected:
|
|
Ptr<ParsingDefinitionType> type;
|
|
|
|
ParsingDefinitionTypeWriter(Ptr<ParsingDefinitionType> internalType);
|
|
ParsingDefinitionTypeWriter(const WString& name);
|
|
public:
|
|
ParsingDefinitionTypeWriter(const ParsingDefinitionTypeWriter& typeWriter);
|
|
|
|
ParsingDefinitionTypeWriter Sub(const WString& subTypeName)const;
|
|
ParsingDefinitionTypeWriter Array()const;
|
|
Ptr<ParsingDefinitionType> Type()const;
|
|
};
|
|
|
|
extern ParsingDefinitionTypeWriter Type(const WString& name);
|
|
extern ParsingDefinitionTypeWriter TokenType();
|
|
|
|
/***********************************************************************
|
|
Type Definition Writer
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionTypeDefinitionWriter : public Object
|
|
{
|
|
public:
|
|
virtual Ptr<ParsingDefinitionTypeDefinition> Definition()const=0;
|
|
};
|
|
|
|
class ParsingDefinitionClassDefinitionWriter : public ParsingDefinitionTypeDefinitionWriter
|
|
{
|
|
protected:
|
|
Ptr<ParsingDefinitionBase> currentDefinition;
|
|
Ptr<ParsingDefinitionClassDefinition> definition;
|
|
|
|
public:
|
|
ParsingDefinitionClassDefinitionWriter(const WString& name);
|
|
ParsingDefinitionClassDefinitionWriter(const WString& name, const ParsingDefinitionTypeWriter& parentType);
|
|
|
|
ParsingDefinitionClassDefinitionWriter& AmbiguousType(const ParsingDefinitionTypeWriter& ambiguousType);
|
|
ParsingDefinitionClassDefinitionWriter& Member(const WString& name, const ParsingDefinitionTypeWriter& type, const WString& unescapingFunction=L"");
|
|
ParsingDefinitionClassDefinitionWriter& SubType(const ParsingDefinitionTypeDefinitionWriter& type);
|
|
ParsingDefinitionClassDefinitionWriter& Attribute(const ParsingDefinitionAttributeWriter& attribute);
|
|
|
|
Ptr<ParsingDefinitionTypeDefinition> Definition()const override;
|
|
};
|
|
|
|
extern ParsingDefinitionClassDefinitionWriter Class(const WString& name);
|
|
extern ParsingDefinitionClassDefinitionWriter Class(const WString& name, const ParsingDefinitionTypeWriter& parentType);
|
|
|
|
class ParsingDefinitionEnumDefinitionWriter : public ParsingDefinitionTypeDefinitionWriter
|
|
{
|
|
protected:
|
|
Ptr<ParsingDefinitionBase> currentDefinition;
|
|
Ptr<ParsingDefinitionEnumDefinition> definition;
|
|
|
|
public:
|
|
ParsingDefinitionEnumDefinitionWriter(const WString& name);
|
|
|
|
ParsingDefinitionEnumDefinitionWriter& Member(const WString& name);
|
|
ParsingDefinitionEnumDefinitionWriter& Attribute(const ParsingDefinitionAttributeWriter& attribute);
|
|
|
|
Ptr<ParsingDefinitionTypeDefinition> Definition()const override;
|
|
};
|
|
|
|
extern ParsingDefinitionEnumDefinitionWriter Enum(const WString& name);
|
|
|
|
/***********************************************************************
|
|
Grammar Writer
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionGrammarWriter : public Object
|
|
{
|
|
friend ParsingDefinitionGrammarWriter Rule(const WString& name);
|
|
friend ParsingDefinitionGrammarWriter Text(const WString& name);
|
|
friend ParsingDefinitionGrammarWriter Opt(const ParsingDefinitionGrammarWriter& writer);
|
|
protected:
|
|
Ptr<ParsingDefinitionGrammar> grammar;
|
|
|
|
ParsingDefinitionGrammarWriter(Ptr<ParsingDefinitionGrammar> internalGrammar);
|
|
public:
|
|
ParsingDefinitionGrammarWriter(const ParsingDefinitionGrammarWriter& grammarWriter);
|
|
|
|
ParsingDefinitionGrammarWriter operator+(const ParsingDefinitionGrammarWriter& next)const;
|
|
ParsingDefinitionGrammarWriter operator|(const ParsingDefinitionGrammarWriter& next)const;
|
|
ParsingDefinitionGrammarWriter operator*()const;
|
|
ParsingDefinitionGrammarWriter As(const ParsingDefinitionTypeWriter& type)const;
|
|
ParsingDefinitionGrammarWriter operator[](const WString& memberName)const;
|
|
ParsingDefinitionGrammarWriter operator!()const;
|
|
ParsingDefinitionGrammarWriter Set(const WString& memberName, const WString& value)const;
|
|
|
|
Ptr<ParsingDefinitionGrammar> Grammar()const;
|
|
};
|
|
|
|
extern ParsingDefinitionGrammarWriter Rule(const WString& name);
|
|
extern ParsingDefinitionGrammarWriter Text(const WString& text);
|
|
extern ParsingDefinitionGrammarWriter Opt(const ParsingDefinitionGrammarWriter& writer);
|
|
|
|
/***********************************************************************
|
|
Token and Rule Writer
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionWriter;
|
|
|
|
class ParsingDefinitionTokenDefinitionWriter : public Object
|
|
{
|
|
protected:
|
|
Ptr<ParsingDefinitionTokenDefinition> token;
|
|
ParsingDefinitionWriter& owner;
|
|
public:
|
|
ParsingDefinitionTokenDefinitionWriter(ParsingDefinitionWriter& _owner, Ptr<ParsingDefinitionTokenDefinition> _token);
|
|
|
|
ParsingDefinitionTokenDefinitionWriter& Attribute(const ParsingDefinitionAttributeWriter& attribute);
|
|
ParsingDefinitionWriter& EndToken();
|
|
};
|
|
|
|
class ParsingDefinitionRuleDefinitionWriter : public Object
|
|
{
|
|
protected:
|
|
Ptr<ParsingDefinitionRuleDefinition> rule;
|
|
ParsingDefinitionWriter& owner;
|
|
public:
|
|
ParsingDefinitionRuleDefinitionWriter(ParsingDefinitionWriter& _owner, Ptr<ParsingDefinitionRuleDefinition> _rule);
|
|
|
|
ParsingDefinitionRuleDefinitionWriter& Imply(const ParsingDefinitionGrammarWriter& grammar);
|
|
ParsingDefinitionRuleDefinitionWriter& Attribute(const ParsingDefinitionAttributeWriter& attribute);
|
|
ParsingDefinitionWriter& EndRule();
|
|
};
|
|
|
|
class ParsingDefinitionWriter : public Object
|
|
{
|
|
protected:
|
|
Ptr<ParsingDefinition> definition;
|
|
|
|
public:
|
|
ParsingDefinitionWriter();
|
|
|
|
ParsingDefinitionWriter& Type(const ParsingDefinitionTypeDefinitionWriter& type);
|
|
ParsingDefinitionWriter& Token(const WString& name, const WString& regex);
|
|
ParsingDefinitionTokenDefinitionWriter TokenAtt(const WString& name, const WString& regex);
|
|
ParsingDefinitionWriter& Discard(const WString& name, const WString& regex);
|
|
ParsingDefinitionRuleDefinitionWriter Rule(const WString& name, const ParsingDefinitionTypeWriter& type);
|
|
|
|
Ptr<ParsingDefinition> Definition()const;
|
|
};
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
extern WString TypeToString(ParsingDefinitionType* type);
|
|
extern WString GrammarToString(ParsingDefinitionGrammar* grammar);
|
|
extern WString GrammarStateToString(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode);
|
|
extern ParsingDefinitionGrammar* FindAppropriateGrammarState(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode);
|
|
extern void Log(Ptr<ParsingDefinition> definition, stream::TextWriter& writer);
|
|
extern WString DeserializeString(const WString& value);
|
|
extern WString SerializeString(const WString& value);
|
|
|
|
/***********************************************************************
|
|
Bootstrap
|
|
***********************************************************************/
|
|
|
|
extern Ptr<ParsingDefinition> CreateParserDefinition();
|
|
extern Ptr<ParsingDefinition> DeserializeDefinition(Ptr<ParsingTreeNode> node);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\PARSINGANALYZER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_PARSINGANALYZER
|
|
#define VCZH_PARSING_PARSINGANALYZER
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
DefinitionTypeScopePair
|
|
***********************************************************************/
|
|
|
|
class ParsingSymbol;
|
|
class ParsingSymbolManager;
|
|
|
|
struct DefinitionTypeScopePair
|
|
{
|
|
definitions::ParsingDefinitionType* type;
|
|
ParsingSymbol* scope;
|
|
|
|
DefinitionTypeScopePair()
|
|
{
|
|
}
|
|
|
|
DefinitionTypeScopePair(definitions::ParsingDefinitionType* _type, ParsingSymbol* _scope)
|
|
:type(_type)
|
|
,scope(_scope)
|
|
{
|
|
}
|
|
|
|
vint Compare(const DefinitionTypeScopePair& pair)const
|
|
{
|
|
if(type<pair.type) return -1;
|
|
if(type>pair.type) return 1;
|
|
if(scope<pair.scope) return -1;
|
|
if(scope>pair.scope) return 1;
|
|
return 0;
|
|
}
|
|
|
|
bool operator== (const DefinitionTypeScopePair& pair)const {return Compare(pair)==0;}
|
|
bool operator!= (const DefinitionTypeScopePair& pair)const {return Compare(pair)!=0;}
|
|
bool operator> (const DefinitionTypeScopePair& pair)const {return Compare(pair)>0;}
|
|
bool operator>= (const DefinitionTypeScopePair& pair)const {return Compare(pair)>=0;}
|
|
bool operator< (const DefinitionTypeScopePair& pair)const {return Compare(pair)<0;}
|
|
bool operator<= (const DefinitionTypeScopePair& pair)const {return Compare(pair)<=0;}
|
|
};
|
|
|
|
/***********************************************************************
|
|
ParsingSymbol Management
|
|
***********************************************************************/
|
|
|
|
class ParsingSymbol : public Object
|
|
{
|
|
friend class ParsingSymbolManager;
|
|
|
|
typedef collections::Dictionary<WString, ParsingSymbol*> ParsingSymbolMap;
|
|
typedef collections::List<ParsingSymbol*> ParsingSymbolList;
|
|
public:
|
|
enum SymbolType
|
|
{
|
|
Global,
|
|
EnumType,
|
|
ClassType, // descriptor == base type
|
|
ArrayType, // descriptor == element type
|
|
TokenType,
|
|
EnumItem, // descriptor == parent
|
|
ClassField, // descriptor == field type
|
|
TokenDef, // descriptor == token type
|
|
RuleDef, // descriptor == rule type
|
|
};
|
|
|
|
protected:
|
|
ParsingSymbolManager* manager;
|
|
SymbolType type;
|
|
WString name;
|
|
ParsingSymbol* descriptorSymbol;
|
|
WString descriptorString;
|
|
ParsingSymbol* parentSymbol;
|
|
ParsingSymbol* arrayTypeSymbol;
|
|
ParsingSymbolList subSymbolList;
|
|
ParsingSymbolMap subSymbolMap;
|
|
|
|
bool AddSubSymbol(ParsingSymbol* subSymbol);
|
|
|
|
ParsingSymbol(ParsingSymbolManager* _manager, SymbolType _type, const WString& _name, ParsingSymbol* _descriptorSymbol, const WString& _descriptorString);
|
|
public:
|
|
~ParsingSymbol();
|
|
|
|
ParsingSymbolManager* GetManager();
|
|
SymbolType GetType();
|
|
const WString& GetName();
|
|
vint GetSubSymbolCount();
|
|
ParsingSymbol* GetSubSymbol(vint index);
|
|
ParsingSymbol* GetSubSymbolByName(const WString& name);
|
|
ParsingSymbol* GetDescriptorSymbol();
|
|
WString GetDescriptorString();
|
|
ParsingSymbol* GetParentSymbol();
|
|
bool IsType();
|
|
ParsingSymbol* SearchClassSubSymbol(const WString& name);
|
|
ParsingSymbol* SearchCommonBaseClass(ParsingSymbol* classType);
|
|
};
|
|
|
|
class ParsingSymbolManager : public Object
|
|
{
|
|
typedef definitions::ParsingDefinitionClassDefinition ClassDefinition;
|
|
typedef collections::List<Ptr<ParsingSymbol>> ParsingSymbolList;
|
|
typedef collections::Dictionary<DefinitionTypeScopePair, ParsingSymbol*> DefinitionTypeSymbolMap;
|
|
typedef collections::Dictionary<definitions::ParsingDefinitionGrammar*, ParsingSymbol*> DefinitionGrammarSymbolMap;
|
|
typedef collections::Dictionary<ParsingSymbol*, ClassDefinition*> SymbolClassDefinitionMap;
|
|
typedef collections::Dictionary<ClassDefinition*, ParsingSymbol*> ClassDefinitionSymbolMap;
|
|
protected:
|
|
ParsingSymbol* globalSymbol;
|
|
ParsingSymbol* tokenTypeSymbol;
|
|
ParsingSymbolList createdSymbols;
|
|
DefinitionTypeSymbolMap definitionTypeSymbolCache;
|
|
DefinitionGrammarSymbolMap definitionGrammarSymbolCache;
|
|
DefinitionGrammarSymbolMap definitionGrammarTypeCache;
|
|
SymbolClassDefinitionMap symbolClassDefinitionCache;
|
|
ClassDefinitionSymbolMap classDefinitionSymbolCache;
|
|
|
|
bool TryAddSubSymbol(Ptr<ParsingSymbol> subSymbol, ParsingSymbol* parentSymbol);
|
|
public:
|
|
ParsingSymbolManager();
|
|
~ParsingSymbolManager();
|
|
|
|
ParsingSymbol* GetGlobal();
|
|
ParsingSymbol* GetTokenType();
|
|
ParsingSymbol* GetArrayType(ParsingSymbol* elementType);
|
|
|
|
ParsingSymbol* AddClass(definitions::ParsingDefinitionClassDefinition* classDef, ParsingSymbol* baseType, ParsingSymbol* parentType=0);
|
|
ParsingSymbol* AddField(const WString& name, ParsingSymbol* classType, ParsingSymbol* fieldType);
|
|
ParsingSymbol* AddEnum(const WString& name, ParsingSymbol* parentType=0);
|
|
ParsingSymbol* AddEnumItem(const WString& name, ParsingSymbol* enumType);
|
|
ParsingSymbol* AddTokenDefinition(const WString& name, const WString& regex);
|
|
ParsingSymbol* AddRuleDefinition(const WString& name, ParsingSymbol* ruleType);
|
|
|
|
ClassDefinition* CacheGetClassDefinition(ParsingSymbol* type);
|
|
ParsingSymbol* CacheGetClassType(ClassDefinition* type);
|
|
ParsingSymbol* CacheGetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope);
|
|
bool CacheSetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope, ParsingSymbol* symbol);
|
|
ParsingSymbol* CacheGetSymbol(definitions::ParsingDefinitionGrammar* grammar);
|
|
bool CacheSetSymbol(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* symbol);
|
|
ParsingSymbol* CacheGetType(definitions::ParsingDefinitionGrammar* grammar);
|
|
bool CacheSetType(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* type);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Semantic Analyzer
|
|
***********************************************************************/
|
|
|
|
extern WString GetTypeFullName(ParsingSymbol* type);
|
|
extern ParsingSymbol* FindType(definitions::ParsingDefinitionType* type, ParsingSymbolManager* manager, ParsingSymbol* scope, collections::List<Ptr<ParsingError>>& errors);
|
|
extern void PrepareSymbols(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors);
|
|
extern void ValidateRuleStructure(Ptr<definitions::ParsingDefinition> definition, Ptr<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors);
|
|
extern void ResolveRuleSymbols(Ptr<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors);
|
|
extern void ResolveSymbols(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors);
|
|
extern void ValidateDefinition(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\PARSINGTABLE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_PARSINGTABLE
|
|
#define VCZH_PARSING_PARSINGTABLE
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace tabling
|
|
{
|
|
|
|
/***********************************************************************
|
|
Parsing Table
|
|
***********************************************************************/
|
|
|
|
/// <summary>
|
|
/// <p>
|
|
/// The parsing table. When you complete a grammar file, use ParserGen.exe to generate the C++ code for you to create a parsing table.
|
|
/// </p>
|
|
/// <p>
|
|
/// Here is a brief description of the grammar file format:
|
|
/// </p>
|
|
/// <p>
|
|
/// The grammar file consists of four parts: configuration, types, tokens and grammar in order like this:
|
|
/// <program><code><![CDATA[
|
|
/// CONFIGURATION
|
|
/// grammar:
|
|
/// TYPES
|
|
/// TOKENS
|
|
/// GRAMMAR
|
|
/// ]]></code></program>
|
|
/// </p>
|
|
/// <p>
|
|
/// <b>Configuration</b>
|
|
/// <ul>
|
|
/// <li>
|
|
/// <b>include:"releative path to the VlppParser.h"</b>:
|
|
/// (multiple) e.g. "../Import/Vlpp.h"
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>namespace:C++-NAMESPACE</b>:
|
|
/// (single) Namespaces separated by "." to contain the generated code. e.g. vl.parsing.xml
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>reflection:REFLECTION-NAMESPACE</b>:
|
|
/// (single) Namespaces separated by "." to contain the name of reflectable types. In most of the cases this should be the same as namespace. e.g. vl.parsing.xml
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>filePrefix:FILE-PREFIX</b>:
|
|
/// (single) A prefix that will be add before all generated files. e.g. ParsingXml
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>classPrefix:CLASS-PREFIX</b>:
|
|
/// (single) A prefix that will be add before all generated types and function. e.g. Xml
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>classRoot:CLASS-ROOT</b>:
|
|
/// (single) The class that represents the whole text being parsed.
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>guard:C++-HEADER-GUARD</b>:
|
|
/// (single) The C++ header guard pattern macro name. e.g. VCZH_PARSING_XML_PARSINGXML_PARSER
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>parser:NAME(RULE)</b>:
|
|
/// (multiple) Pair a function name to a rule name.
|
|
/// It will generate a function called "XmlParseDocument" to parse the input using the rule named "XDocument",
|
|
/// if you have "classPrefix:Xml" and "parser:ParseDocument(XDocument)".</li>
|
|
/// <li>
|
|
/// <b>file:FEATURE(POSTFIX)</b>:
|
|
/// (multiple) Generate code for a specified feature to "<FILE-PREFIX><POSTFIX>.h" and "<FILE-PREFIX><POSTFIX>.cpp".
|
|
/// FEATURE could be Ast, Parser, Copy, Traverse and Empty.
|
|
/// Ast is the definition of all classes in the grammar file.
|
|
/// Parser is the implementation of all parsers.
|
|
/// Others are visitors for Ast with different traversing features.
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>ambiguity:(enabled|disabled)</b>:
|
|
/// (single) Set to "enabled" indicating that the grammar is by design to have ambiguity.
|
|
/// If ambiguity happens during parser, but here is "disabled", then an error will be generated.
|
|
/// </li>
|
|
/// <li>
|
|
/// <b>serialization:(enabled|disabled)</b>:
|
|
/// (single) Set to "enabled" to serialize the parsing table as binary in the generated C++ code,
|
|
/// so that when the "<CLASS-PREFIX>LoadTable" function is called to load the table,
|
|
/// it can deserialize from the binary data directly,
|
|
/// instead of parsing the grammar again.
|
|
/// But the grammar text will always be in the generated C++ code regardless of the value of "serialization",
|
|
/// it can always be retrived using the "<CLASS-PREFIX>GetParserTextBuffer" function.
|
|
/// </li>
|
|
/// </ul>
|
|
/// </p>
|
|
/// <p>
|
|
/// <b>Character escaping in strings</b>
|
|
/// </p>
|
|
/// <p>
|
|
/// There is only character escaping in strings: "", which means the " character.
|
|
/// For example, "a""b""c" means R"TEXT(a"b"c)TEXT" in C++.
|
|
/// </p>
|
|
/// <p>
|
|
/// <b>Types</b>
|
|
/// </p>
|
|
/// <p>
|
|
/// You can write attributes like @AttributeName("argument1", "argument2", ...) in the middle of types.
|
|
/// But attributes don't affect parsing.
|
|
/// All attribute definitions will be stored in the generated parsing table,
|
|
/// and who uses the table defines how attributes work. Multiple attributes are separated by ",".
|
|
/// </p>
|
|
/// <p>
|
|
/// If you only need parsing, usually you don't need to use attributes.
|
|
/// GacUI will use some attributes to drive colorizer and intellisense.
|
|
/// This part is subject to change in the next version, so it will not be described here.
|
|
/// </p>
|
|
/// <p>
|
|
/// <ul>
|
|
/// <li>
|
|
/// <b>Enum</b>:
|
|
/// <program><code><![CDATA[
|
|
/// enum EnumName <attributes>
|
|
/// {
|
|
/// Item1 <attributes>,
|
|
/// Item2 <attributes>,
|
|
/// ... // cannot skip the last ","
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// </li>
|
|
/// <li>
|
|
/// <p>
|
|
/// <b>Class</b>:
|
|
/// <program><code><![CDATA[
|
|
/// class Name [ambiguous(AmbiguousType)] [: ParentType] <attributes>
|
|
/// {
|
|
/// Type name [(UnescapingFunction)] <attributes> ;
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// </p>
|
|
/// <p>
|
|
/// UnescapingFunction is a callback,
|
|
/// which will be called after the contained type is fully constructed.
|
|
/// The generated C++ code will define forward declarations of all unescaping functions in the cpp file.
|
|
/// You should implement them in other places, or you will get linking errors.
|
|
/// </p>
|
|
/// <p>
|
|
/// If the grammar enables ambiguity, then the parsing result may contain ambiguous results for the same part of the input. For example, in C++:
|
|
/// <program><code><![CDATA[
|
|
/// A*B;
|
|
/// ]]></code></program>
|
|
/// has two meanings without considering the surrounding context: a multiplication expression or a pointer variable definition.
|
|
/// </p>
|
|
/// <p>
|
|
/// If the grammar doesn't enable ambiguity, it will refuce to generate C++ codes because the grammar is wrong.
|
|
/// Note that it doesn't generate errors for every possible cases of ambiguity.
|
|
/// Do not rely on this to check ambiguity in the grammar.
|
|
/// </p>
|
|
/// <p>
|
|
/// If the grammar enables ambiguity, than the syntax tree should be defined like this:
|
|
/// <program><code><![CDATA[
|
|
/// // when ambiguity happens for Statement, AmbiguiusStatement will be used to container all possible cases
|
|
/// class Statement ambiguous(AmbiguousStatement)
|
|
/// {
|
|
/// }
|
|
///
|
|
/// // so that "AmbiguousStatement" should inherit from "Statement"
|
|
/// class AmbiguousStatement : Statement
|
|
/// {
|
|
/// // it should called "items", and the type should be an array of the base type
|
|
/// Statement[] items;
|
|
/// }
|
|
///
|
|
/// class ExpressionStatement : Statement
|
|
/// {
|
|
/// Expression expression;
|
|
/// }
|
|
///
|
|
/// class VariableDefinitionStatement : Statement
|
|
/// {
|
|
/// Type type;
|
|
/// token name;
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// For "A*B;" part in the whole input, it becomes an AmbiguousStatement.
|
|
/// The "items" field contains two instances, which are "ExpressionStatement" and "VariableDefinitionStatement".
|
|
/// You could write C++ code to resolve the ambiguity in later passes.
|
|
/// </p>
|
|
/// </li>
|
|
/// <li>
|
|
/// <p><b>Type references</b>:</p>
|
|
/// <p>
|
|
/// Types can be defined globally or inside classes. Generic type is not supported. You can use the following types for a class field:
|
|
/// <ul>
|
|
/// <li><b>token</b>: Store a token, which will becomes [T:vl.parsing.ParsingToken].</li>
|
|
/// <li><b>ClassName</b>: Instance of a specified type, which will becomes Ptr<ClassName>.</li>
|
|
/// <li>
|
|
/// <p><b>ClassName[]</b>: Array, which will becomes List<Ptr<ClassName>>. Array of tokens are not supported.</p>
|
|
/// <p>A class name could also be<b>OuterClass.InnerClass</b>, referring to the "InnerClass" defined inside the "OuterClass".</p>
|
|
/// </li>
|
|
/// </ul>
|
|
/// </p>
|
|
/// </li>
|
|
/// </ul>
|
|
/// </p>
|
|
/// <p>
|
|
/// <b>Token definitions</b>
|
|
/// <program><code><![CDATA[
|
|
/// token TokenName = "regular expression" <attributes>;
|
|
/// discardtoken TokenName = "regular expression";
|
|
/// ]]></code></program>
|
|
/// "discardtoken" means that,
|
|
/// if such a token is identified,
|
|
/// it will not appear in the lexical analyzing result.
|
|
/// You cannot use tokens marked with "discardtoken" in the grammar.
|
|
/// </p>
|
|
/// <p>
|
|
/// <b>Grammar</b>
|
|
/// <program><code><![CDATA[
|
|
/// rule RuleType RuleName <attributes>
|
|
/// = Grammar1
|
|
/// = Grammar2
|
|
/// ...
|
|
/// ;
|
|
/// ]]></code></program>
|
|
/// It means rule "RuleName" is defined by those grammars,
|
|
/// and matching this rule will create an instance of "RuleType" or one of its sub classes.
|
|
/// </p>
|
|
/// <p>
|
|
/// Here are all supported grammars that:
|
|
/// <ul>
|
|
/// <li><b>RuleName</b>: Defines an input that matches a rule.</li>
|
|
/// <li><b>TokenName</b>: Defines an input that formed by the specified token.</li>
|
|
/// <li><b>"StringConstant"</b>: Defines an input that formed by exactly the string constant. There should be exactly one token who can only be this string constant.</li>
|
|
/// <li><b>Grammar: FieldName</b>: Defines an input that matches Grammar (should be either a rule name or a token name), and the result will be stored in field "FieldName" of the created object.</li>
|
|
/// <li><b>!Grammar</b>: Defines an input that matches Grammar, and the rule will use the created object from this grammar. The input should still match other part of the rule, but result of other parts are ignored.</li>
|
|
/// <li><b>[Grammar]</b>: Defines an input that, if it matches Grammar, it returns the result from that grammar; otherwise, it returns null.</li>
|
|
/// <li><b>{Grammar}</b>: Defines an input that matches 0, 1 or more Grammar.</li>
|
|
/// <li><b>(Grammar)</b>: Defines an input that matches the the grammar. Brackets is only for changing operator associations.</li>
|
|
/// <li><b>Grammar1 Grammar2</b>: Defines an input that should match Grammar1 followed by Grammar2.</li>
|
|
/// <li><b>Grammar1 | Grammar2</b>: Defines an input that match either Grammar1 or Grammar2. When it matches Grammar1, Grammar2 will be ignored.</li>
|
|
/// <li><b>Grammar as Type</b>: Defines an input that matches the Grammar, and the whole branch of the rule creates an instance of type "Type".</li>
|
|
/// <li><b>Grammar with { FieldName = Value }</b>: Defines an input that matches the Grammar, assign "Value" to the field "FieldName" of the created object.</li>
|
|
/// </ul>
|
|
/// A grammar branch must be "GRAMMAR as TYPE with {Field1 = Value1} with {Field2 = Value2} ...".
|
|
/// </p>
|
|
/// <p>
|
|
/// <b>Example</b>
|
|
/// </p>
|
|
/// <p>
|
|
/// Here is an example to parse expression containing +, -, *, /, () and numbers:
|
|
/// <program><code><![CDATA[
|
|
/// include:"Vlpp.h"
|
|
/// namespace:vl.calculator
|
|
/// reflection:vl.calculator
|
|
/// filePrefix:Calc
|
|
/// classPrefix:Calc
|
|
/// classRoot:Expression
|
|
/// guard:VCZH_CALCULATOR_PARSER
|
|
/// parser:ParseExpression(Expr)
|
|
/// file:Ast(_Ast)
|
|
/// file:Parser(_Parser)
|
|
/// ambiguity:disabled
|
|
/// serialization:enabled
|
|
/// grammar:
|
|
///
|
|
/// class Expression
|
|
/// {
|
|
/// }
|
|
///
|
|
/// enum BinaryOperator
|
|
/// {
|
|
/// Add, Sub, Mul, Div,
|
|
/// }
|
|
///
|
|
/// class NumberExpression : Expression
|
|
/// {
|
|
/// token number;
|
|
/// }
|
|
///
|
|
/// class BinaryExpression : Expression
|
|
/// {
|
|
/// BinaryOperator op;
|
|
/// Expression left;
|
|
/// Expression right;
|
|
/// }
|
|
///
|
|
/// token ADD "\+"
|
|
/// token SUB "-"
|
|
/// token MUL "\*"
|
|
/// token DIV "\/"
|
|
/// token NUMBER "\d+(.\d+)?"
|
|
/// token OPEN "("
|
|
/// token CLOSE ")"
|
|
/// discardtoken SPACE = "/s+";
|
|
///
|
|
/// rule Expression Factor
|
|
/// = NUMBER : number as NumberExpression
|
|
/// = "(" !Expr ")"
|
|
/// ;
|
|
/// rule Expression Term
|
|
/// = !Factor
|
|
/// = Term : left "*" Factor : right as BinaryExpression with {op = "Mul"}
|
|
/// = Term : left "/" Factor : right as BinaryExpression with {op = "Div"}
|
|
/// ;
|
|
/// rule Expression Expr
|
|
/// = !Term
|
|
/// = Expr : left "+" Term : right as BinaryExpression with {op = "Add"}
|
|
/// = Expr : left "-" Term : right as BinaryExpression with {op = "Sub"}
|
|
/// ;
|
|
/// ]]></code></program>
|
|
/// </p>
|
|
/// <p>
|
|
/// After using ParserGen.exe to generate C++ codes, you can do this:
|
|
/// <program><code><![CDATA[
|
|
/// // this table can be used, please cache the result to improve the performance
|
|
/// auto table = CalcLoadTable();
|
|
/// List<Ptr<ParsingError>> errors;
|
|
/// // it should be a Ptr<CalcExpression>, will returns nullptr if the input contains syntax errors
|
|
/// auto expression = CalcParseExpression(L"(1+2) * (3+4)", table, errors);
|
|
/// ]]></code></program>
|
|
/// You don't need to define the "errors" if you don't actually care how the input is wrong.
|
|
/// There will be a overloaded version of CalcParseExpression that doesn't need the third argument.
|
|
/// </p>
|
|
/// <p>
|
|
/// You can also automatically correct wrong input.
|
|
/// Ifthe input is not too wrong to recognize,
|
|
/// you can still get a syntax tree,
|
|
/// but some fields are nullptr,
|
|
/// with errors filled into the "error" variable.
|
|
/// <program><code><![CDATA[
|
|
/// auto table = CalcLoadTable(); // Load the table.
|
|
/// ParsingState state(L"(1+2) * (3+4)", table); // Initialize a state with the input and the table.
|
|
/// state.Reset(L"Expr"); // Set the rule to parse.
|
|
/// auto parser = CreateAutoRecoverParser(table); // Create an appropriate automatic error recoverable parser.
|
|
/// List<Ptr<ParsingError>> errors; // Define an error list.
|
|
/// auto node = parser->Parse(state, errors); // Parse to get an abstract syntax tree, which is a Ptr<ParsingTreeNode>.
|
|
/// if (node)
|
|
/// {
|
|
/// auto expression = CalcConvertParsingTreeNode(node, state.GetTokens()).Cast<CalcExpression>();
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// </p>
|
|
/// <p>
|
|
/// After you get a strong typed syntax tree, you can use the generated visitor interface to do something, like evaluate the results of the expression:
|
|
/// <program><code><![CDATA[
|
|
/// class Evaluator : public Object, public virtual CalcExpression::IVisitor
|
|
/// {
|
|
/// private:
|
|
/// double result;
|
|
///
|
|
/// double Call(CalcExpression* node)
|
|
/// {
|
|
/// node->Accept(this);
|
|
/// return result;
|
|
/// }
|
|
///
|
|
/// public:
|
|
/// static double Evaluate(CalcExpression* node)
|
|
/// {
|
|
/// return Evaluator().Call(node);
|
|
/// }
|
|
///
|
|
/// void Visit(CalcNumberExpression* node)override
|
|
/// {
|
|
/// return wtof(node->number.value);
|
|
/// }
|
|
///
|
|
/// void Visit(CalcBinaryExpression* node)override
|
|
/// {
|
|
/// auto left = Calc(node->left.Obj());
|
|
/// auto right = Calc(node->right.Obj());
|
|
/// switch (node->op)
|
|
/// {
|
|
/// case CalcBinaryOperator::Add:
|
|
/// result = left + right;
|
|
/// break;
|
|
/// case CalcBinaryOperator::Sub:
|
|
/// result = left 0 right;
|
|
/// break;
|
|
/// case CalcBinaryOperator::Mul:
|
|
/// result = left * right;
|
|
/// break;
|
|
/// case CalcBinaryOperator::Div:
|
|
/// result = left / right;
|
|
/// break;
|
|
/// }
|
|
/// }
|
|
/// };
|
|
///
|
|
/// Nullable<double> EvaluateExpression(const WString& input)
|
|
/// {
|
|
/// static auto table = CalcLoadTable();
|
|
/// auto expression = CalcParseExpression(input, table);
|
|
/// Nulllable<double> result;
|
|
/// if (expression)
|
|
/// {
|
|
/// result = Evaluator::Evaulate(expression.Obj());
|
|
/// }
|
|
/// return result;
|
|
/// }
|
|
/// ]]></code></program>
|
|
/// </p>
|
|
/// </summary>
|
|
class ParsingTable : public Object
|
|
{
|
|
public:
|
|
static const vint TokenBegin=0;
|
|
static const vint TokenFinish=1;
|
|
static const vint NormalReduce=2;
|
|
static const vint LeftRecursiveReduce=3;
|
|
static const vint UserTokenStart=4;
|
|
|
|
class AttributeInfo : public Object
|
|
{
|
|
public:
|
|
WString name;
|
|
collections::List<WString> arguments;
|
|
|
|
AttributeInfo(const WString& _name = L"")
|
|
:name(_name)
|
|
{
|
|
}
|
|
|
|
AttributeInfo* Argument(const WString& argument)
|
|
{
|
|
arguments.Add(argument);
|
|
return this;
|
|
}
|
|
};
|
|
|
|
class AttributeInfoList : public Object
|
|
{
|
|
public:
|
|
collections::List<Ptr<AttributeInfo>> attributes;
|
|
|
|
Ptr<AttributeInfo> FindFirst(const WString& name);
|
|
};
|
|
|
|
class TreeTypeInfo
|
|
{
|
|
public:
|
|
WString type;
|
|
vint attributeIndex;
|
|
|
|
TreeTypeInfo()
|
|
:attributeIndex(-1)
|
|
{
|
|
}
|
|
|
|
TreeTypeInfo(const WString& _type, vint _attributeIndex)
|
|
:type(_type)
|
|
,attributeIndex(_attributeIndex)
|
|
{
|
|
}
|
|
};
|
|
|
|
class TreeFieldInfo
|
|
{
|
|
public:
|
|
WString type;
|
|
WString field;
|
|
vint attributeIndex;
|
|
|
|
TreeFieldInfo()
|
|
:attributeIndex(-1)
|
|
{
|
|
}
|
|
|
|
TreeFieldInfo(const WString& _type, const WString& _field, vint _attributeIndex)
|
|
:type(_type)
|
|
,field(_field)
|
|
,attributeIndex(_attributeIndex)
|
|
{
|
|
}
|
|
};
|
|
|
|
class TokenInfo
|
|
{
|
|
public:
|
|
WString name;
|
|
WString regex;
|
|
vint regexTokenIndex;
|
|
vint attributeIndex;
|
|
|
|
TokenInfo()
|
|
:regexTokenIndex(-1)
|
|
,attributeIndex(-1)
|
|
{
|
|
}
|
|
|
|
TokenInfo(const WString& _name, const WString& _regex, vint _attributeIndex)
|
|
:name(_name)
|
|
,regex(_regex)
|
|
,regexTokenIndex(-1)
|
|
,attributeIndex(_attributeIndex)
|
|
{
|
|
}
|
|
};
|
|
|
|
class StateInfo
|
|
{
|
|
public:
|
|
WString ruleName;
|
|
WString stateName;
|
|
WString stateExpression;
|
|
|
|
WString ruleAmbiguousType; // filled in Initialize()
|
|
|
|
StateInfo()
|
|
{
|
|
}
|
|
|
|
StateInfo(const WString& _ruleName, const WString& _stateName, const WString& _stateExpression)
|
|
:ruleName(_ruleName)
|
|
,stateName(_stateName)
|
|
,stateExpression(_stateExpression)
|
|
{
|
|
}
|
|
};
|
|
|
|
class RuleInfo
|
|
{
|
|
public:
|
|
WString name;
|
|
WString type;
|
|
WString ambiguousType;
|
|
vint rootStartState;
|
|
vint attributeIndex;
|
|
|
|
RuleInfo()
|
|
:rootStartState(-1)
|
|
,attributeIndex(-1)
|
|
{
|
|
}
|
|
|
|
RuleInfo(const WString& _name, const WString& _type, const WString& _ambiguousType, vint _rootStartState, vint _attributeIndex)
|
|
:name(_name)
|
|
,type(_type)
|
|
,ambiguousType(_ambiguousType)
|
|
,rootStartState(_rootStartState)
|
|
,attributeIndex(_attributeIndex)
|
|
{
|
|
}
|
|
};
|
|
|
|
class Instruction
|
|
{
|
|
public:
|
|
enum InstructionType
|
|
{
|
|
Create,
|
|
Assign,
|
|
Item,
|
|
Using,
|
|
Setter,
|
|
Shift,
|
|
Reduce,
|
|
LeftRecursiveReduce,
|
|
};
|
|
|
|
InstructionType instructionType;
|
|
vint stateParameter;
|
|
WString nameParameter;
|
|
WString value;
|
|
WString creatorRule;
|
|
|
|
Instruction()
|
|
:instructionType(Create)
|
|
,stateParameter(0)
|
|
{
|
|
}
|
|
|
|
Instruction(InstructionType _instructionType, vint _stateParameter, const WString& _nameParameter, const WString& _value, const WString& _creatorRule)
|
|
:instructionType(_instructionType)
|
|
,stateParameter(_stateParameter)
|
|
,nameParameter(_nameParameter)
|
|
,value(_value)
|
|
,creatorRule(_creatorRule)
|
|
{
|
|
}
|
|
};
|
|
|
|
class LookAheadInfo
|
|
{
|
|
public:
|
|
collections::List<vint> tokens;
|
|
vint state;
|
|
|
|
LookAheadInfo()
|
|
:state(-1)
|
|
{
|
|
}
|
|
|
|
enum PrefixResult
|
|
{
|
|
Prefix,
|
|
Equal,
|
|
NotPrefix,
|
|
};
|
|
|
|
static PrefixResult TestPrefix(Ptr<LookAheadInfo> a, Ptr<LookAheadInfo> b);
|
|
static void WalkInternal(Ptr<ParsingTable> table, Ptr<LookAheadInfo> previous, vint state, collections::SortedList<vint>& walkedStates, collections::List<Ptr<LookAheadInfo>>& newInfos);
|
|
static void Walk(Ptr<ParsingTable> table, Ptr<LookAheadInfo> previous, vint state, collections::List<Ptr<LookAheadInfo>>& newInfos);
|
|
};
|
|
|
|
class TransitionItem
|
|
{
|
|
public:
|
|
vint token;
|
|
vint targetState;
|
|
collections::List<Ptr<LookAheadInfo>> lookAheads;
|
|
collections::List<vint> stackPattern;
|
|
collections::List<Instruction> instructions;
|
|
|
|
enum OrderResult
|
|
{
|
|
CorrectOrder,
|
|
WrongOrder,
|
|
SameOrder,
|
|
UnknownOrder,
|
|
};
|
|
|
|
TransitionItem(){}
|
|
|
|
TransitionItem(vint _token, vint _targetState)
|
|
:token(_token)
|
|
,targetState(_targetState)
|
|
{
|
|
}
|
|
|
|
static OrderResult CheckOrder(Ptr<TransitionItem> t1, Ptr<TransitionItem> t2, OrderResult defaultResult = UnknownOrder);
|
|
static vint Compare(Ptr<TransitionItem> t1, Ptr<TransitionItem> t2, OrderResult defaultResult);
|
|
};
|
|
|
|
class TransitionBag
|
|
{
|
|
public:
|
|
collections::List<Ptr<TransitionItem>> transitionItems;
|
|
};
|
|
|
|
protected:
|
|
// metadata
|
|
bool ambiguity;
|
|
collections::Array<Ptr<AttributeInfoList>> attributeInfos;
|
|
collections::Array<TreeTypeInfo> treeTypeInfos;
|
|
collections::Array<TreeFieldInfo> treeFieldInfos;
|
|
|
|
// LALR table
|
|
vint tokenCount; // tokenInfos.Count() + discardTokenInfos.Count()
|
|
vint stateCount; // stateInfos.Count()
|
|
collections::Array<TokenInfo> tokenInfos;
|
|
collections::Array<TokenInfo> discardTokenInfos;
|
|
collections::Array<StateInfo> stateInfos;
|
|
collections::Array<RuleInfo> ruleInfos;
|
|
collections::Array<Ptr<TransitionBag>> transitionBags;
|
|
|
|
// generated data
|
|
Ptr<regex::RegexLexer> lexer;
|
|
collections::Dictionary<WString, vint> ruleMap;
|
|
collections::Dictionary<WString, vint> treeTypeInfoMap;
|
|
collections::Dictionary<collections::Pair<WString, WString>, vint> treeFieldInfoMap;
|
|
|
|
template<typename TIO>
|
|
void IO(TIO& io);
|
|
|
|
public:
|
|
ParsingTable(vint _attributeInfoCount, vint _treeTypeInfoCount, vint _treeFieldInfoCount, vint _tokenCount, vint _discardTokenCount, vint _stateCount, vint _ruleCount);
|
|
/// <summary>Deserialize the parsing table from a stream. <see cref="Initialize"/> should be before using this table.</summary>
|
|
/// <param name="input">The stream.</param>
|
|
ParsingTable(stream::IStream& input);
|
|
~ParsingTable();
|
|
|
|
/// <summary>Serialize the parsing table to a stream.</summary>
|
|
/// <param name="output">The stream.</param>
|
|
void Serialize(stream::IStream& output);
|
|
|
|
bool GetAmbiguity();
|
|
void SetAmbiguity(bool value);
|
|
|
|
vint GetAttributeInfoCount();
|
|
Ptr<AttributeInfoList> GetAttributeInfo(vint index);
|
|
void SetAttributeInfo(vint index, Ptr<AttributeInfoList> info);
|
|
|
|
vint GetTreeTypeInfoCount();
|
|
const TreeTypeInfo& GetTreeTypeInfo(vint index);
|
|
const TreeTypeInfo& GetTreeTypeInfo(const WString& type);
|
|
void SetTreeTypeInfo(vint index, const TreeTypeInfo& info);
|
|
|
|
vint GetTreeFieldInfoCount();
|
|
const TreeFieldInfo& GetTreeFieldInfo(vint index);
|
|
const TreeFieldInfo& GetTreeFieldInfo(const WString& type, const WString& field);
|
|
void SetTreeFieldInfo(vint index, const TreeFieldInfo& info);
|
|
|
|
vint GetTokenCount();
|
|
const TokenInfo& GetTokenInfo(vint token);
|
|
void SetTokenInfo(vint token, const TokenInfo& info);
|
|
|
|
vint GetDiscardTokenCount();
|
|
const TokenInfo& GetDiscardTokenInfo(vint token);
|
|
void SetDiscardTokenInfo(vint token, const TokenInfo& info);
|
|
|
|
vint GetStateCount();
|
|
const StateInfo& GetStateInfo(vint state);
|
|
void SetStateInfo(vint state, const StateInfo& info);
|
|
|
|
vint GetRuleCount();
|
|
const RuleInfo& GetRuleInfo(const WString& ruleName);
|
|
const RuleInfo& GetRuleInfo(vint rule);
|
|
void SetRuleInfo(vint rule, const RuleInfo& info);
|
|
|
|
const regex::RegexLexer& GetLexer();
|
|
Ptr<TransitionBag> GetTransitionBag(vint state, vint token);
|
|
void SetTransitionBag(vint state, vint token, Ptr<TransitionBag> bag);
|
|
/// <summary>Initialize the parsing table. This function should be called after deserializing the table from a string.</summary>
|
|
void Initialize();
|
|
bool IsInputToken(vint regexTokenIndex);
|
|
vint GetTableTokenIndex(vint regexTokenIndex);
|
|
vint GetTableDiscardTokenIndex(vint regexTokenIndex);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
extern void Log(Ptr<ParsingTable> table, stream::TextWriter& writer);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_PARSINGAUTOMATON
|
|
#define VCZH_PARSING_PARSINGAUTOMATON
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
Automaton
|
|
***********************************************************************/
|
|
|
|
class Action;
|
|
class Transition;
|
|
class State;
|
|
|
|
class Action : public Object
|
|
{
|
|
public:
|
|
enum ActionType
|
|
{
|
|
Create, // new source
|
|
Assign, // source ::= <created symbol>
|
|
Using, // use <created symbol>
|
|
Setter, // source ::= target
|
|
Shift,
|
|
Reduce,
|
|
LeftRecursiveReduce,
|
|
};
|
|
|
|
ActionType actionType;
|
|
ParsingSymbol* actionTarget;
|
|
ParsingSymbol* actionSource;
|
|
definitions::ParsingDefinitionRuleDefinition* creatorRule;
|
|
|
|
// the following two fields record which rule symbol transition generate this shift/reduce action
|
|
State* shiftReduceSource;
|
|
State* shiftReduceTarget;
|
|
|
|
Action();
|
|
~Action();
|
|
};
|
|
|
|
class Transition : public Object
|
|
{
|
|
public:
|
|
enum TransitionType
|
|
{
|
|
TokenBegin, // token stream start
|
|
TokenFinish, // token stream end
|
|
NormalReduce, // rule end
|
|
LeftRecursiveReduce, // rule end with left recursive
|
|
Epsilon, // an epsilon transition
|
|
Symbol, // a syntax symbol
|
|
};
|
|
|
|
enum StackOperationType
|
|
{
|
|
None,
|
|
ShiftReduceCompacted,
|
|
LeftRecursive,
|
|
};
|
|
|
|
State* source;
|
|
State* target;
|
|
collections::List<Ptr<Action>> actions;
|
|
|
|
TransitionType transitionType;
|
|
StackOperationType stackOperationType;
|
|
ParsingSymbol* transitionSymbol;
|
|
|
|
Transition();
|
|
~Transition();
|
|
|
|
static bool IsEquivalent(Transition* t1, Transition* t2, bool careSourceAndTarget);
|
|
};
|
|
|
|
class State : public Object
|
|
{
|
|
public:
|
|
enum StatePosition
|
|
{
|
|
BeforeNode,
|
|
AfterNode,
|
|
};
|
|
|
|
collections::List<Transition*> transitions;
|
|
collections::List<Transition*> inputs;
|
|
bool endState;
|
|
|
|
ParsingSymbol* ownerRuleSymbol;
|
|
definitions::ParsingDefinitionRuleDefinition* ownerRule;
|
|
definitions::ParsingDefinitionGrammar* grammarNode;
|
|
definitions::ParsingDefinitionGrammar* stateNode;
|
|
StatePosition statePosition;
|
|
WString stateName;
|
|
WString stateExpression;
|
|
|
|
State();
|
|
~State();
|
|
};
|
|
|
|
class RuleInfo : public Object
|
|
{
|
|
public:
|
|
State* rootRuleStartState;
|
|
State* rootRuleEndState;
|
|
State* startState;
|
|
collections::List<State*> endStates;
|
|
int stateNameCount;
|
|
|
|
RuleInfo();
|
|
~RuleInfo();
|
|
};
|
|
|
|
class Automaton : public Object
|
|
{
|
|
typedef collections::List<definitions::ParsingDefinitionRuleDefinition*> RuleDefList;
|
|
typedef collections::Dictionary<definitions::ParsingDefinitionRuleDefinition*, Ptr<RuleInfo>> RuleInfoMap;
|
|
public:
|
|
ParsingSymbolManager* symbolManager;
|
|
collections::List<Ptr<Transition>> transitions;
|
|
collections::List<Ptr<State>> states;
|
|
collections::List<Ptr<RuleInfo>> ruleInfos;
|
|
|
|
RuleDefList orderedRulesDefs;
|
|
RuleInfoMap ruleDefToInfoMap;
|
|
|
|
Automaton(ParsingSymbolManager* _symbolManager);
|
|
~Automaton();
|
|
|
|
void AddRuleInfo(definitions::ParsingDefinitionRuleDefinition* rule, Ptr<RuleInfo> ruleInfo);
|
|
|
|
State* RuleStartState(definitions::ParsingDefinitionRuleDefinition* ownerRule);
|
|
State* RootRuleStartState(definitions::ParsingDefinitionRuleDefinition* ownerRule);
|
|
State* RootRuleEndState(definitions::ParsingDefinitionRuleDefinition* ownerRule);
|
|
State* StartState(definitions::ParsingDefinitionRuleDefinition* ownerRule, definitions::ParsingDefinitionGrammar* grammarNode, definitions::ParsingDefinitionGrammar* stateNode);
|
|
State* EndState(definitions::ParsingDefinitionRuleDefinition* ownerRule, definitions::ParsingDefinitionGrammar* grammarNode, definitions::ParsingDefinitionGrammar* stateNode);
|
|
State* CopyState(State* oldState);
|
|
|
|
Transition* CreateTransition(State* start, State* end);
|
|
Transition* TokenBegin(State* start, State* end);
|
|
Transition* TokenFinish(State* start, State* end);
|
|
Transition* NormalReduce(State* start, State* end);
|
|
Transition* LeftRecursiveReduce(State* start, State* end);
|
|
Transition* Epsilon(State* start, State* end);
|
|
Transition* Symbol(State* start, State* end, ParsingSymbol* transitionSymbol);
|
|
Transition* CopyTransition(State* start, State* end, Transition* oldTransition);
|
|
|
|
void DeleteTransition(Transition* transition);
|
|
void DeleteState(State* state);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Helper: Closuer Searching
|
|
***********************************************************************/
|
|
|
|
struct ClosureItem
|
|
{
|
|
enum SearchResult
|
|
{
|
|
Continue,
|
|
Hit,
|
|
Blocked,
|
|
};
|
|
|
|
State* state; // target state of one path of a closure
|
|
Ptr<collections::List<Transition*>> transitions; // path
|
|
bool cycle; // true: invalid closure because there are cycles, and in the middle of the path there will be a transition that targets to the state field.
|
|
|
|
ClosureItem()
|
|
:state(0)
|
|
,cycle(false)
|
|
{
|
|
}
|
|
|
|
ClosureItem(State* _state, Ptr<collections::List<Transition*>> _transitions, bool _cycle)
|
|
:state(_state)
|
|
,transitions(_transitions)
|
|
,cycle(_cycle)
|
|
{
|
|
}
|
|
};
|
|
|
|
extern void SearchClosure(ClosureItem::SearchResult(*closurePredicate)(Transition*), State* startState, collections::List<ClosureItem>& closure);
|
|
extern void RemoveEpsilonTransitions(collections::Dictionary<State*, State*>& oldNewStateMap, collections::List<State*>& scanningStates, Ptr<Automaton> automaton);
|
|
|
|
/***********************************************************************
|
|
Helper: State Merging
|
|
***********************************************************************/
|
|
|
|
extern void DeleteUnnecessaryStates(Ptr<Automaton> automaton, Ptr<RuleInfo> ruleInfo, collections::List<State*>& newStates);
|
|
extern void MergeStates(Ptr<Automaton> automaton, Ptr<RuleInfo> ruleInfo, collections::List<State*>& newStates);
|
|
|
|
/***********************************************************************
|
|
Helper: Automaton Building
|
|
***********************************************************************/
|
|
|
|
extern Ptr<Automaton> CreateEpsilonPDA(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager);
|
|
extern Ptr<Automaton> CreateNondeterministicPDAFromEpsilonPDA(Ptr<Automaton> epsilonPDA);
|
|
extern Ptr<Automaton> CreateJointPDAFromNondeterministicPDA(Ptr<Automaton> nondeterministicPDA);
|
|
extern void CompactJointPDA(Ptr<Automaton> jointPDA);
|
|
extern void MarkLeftRecursiveInJointPDA(Ptr<Automaton> jointPDA, collections::List<Ptr<ParsingError>>& errors);
|
|
|
|
/***********************************************************************
|
|
Helper: Parsing Table Generating
|
|
***********************************************************************/
|
|
|
|
extern WString GetTypeNameForCreateInstruction(ParsingSymbol* type);
|
|
extern Ptr<tabling::ParsingTable> GenerateTableFromPDA(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, Ptr<Automaton> jointPDA, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& errors);
|
|
extern Ptr<tabling::ParsingTable> GenerateTable(Ptr<definitions::ParsingDefinition> definition, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& errors);
|
|
extern void Log(Ptr<Automaton> automaton, stream::TextWriter& writer);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\PARSINGSTATE.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_PARSINGSTATE
|
|
#define VCZH_PARSING_PARSINGSTATE
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace tabling
|
|
{
|
|
|
|
/***********************************************************************
|
|
Syntax Analyzer
|
|
***********************************************************************/
|
|
|
|
class ParsingTokenWalker : public Object
|
|
{
|
|
protected:
|
|
class LookAheadEnumerator : public Object, public collections::IEnumerator<vint>
|
|
{
|
|
protected:
|
|
const ParsingTokenWalker* walker;
|
|
vint firstToken;
|
|
vint currentToken;
|
|
vint currentValue;
|
|
vint index;
|
|
|
|
public:
|
|
LookAheadEnumerator(const ParsingTokenWalker* _walker, vint _currentToken);
|
|
LookAheadEnumerator(const LookAheadEnumerator& _enumerator);
|
|
|
|
collections::IEnumerator<vint>* Clone()const override;
|
|
const vint& Current()const override;
|
|
vint Index()const override;
|
|
bool Next()override;
|
|
void Reset()override;
|
|
};
|
|
|
|
class TokenLookAhead : public Object, public collections::IEnumerable<vint>
|
|
{
|
|
protected:
|
|
const ParsingTokenWalker* walker;
|
|
public:
|
|
TokenLookAhead(const ParsingTokenWalker* _talker);
|
|
|
|
collections::IEnumerator<vint>* CreateEnumerator()const override;
|
|
};
|
|
|
|
class ReduceLookAhead : public Object, public collections::IEnumerable<vint>
|
|
{
|
|
protected:
|
|
const ParsingTokenWalker* walker;
|
|
public:
|
|
ReduceLookAhead(const ParsingTokenWalker* _walker);
|
|
|
|
collections::IEnumerator<vint>* CreateEnumerator()const override;
|
|
};
|
|
|
|
protected:
|
|
collections::List<regex::RegexToken>& tokens;
|
|
Ptr<ParsingTable> table;
|
|
vint currentToken;
|
|
TokenLookAhead tokenLookAhead;
|
|
ReduceLookAhead reduceLookAhead;
|
|
|
|
vint GetNextIndex(vint index)const;
|
|
vint GetTableTokenIndex(vint index)const;
|
|
public:
|
|
ParsingTokenWalker(collections::List<regex::RegexToken>& _tokens, Ptr<ParsingTable> _table);
|
|
~ParsingTokenWalker();
|
|
|
|
const collections::IEnumerable<vint>& GetTokenLookahead()const;
|
|
const collections::IEnumerable<vint>& GetReduceLookahead()const;
|
|
void Reset();
|
|
bool Move();
|
|
vint GetTableTokenIndex()const;
|
|
regex::RegexToken* GetRegexToken()const;
|
|
vint GetTokenIndexInStream()const;
|
|
};
|
|
|
|
class ParsingState : public Object
|
|
{
|
|
public:
|
|
struct ShiftReduceRange
|
|
{
|
|
regex::RegexToken* shiftToken;
|
|
regex::RegexToken* reduceToken;
|
|
|
|
ShiftReduceRange()
|
|
:shiftToken(0)
|
|
,reduceToken(0)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct TransitionResult
|
|
{
|
|
enum TransitionType
|
|
{
|
|
ExecuteInstructions,
|
|
AmbiguityBegin,
|
|
AmbiguityBranch,
|
|
AmbiguityEnd,
|
|
SkipToken,
|
|
};
|
|
|
|
TransitionType transitionType;
|
|
vint ambiguityAffectedStackNodeCount;
|
|
WString ambiguityNodeType;
|
|
|
|
vint tableTokenIndex;
|
|
vint tableStateSource;
|
|
vint tableStateTarget;
|
|
vint tokenIndexInStream;
|
|
regex::RegexToken* token;
|
|
|
|
ParsingTable::TransitionItem* transition;
|
|
vint instructionBegin;
|
|
vint instructionCount;
|
|
Ptr<collections::List<ShiftReduceRange>> shiftReduceRanges;
|
|
|
|
TransitionResult(TransitionType _transitionType=ExecuteInstructions)
|
|
:transitionType(_transitionType)
|
|
,ambiguityAffectedStackNodeCount(0)
|
|
,tableTokenIndex(-1)
|
|
,tableStateSource(-1)
|
|
,tableStateTarget(-1)
|
|
,tokenIndexInStream(-1)
|
|
,token(0)
|
|
,transition(0)
|
|
,instructionBegin(-1)
|
|
,instructionCount(-1)
|
|
{
|
|
}
|
|
|
|
operator bool()const
|
|
{
|
|
return transitionType!=ExecuteInstructions || transition!=0;
|
|
}
|
|
|
|
void AddShiftReduceRange(regex::RegexToken* shiftToken, regex::RegexToken* reduceToken)
|
|
{
|
|
ShiftReduceRange range;
|
|
range.shiftToken=shiftToken;
|
|
range.reduceToken=reduceToken;
|
|
if(!shiftReduceRanges)
|
|
{
|
|
shiftReduceRanges=new collections::List<ShiftReduceRange>();
|
|
}
|
|
shiftReduceRanges->Add(range);
|
|
}
|
|
};
|
|
|
|
struct Future
|
|
{
|
|
vint currentState;
|
|
vint reduceStateCount;
|
|
collections::List<vint> shiftStates;
|
|
regex::RegexToken* selectedRegexToken;
|
|
vint selectedToken;
|
|
ParsingTable::TransitionItem* selectedItem;
|
|
Future* previous;
|
|
Future* next;
|
|
|
|
Future()
|
|
:currentState(-1)
|
|
,reduceStateCount(0)
|
|
,selectedRegexToken(0)
|
|
,selectedToken(-1)
|
|
,selectedItem(0)
|
|
,previous(0)
|
|
,next(0)
|
|
{
|
|
}
|
|
|
|
Future* Clone()
|
|
{
|
|
Future* future = new Future;
|
|
future->currentState = currentState;
|
|
future->reduceStateCount = reduceStateCount;
|
|
CopyFrom(future->shiftStates, shiftStates);
|
|
future->selectedRegexToken = selectedRegexToken;
|
|
future->selectedToken = selectedToken;
|
|
future->selectedItem = selectedItem;
|
|
future->previous = previous;
|
|
return future;
|
|
}
|
|
};
|
|
|
|
struct StateGroup
|
|
{
|
|
collections::List<vint> stateStack;
|
|
vint currentState;
|
|
vint tokenSequenceIndex;
|
|
|
|
collections::List<regex::RegexToken*> shiftTokenStack;
|
|
regex::RegexToken* shiftToken;
|
|
regex::RegexToken* reduceToken;
|
|
|
|
StateGroup();
|
|
StateGroup(const ParsingTable::RuleInfo& info);
|
|
StateGroup(const StateGroup& group);
|
|
};
|
|
private:
|
|
WString input;
|
|
Ptr<ParsingTable> table;
|
|
collections::List<regex::RegexToken> tokens;
|
|
Ptr<ParsingTokenWalker> walker;
|
|
|
|
WString parsingRule;
|
|
vint parsingRuleStartState;
|
|
Ptr<StateGroup> stateGroup;
|
|
public:
|
|
ParsingState(const WString& _input, Ptr<ParsingTable> _table, vint codeIndex=-1);
|
|
~ParsingState();
|
|
|
|
const WString& GetInput();
|
|
Ptr<ParsingTable> GetTable();
|
|
const collections::List<regex::RegexToken>& GetTokens();
|
|
regex::RegexToken* GetToken(vint index);
|
|
|
|
vint Reset(const WString& rule);
|
|
WString GetParsingRule();
|
|
vint GetParsingRuleStartState();
|
|
vint GetCurrentToken();
|
|
vint GetCurrentTableTokenIndex();
|
|
const collections::List<vint>& GetStateStack();
|
|
vint GetCurrentState();
|
|
void SkipCurrentToken();
|
|
|
|
bool TestTransitionItemInFuture(vint tableTokenIndex, Future* future, ParsingTable::TransitionItem* item, const collections::IEnumerable<vint>* lookAheadTokens);
|
|
ParsingTable::TransitionItem* MatchTokenInFuture(vint tableTokenIndex, Future* future, const collections::IEnumerable<vint>* lookAheadTokens);
|
|
ParsingTable::TransitionItem* MatchToken(vint tableTokenIndex, const collections::IEnumerable<vint>* lookAheadTokens);
|
|
void RunTransitionInFuture(ParsingTable::TransitionItem* transition, Future* previous, Future* now);
|
|
ParsingState::TransitionResult RunTransition(ParsingTable::TransitionItem* transition, regex::RegexToken* regexToken, vint instructionBegin, vint instructionCount, bool lastPart);
|
|
ParsingState::TransitionResult RunTransition(ParsingTable::TransitionItem* transition, regex::RegexToken* regexToken);
|
|
|
|
bool ReadTokenInFuture(vint tableTokenIndex, Future* previous, Future* now, const collections::IEnumerable<vint>* lookAheadTokens);
|
|
TransitionResult ReadToken(vint tableTokenIndex, regex::RegexToken* regexToken, const collections::IEnumerable<vint>* lookAheadTokens);
|
|
TransitionResult ReadToken();
|
|
|
|
bool TestExplore(vint tableTokenIndex, Future* previous);
|
|
bool Explore(vint tableTokenIndex, Future* previous, collections::List<Future*>& possibilities);
|
|
bool ExploreStep(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities);
|
|
bool ExploreNormalReduce(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities);
|
|
bool ExploreLeftRecursiveReduce(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities);
|
|
Future* ExploreCreateRootFuture();
|
|
|
|
Ptr<StateGroup> TakeSnapshot();
|
|
void RestoreSnapshot(Ptr<StateGroup> group);
|
|
};
|
|
|
|
/***********************************************************************
|
|
AST Generating
|
|
***********************************************************************/
|
|
|
|
class ParsingTransitionProcessor : public Object
|
|
{
|
|
public:
|
|
virtual void Reset()=0;
|
|
virtual bool Run(const ParsingState::TransitionResult& result)=0;
|
|
virtual bool GetProcessingAmbiguityBranch()=0;
|
|
};
|
|
|
|
class ParsingTreeBuilder : public ParsingTransitionProcessor
|
|
{
|
|
protected:
|
|
Ptr<ParsingTreeNode> createdObject;
|
|
Ptr<ParsingTreeObject> operationTarget;
|
|
collections::List<Ptr<ParsingTreeObject>> nodeStack;
|
|
|
|
bool processingAmbiguityBranch;
|
|
Ptr<ParsingTreeNode> ambiguityBranchCreatedObject;
|
|
Ptr<ParsingTreeNode> ambiguityBranchOperationTarget;
|
|
vint ambiguityBranchSharedNodeCount;
|
|
collections::List<Ptr<ParsingTreeObject>> ambiguityBranchNodeStack;
|
|
collections::List<Ptr<ParsingTreeObject>> ambiguityNodes;
|
|
public:
|
|
ParsingTreeBuilder();
|
|
~ParsingTreeBuilder();
|
|
|
|
void Reset()override;
|
|
bool Run(const ParsingState::TransitionResult& result)override;
|
|
bool GetProcessingAmbiguityBranch()override;
|
|
Ptr<ParsingTreeObject> GetNode()const;
|
|
};
|
|
|
|
class ParsingTransitionCollector : public ParsingTransitionProcessor
|
|
{
|
|
typedef collections::List<ParsingState::TransitionResult> TransitionResultList;
|
|
protected:
|
|
vint ambiguityBegin;
|
|
TransitionResultList transitions;
|
|
|
|
collections::Dictionary<vint, vint> ambiguityBeginToEnds;
|
|
collections::Group<vint, vint> ambiguityBeginToBranches;
|
|
collections::Dictionary<vint, vint> ambiguityBranchToBegins;
|
|
public:
|
|
ParsingTransitionCollector();
|
|
~ParsingTransitionCollector();
|
|
|
|
void Reset()override;
|
|
bool Run(const ParsingState::TransitionResult& result)override;
|
|
bool GetProcessingAmbiguityBranch()override;
|
|
|
|
const TransitionResultList& GetTransitions()const;
|
|
vint GetAmbiguityEndFromBegin(vint transitionIndex)const;
|
|
const collections::List<vint>& GetAmbiguityBranchesFromBegin(vint transitionIndex)const;
|
|
vint GetAmbiguityBeginFromBranch(vint transitionIndex)const;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\PARSING.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_PARSING
|
|
#define VCZH_PARSING_PARSING
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace tabling
|
|
{
|
|
|
|
/***********************************************************************
|
|
Parser
|
|
***********************************************************************/
|
|
|
|
/// <summary>Base type of all parser strategy.</summary>
|
|
class ParsingGeneralParser : public Object
|
|
{
|
|
protected:
|
|
Ptr<ParsingTable> table;
|
|
|
|
public:
|
|
ParsingGeneralParser(Ptr<ParsingTable> _table);
|
|
~ParsingGeneralParser();
|
|
|
|
/// <summary>Get the parser table that used to do the parsing.</summary>
|
|
/// <returns>The parser table that used to do the parsing.</returns>
|
|
Ptr<ParsingTable> GetTable();
|
|
/// <summary>Initialization. It should be called before each time of parsing.</summary>
|
|
virtual void BeginParse();
|
|
virtual ParsingState::TransitionResult ParseStep(ParsingState& state, collections::List<Ptr<ParsingError>>& errors)=0;
|
|
bool Parse(ParsingState& state, ParsingTransitionProcessor& processor, collections::List<Ptr<ParsingError>>& errors);
|
|
Ptr<ParsingTreeNode> Parse(ParsingState& state, collections::List<Ptr<ParsingError>>& errors);
|
|
/// <summary>Parse an input and get an abstract syntax tree if no error happens or all errors are recovered.</summary>
|
|
/// <returns>The abstract syntax tree.</returns>
|
|
/// <param name="input">The input to parse.</param>
|
|
/// <param name="rule">The name of the rule that used to parse the input.</param>
|
|
/// <param name="errors">Returns all errors.</param>
|
|
/// <param name="codeIndex">The code index to differentiate each input. This value will be stored in every tokens and abstract syntax nodes.</param>
|
|
Ptr<ParsingTreeNode> Parse(const WString& input, const WString& rule, collections::List<Ptr<ParsingError>>& errors, vint codeIndex = -1);
|
|
};
|
|
|
|
/***********************************************************************
|
|
Parser with different strategies
|
|
***********************************************************************/
|
|
|
|
/// <summary>A strict parse. It doesn't allow ambiguity and error recovery.</summary>
|
|
class ParsingStrictParser : public ParsingGeneralParser
|
|
{
|
|
protected:
|
|
|
|
virtual bool OnTestErrorRecoverExists();
|
|
virtual void OnClearErrorRecover();
|
|
virtual ParsingState::TransitionResult OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<Ptr<ParsingError>>& errors);
|
|
public:
|
|
/// <summary>Create the parse using a parsing table.</summary>
|
|
/// <param name="_table">The parsing table.</param>
|
|
ParsingStrictParser(Ptr<ParsingTable> _table=0);
|
|
~ParsingStrictParser();
|
|
|
|
ParsingState::TransitionResult ParseStep(ParsingState& state, collections::List<Ptr<ParsingError>>& errors)override;
|
|
};
|
|
|
|
/// <summary>A strict parse. It doesn't allow ambiguity but allows error recovery.</summary>
|
|
class ParsingAutoRecoverParser : public ParsingStrictParser
|
|
{
|
|
public:
|
|
struct RecoverFuture
|
|
{
|
|
ParsingState::Future* future;
|
|
vint insertedTokenCount;
|
|
vint index;
|
|
vint previousIndex;
|
|
vint nextIndex;
|
|
|
|
RecoverFuture()
|
|
:future(0)
|
|
, insertedTokenCount(0)
|
|
, index(-1)
|
|
, previousIndex(-1)
|
|
, nextIndex(-1)
|
|
{
|
|
}
|
|
};
|
|
protected:
|
|
vint maxInsertedTokenCount;
|
|
collections::List<RecoverFuture> recoverFutures;
|
|
vint recoveringFutureIndex;
|
|
|
|
RecoverFuture& GetRecoverFuture(vint index);
|
|
RecoverFuture& CreateRecoverFuture(vint index, vint previousIndex);
|
|
bool OnTestErrorRecoverExists()override;
|
|
void OnClearErrorRecover()override;
|
|
ParsingState::TransitionResult OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<Ptr<ParsingError>>& errors)override;
|
|
public:
|
|
/// <summary>Create the parse using a parsing table.</summary>
|
|
/// <param name="_table">The parsing table.</param>
|
|
/// <param name="_maxInsertedTokenCount">The maximum number of tokens that allow to insert to recover an error.</param>
|
|
ParsingAutoRecoverParser(Ptr<ParsingTable> _table = 0, vint _maxInsertedTokenCount = -1);
|
|
~ParsingAutoRecoverParser();
|
|
|
|
void BeginParse()override;
|
|
};
|
|
|
|
/// <summary>A strict parse. It allows ambiguity but doesn't allow error recovery.</summary>
|
|
class ParsingAmbiguousParser : public ParsingGeneralParser
|
|
{
|
|
typedef collections::List<ParsingState::TransitionResult> DecisionList;
|
|
protected:
|
|
|
|
DecisionList decisions;
|
|
vint consumedDecisionCount;
|
|
|
|
virtual void OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors);
|
|
vint GetResolvableFutureLevels(collections::List<ParsingState::Future*>& futures, vint begin, vint end);
|
|
vint SearchPathForOneStep(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors);
|
|
vint GetConflictReduceCount(collections::List<ParsingState::Future*>& futures);
|
|
void GetConflictReduceIndices(collections::List<ParsingState::Future*>& futures, vint conflictReduceCount, collections::Array<vint>& conflictReduceIndices);
|
|
vint GetAffectedStackNodeCount(collections::List<ParsingState::Future*>& futures, collections::Array<vint>& conflictReduceIndices);
|
|
void BuildSingleDecisionPath(ParsingState& state, ParsingState::Future* future, vint lastAvailableInstructionCount);
|
|
void BuildAmbiguousDecisions(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List<Ptr<ParsingError>>& errors);
|
|
void BuildDecisions(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List<Ptr<ParsingError>>& errors);
|
|
public:
|
|
/// <summary>Create the parse using a parsing table.</summary>
|
|
/// <param name="_table">The parsing table.</param>
|
|
ParsingAmbiguousParser(Ptr<ParsingTable> _table=0);
|
|
~ParsingAmbiguousParser();
|
|
|
|
ParsingState::TransitionResult ParseStep(ParsingState& state, collections::List<Ptr<ParsingError>>& errors)override;
|
|
void BeginParse()override;
|
|
};
|
|
|
|
/// <summary>A strict parse. It allow both ambiguity and error recovery.</summary>
|
|
class ParsingAutoRecoverAmbiguousParser : public ParsingAmbiguousParser
|
|
{
|
|
protected:
|
|
vint maxInsertedTokenCount;
|
|
|
|
void OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors)override;
|
|
public:
|
|
/// <summary>Create the parse using a parsing table.</summary>
|
|
/// <param name="_table">The parsing table.</param>
|
|
/// <param name="_maxInsertedTokenCount">The maximum number of tokens that allow to insert to recover an error.</param>
|
|
ParsingAutoRecoverAmbiguousParser(Ptr<ParsingTable> _table = 0, vint _maxInsertedTokenCount = -1);
|
|
~ParsingAutoRecoverAmbiguousParser();
|
|
};
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
/// <summary>Create the correct strict parser from a parsing table.</summary>
|
|
/// <returns>The created parse.</returns>
|
|
/// <param name="table">The table to create a parser.</param>
|
|
extern Ptr<ParsingGeneralParser> CreateStrictParser(Ptr<ParsingTable> table);
|
|
/// <summary>Create the correct error recoverable parser from a parsing table.</summary>
|
|
/// <returns>The created parse.</returns>
|
|
/// <param name="table">The table to create a parser.</param>
|
|
extern Ptr<ParsingGeneralParser> CreateAutoRecoverParser(Ptr<ParsingTable> table);
|
|
/// <summary>Create the correct strict parser to parse the grammar itself.</summary>
|
|
/// <returns>The created parse.</returns>
|
|
extern Ptr<ParsingGeneralParser> CreateBootstrapStrictParser();
|
|
/// <summary>Create the correct error recoverable to parse the grammar itself.</summary>
|
|
/// <returns>The created parse.</returns>
|
|
extern Ptr<ParsingGeneralParser> CreateBootstrapAutoRecoverParser();
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Reflection for AST
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#define PARSINGREFLECTION_TYPELIST(F)\
|
|
F(parsing::ParsingTextPos)\
|
|
F(parsing::ParsingTextRange)\
|
|
F(parsing::ParsingTreeNode)\
|
|
F(parsing::ParsingTreeToken)\
|
|
F(parsing::ParsingTreeObject)\
|
|
F(parsing::ParsingTreeArray)\
|
|
F(parsing::ParsingTreeCustomBase)\
|
|
F(parsing::ParsingToken)\
|
|
F(parsing::ParsingError)\
|
|
|
|
PARSINGREFLECTION_TYPELIST(DECL_TYPE_INFO)
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
extern bool LoadParsingTypes();
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\PARSINGJSON_AST.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:ParsingJson.parser.txt
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_JSON_PARSINGJSON_PARSER_AST
|
|
#define VCZH_PARSING_JSON_PARSINGJSON_PARSER_AST
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace json
|
|
{
|
|
/// <summary>Token types. Values of enum items will be used in <see cref="vl::regex::RegexToken::token"/>.</summary>
|
|
enum class JsonParserTokenIndex
|
|
{
|
|
/// <summary>Token TRUEVALUE: true</summary>
|
|
TRUEVALUE = 0,
|
|
/// <summary>Token FALSEVALUE: false</summary>
|
|
FALSEVALUE = 1,
|
|
/// <summary>Token NULLVALUE: null</summary>
|
|
NULLVALUE = 2,
|
|
/// <summary>Token OBJOPEN: \{</summary>
|
|
OBJOPEN = 3,
|
|
/// <summary>Token OBJCLOSE: \}</summary>
|
|
OBJCLOSE = 4,
|
|
/// <summary>Token ARROPEN: \[</summary>
|
|
ARROPEN = 5,
|
|
/// <summary>Token ARRCLOSE: \]</summary>
|
|
ARRCLOSE = 6,
|
|
/// <summary>Token COMMA: ,</summary>
|
|
COMMA = 7,
|
|
/// <summary>Token COLON: :</summary>
|
|
COLON = 8,
|
|
/// <summary>Token NUMBER: [\-]?\d+(.\d+)?([eE][+\-]?\d+)?</summary>
|
|
NUMBER = 9,
|
|
/// <summary>Token STRING: "([^\\"]|\\[^u]|\\u\d{4})*"</summary>
|
|
STRING = 10,
|
|
/// <summary>Discardable token SPACE: \s+</summary>
|
|
SPACE = 11,
|
|
};
|
|
class JsonNode;
|
|
class JsonLiteral;
|
|
class JsonString;
|
|
class JsonNumber;
|
|
class JsonArray;
|
|
class JsonObjectField;
|
|
class JsonObject;
|
|
|
|
/// <summary>Base class of JSON nodes.</summary>
|
|
class JsonNode abstract : public vl::parsing::ParsingTreeCustomBase, vl::reflection::Description<JsonNode>
|
|
{
|
|
public:
|
|
/// <summary>Visitor interface for <see cref="JsonNode"/>.</summary>
|
|
class IVisitor : public vl::reflection::IDescriptable, vl::reflection::Description<IVisitor>
|
|
{
|
|
public:
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="JsonLiteral"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(JsonLiteral* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="JsonString"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(JsonString* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="JsonNumber"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(JsonNumber* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="JsonArray"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(JsonArray* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="JsonObjectField"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(JsonObjectField* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="JsonObject"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(JsonObject* node)=0;
|
|
};
|
|
|
|
/// <summary>Accept a visitor to reveal its real type of this strong-typed AST node.</summary>
|
|
/// <param name="visitor">The visitor, one of its <b>Visit</b> method will be called according to the real type of this strong-typed AST node.</param>
|
|
virtual void Accept(JsonNode::IVisitor* visitor)=0;
|
|
|
|
};
|
|
|
|
/// <summary>Literal value node that is not number or string.</summary>
|
|
class JsonLiteral : public JsonNode, vl::reflection::Description<JsonLiteral>
|
|
{
|
|
public:
|
|
/// <summary>Literal value.</summary>
|
|
enum class JsonValue
|
|
{
|
|
/// <summary>A boolean literal: true.</summary>
|
|
True,
|
|
/// <summary>A boolean literal: false.</summary>
|
|
False,
|
|
/// <summary>A null literal.</summary>
|
|
Null,
|
|
};
|
|
|
|
/// <summary>The literal value.</summary>
|
|
JsonValue value;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<JsonLiteral> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>String literal value node.</summary>
|
|
class JsonString : public JsonNode, vl::reflection::Description<JsonString>
|
|
{
|
|
public:
|
|
/// <summary>Content of the string literal.</summary>
|
|
vl::parsing::ParsingToken content;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<JsonString> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Number literal value node.</summary>
|
|
class JsonNumber : public JsonNode, vl::reflection::Description<JsonNumber>
|
|
{
|
|
public:
|
|
/// <summary>Content of the number literal.</summary>
|
|
vl::parsing::ParsingToken content;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<JsonNumber> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Array node.</summary>
|
|
class JsonArray : public JsonNode, vl::reflection::Description<JsonArray>
|
|
{
|
|
public:
|
|
/// <summary>Array elements.</summary>
|
|
vl::collections::List<vl::Ptr<JsonNode>> items;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<JsonArray> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Object property node.</summary>
|
|
class JsonObjectField : public JsonNode, vl::reflection::Description<JsonObjectField>
|
|
{
|
|
public:
|
|
/// <summary>Property name.</summary>
|
|
vl::parsing::ParsingToken name;
|
|
/// <summary>Property value.</summary>
|
|
vl::Ptr<JsonNode> value;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<JsonObjectField> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Object node.</summary>
|
|
class JsonObject : public JsonNode, vl::reflection::Description<JsonObject>
|
|
{
|
|
public:
|
|
/// <summary>Object properties.</summary>
|
|
vl::collections::List<vl::Ptr<JsonObjectField>> fields;
|
|
|
|
void Accept(JsonNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<JsonObject> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
}
|
|
}
|
|
}
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonNode)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonLiteral)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonLiteral::JsonValue)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonString)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonNumber)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonArray)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonObjectField)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonObject)
|
|
DECL_TYPE_INFO(vl::parsing::json::JsonNode::IVisitor)
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(vl::parsing::json::JsonNode::IVisitor)
|
|
void Visit(vl::parsing::json::JsonLiteral* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::json::JsonString* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::json::JsonNumber* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::json::JsonArray* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::json::JsonObjectField* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::json::JsonObject* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
END_INTERFACE_PROXY(vl::parsing::json::JsonNode::IVisitor)
|
|
|
|
#endif
|
|
#endif
|
|
/// <summary>Load all reflectable AST types, only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is off.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
extern bool JsonLoadTypes();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\PARSINGJSON_PARSER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:ParsingJson.parser.txt
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_JSON_PARSINGJSON_PARSER_PARSER
|
|
#define VCZH_PARSING_JSON_PARSINGJSON_PARSER_PARSER
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace json
|
|
{
|
|
/// <summary>Get the grammar definition for this parser.</summary>
|
|
/// <returns>The grammar definition for this parser.</returns>
|
|
extern vl::WString JsonGetParserTextBuffer();
|
|
/// <summary>Convert parser result to a strong typed AST node. Usually you don't need to use this function, unless you are doing meta programming like error recovering or implementing intellisense for an editor.</summary>
|
|
/// <returns>Returns the strong typed AST node.</returns>
|
|
/// <param name="node">The parser result.</param>
|
|
/// <param name="tokens">Tokens for parsing. You can get the <see cref="vl::regex::RegexLexer"/> by calling <see cref="vl::parsing::tabling::ParsingTable::GetLexer"/> from <see cref="JsonLoadTable"/></param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeCustomBase> JsonConvertParsingTreeNode(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
/// <summary>Create the parser table. You should cache the value if possible, for improving performance.</summary>
|
|
/// <returns>The created parser table.</returns>
|
|
extern vl::Ptr<vl::parsing::tabling::ParsingTable> JsonLoadTable();
|
|
|
|
/// <summary>Parse a JSON text, it could be an object or an array.</summary>
|
|
/// <returns>Returns the parsing result as a weak-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="JsonLoadTable"/>.</param>
|
|
/// <param name="errors">All errors during parsing.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeNode> JsonParseAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex = -1);
|
|
/// <summary>Parse a JSON text, it could be an object or an array.</summary>
|
|
/// <returns>Returns the parsing result as a weak-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="JsonLoadTable"/>.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeNode> JsonParseAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex = -1);
|
|
/// <summary>Parse a JSON text, it could be an object or an array.</summary>
|
|
/// <returns>Returns the parsing result as a strong-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="JsonLoadTable"/>.</param>
|
|
/// <param name="errors">All errors during parsing.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<JsonNode> JsonParse(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex = -1);
|
|
/// <summary>Parse a JSON text, it could be an object or an array.</summary>
|
|
/// <returns>Returns the parsing result as a strong-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="JsonLoadTable"/>.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<JsonNode> JsonParse(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex = -1);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\JSON\PARSINGJSON.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingJson_Parser
|
|
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_JSON_PARSINGJSON
|
|
#define VCZH_PARSING_JSON_PARSINGJSON
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace json
|
|
{
|
|
extern void JsonEscapeString(const WString& text, stream::TextWriter& writer);
|
|
extern void JsonUnescapeString(const WString& text, stream::TextWriter& writer);
|
|
|
|
/// <summary>Serialize JSON to string.</summary>
|
|
/// <param name="node">The JSON node to serialize.</param>
|
|
/// <param name="writer">The text writer to receive the string.</param>
|
|
extern void JsonPrint(Ptr<JsonNode> node, stream::TextWriter& writer);
|
|
|
|
/// <summary>Serialize JSON to string.</summary>
|
|
/// <returns>The serialized string.</returns>
|
|
/// <param name="node">The JSON node to serialize.</param>
|
|
extern WString JsonToString(Ptr<JsonNode> node);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\PARSINGXML_AST.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:ParsingXml.parser.txt
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_XML_PARSINGXML_PARSER_AST
|
|
#define VCZH_PARSING_XML_PARSINGXML_PARSER_AST
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace xml
|
|
{
|
|
/// <summary>Token types. Values of enum items will be used in <see cref="vl::regex::RegexToken::token"/>.</summary>
|
|
enum class XmlParserTokenIndex
|
|
{
|
|
/// <summary>Token INSTRUCTION_OPEN: /</?</summary>
|
|
INSTRUCTION_OPEN = 0,
|
|
/// <summary>Token INSTRUCTION_CLOSE: /?/></summary>
|
|
INSTRUCTION_CLOSE = 1,
|
|
/// <summary>Token COMPLEX_ELEMENT_OPEN: /<//</summary>
|
|
COMPLEX_ELEMENT_OPEN = 2,
|
|
/// <summary>Token SINGLE_ELEMENT_CLOSE: ///></summary>
|
|
SINGLE_ELEMENT_CLOSE = 3,
|
|
/// <summary>Token ELEMENT_OPEN: /<</summary>
|
|
ELEMENT_OPEN = 4,
|
|
/// <summary>Token ELEMENT_CLOSE: /></summary>
|
|
ELEMENT_CLOSE = 5,
|
|
/// <summary>Token EQUAL: /=</summary>
|
|
EQUAL = 6,
|
|
/// <summary>Token NAME: [a-zA-Z0-9:._/-]+</summary>
|
|
NAME = 7,
|
|
/// <summary>Token ATTVALUE: "[^<>"]*"|'[^<>']*'</summary>
|
|
ATTVALUE = 8,
|
|
/// <summary>Token COMMENT: /</!--([^/->]|-[^/->]|--[^>])*--/></summary>
|
|
COMMENT = 9,
|
|
/// <summary>Token CDATA: /</!/[CDATA/[([^/]]|/][^/]]|/]/][^>])*/]/]/></summary>
|
|
CDATA = 10,
|
|
/// <summary>Token TEXT: ([^<>="' /r/n/ta-zA-Z0-9:._/-])+|"|'</summary>
|
|
TEXT = 11,
|
|
/// <summary>Discardable token SPACE: /s+</summary>
|
|
SPACE = 12,
|
|
};
|
|
class XmlNode;
|
|
class XmlText;
|
|
class XmlCData;
|
|
class XmlAttribute;
|
|
class XmlComment;
|
|
class XmlElement;
|
|
class XmlInstruction;
|
|
class XmlDocument;
|
|
|
|
/// <summary>Base class of XML nodes.</summary>
|
|
class XmlNode abstract : public vl::parsing::ParsingTreeCustomBase, vl::reflection::Description<XmlNode>
|
|
{
|
|
public:
|
|
/// <summary>Visitor interface for <see cref="XmlNode"/>.</summary>
|
|
class IVisitor : public vl::reflection::IDescriptable, vl::reflection::Description<IVisitor>
|
|
{
|
|
public:
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="XmlText"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(XmlText* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="XmlCData"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(XmlCData* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="XmlAttribute"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(XmlAttribute* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="XmlComment"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(XmlComment* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="XmlElement"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(XmlElement* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="XmlInstruction"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(XmlInstruction* node)=0;
|
|
/// <summary>A callback that is called if the node accepting this visitor is <see cref="XmlDocument"/>.</summary>
|
|
/// <param name="node">The strong-typed AST node in its real type.</param>
|
|
virtual void Visit(XmlDocument* node)=0;
|
|
};
|
|
|
|
/// <summary>Accept a visitor to reveal its real type of this strong-typed AST node.</summary>
|
|
/// <param name="visitor">The visitor, one of its <b>Visit</b> method will be called according to the real type of this strong-typed AST node.</param>
|
|
virtual void Accept(XmlNode::IVisitor* visitor)=0;
|
|
|
|
};
|
|
|
|
/// <summary>Text node.</summary>
|
|
class XmlText : public XmlNode, vl::reflection::Description<XmlText>
|
|
{
|
|
public:
|
|
/// <summary>Content of the text node.</summary>
|
|
vl::parsing::ParsingToken content;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<XmlText> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>CData node.</summary>
|
|
class XmlCData : public XmlNode, vl::reflection::Description<XmlCData>
|
|
{
|
|
public:
|
|
/// <summary>Content of the cdata node</summary>
|
|
vl::parsing::ParsingToken content;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<XmlCData> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Attribute node.</summary>
|
|
class XmlAttribute : public XmlNode, vl::reflection::Description<XmlAttribute>
|
|
{
|
|
public:
|
|
/// <summary>Attribute name.</summary>
|
|
vl::parsing::ParsingToken name;
|
|
/// <summary>Attribute value.</summary>
|
|
vl::parsing::ParsingToken value;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<XmlAttribute> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Comment node.</summary>
|
|
class XmlComment : public XmlNode, vl::reflection::Description<XmlComment>
|
|
{
|
|
public:
|
|
/// <summary>Content of the comment node.</summary>
|
|
vl::parsing::ParsingToken content;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<XmlComment> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Element node.</summary>
|
|
class XmlElement : public XmlNode, vl::reflection::Description<XmlElement>
|
|
{
|
|
public:
|
|
/// <summary>Element name of the open element node.</summary>
|
|
vl::parsing::ParsingToken name;
|
|
/// <summary>(Optional): Element name of the closing element node. The name is ignored when serializing XML to text.</summary>
|
|
vl::parsing::ParsingToken closingName;
|
|
/// <summary>Attributes of the element.</summary>
|
|
vl::collections::List<vl::Ptr<XmlAttribute>> attributes;
|
|
/// <summary>Sub nodes for element nodes, text nodes, cdata nodes and comment nodes.</summary>
|
|
vl::collections::List<vl::Ptr<XmlNode>> subNodes;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<XmlElement> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>Instruction node.</summary>
|
|
class XmlInstruction : public XmlNode, vl::reflection::Description<XmlInstruction>
|
|
{
|
|
public:
|
|
/// <summary>Name of the instruction.</summary>
|
|
vl::parsing::ParsingToken name;
|
|
/// <summary>Attributes of the instruction.</summary>
|
|
vl::collections::List<vl::Ptr<XmlAttribute>> attributes;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<XmlInstruction> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
/// <summary>XML document node.</summary>
|
|
class XmlDocument : public XmlNode, vl::reflection::Description<XmlDocument>
|
|
{
|
|
public:
|
|
/// <summary>Prologue nodes, for instructions and comments.</summary>
|
|
vl::collections::List<vl::Ptr<XmlNode>> prologs;
|
|
/// <summary>Root element of the XML document.</summary>
|
|
vl::Ptr<XmlElement> rootElement;
|
|
|
|
void Accept(XmlNode::IVisitor* visitor)override;
|
|
|
|
static vl::Ptr<XmlDocument> Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
};
|
|
|
|
}
|
|
}
|
|
}
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlNode)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlText)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlCData)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlAttribute)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlComment)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlElement)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlInstruction)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlDocument)
|
|
DECL_TYPE_INFO(vl::parsing::xml::XmlNode::IVisitor)
|
|
|
|
#ifdef VCZH_DESCRIPTABLEOBJECT_WITH_METADATA
|
|
|
|
BEGIN_INTERFACE_PROXY_NOPARENT_SHAREDPTR(vl::parsing::xml::XmlNode::IVisitor)
|
|
void Visit(vl::parsing::xml::XmlText* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::xml::XmlCData* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::xml::XmlAttribute* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::xml::XmlComment* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::xml::XmlElement* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::xml::XmlInstruction* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
void Visit(vl::parsing::xml::XmlDocument* node)override
|
|
{
|
|
INVOKE_INTERFACE_PROXY(Visit, node);
|
|
}
|
|
|
|
END_INTERFACE_PROXY(vl::parsing::xml::XmlNode::IVisitor)
|
|
|
|
#endif
|
|
#endif
|
|
/// <summary>Load all reflectable AST types, only available when <b>VCZH_DEBUG_NO_REFLECTION</b> is off.</summary>
|
|
/// <returns>Returns true if this operation succeeded.</returns>
|
|
extern bool XmlLoadTypes();
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\PARSINGXML_PARSER.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
This file is generated by: Vczh Parser Generator
|
|
From parser definition:ParsingXml.parser.txt
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_XML_PARSINGXML_PARSER_PARSER
|
|
#define VCZH_PARSING_XML_PARSINGXML_PARSER_PARSER
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace xml
|
|
{
|
|
/// <summary>Get the grammar definition for this parser.</summary>
|
|
/// <returns>The grammar definition for this parser.</returns>
|
|
extern vl::WString XmlGetParserTextBuffer();
|
|
/// <summary>Convert parser result to a strong typed AST node. Usually you don't need to use this function, unless you are doing meta programming like error recovering or implementing intellisense for an editor.</summary>
|
|
/// <returns>Returns the strong typed AST node.</returns>
|
|
/// <param name="node">The parser result.</param>
|
|
/// <param name="tokens">Tokens for parsing. You can get the <see cref="vl::regex::RegexLexer"/> by calling <see cref="vl::parsing::tabling::ParsingTable::GetLexer"/> from <see cref="XmlLoadTable"/></param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeCustomBase> XmlConvertParsingTreeNode(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
/// <summary>Create the parser table. You should cache the value if possible, for improving performance.</summary>
|
|
/// <returns>The created parser table.</returns>
|
|
extern vl::Ptr<vl::parsing::tabling::ParsingTable> XmlLoadTable();
|
|
|
|
/// <summary>Parse an XML document.</summary>
|
|
/// <returns>Returns the parsing result as a weak-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="errors">All errors during parsing.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseDocumentAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex = -1);
|
|
/// <summary>Parse an XML document.</summary>
|
|
/// <returns>Returns the parsing result as a weak-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseDocumentAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex = -1);
|
|
/// <summary>Parse an XML document.</summary>
|
|
/// <returns>Returns the parsing result as a strong-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="errors">All errors during parsing.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<XmlDocument> XmlParseDocument(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex = -1);
|
|
/// <summary>Parse an XML document.</summary>
|
|
/// <returns>Returns the parsing result as a strong-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<XmlDocument> XmlParseDocument(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex = -1);
|
|
|
|
/// <summary>Parse an XML element.</summary>
|
|
/// <returns>Returns the parsing result as a weak-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="errors">All errors during parsing.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseElementAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex = -1);
|
|
/// <summary>Parse an XML element.</summary>
|
|
/// <returns>Returns the parsing result as a weak-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseElementAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex = -1);
|
|
/// <summary>Parse an XML element.</summary>
|
|
/// <returns>Returns the parsing result as a strong-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="errors">All errors during parsing.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<XmlElement> XmlParseElement(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::collections::List<vl::Ptr<vl::parsing::ParsingError>>& errors, vl::vint codeIndex = -1);
|
|
/// <summary>Parse an XML element.</summary>
|
|
/// <returns>Returns the parsing result as a strong-typed AST node. Returns null if there is any unrecoverable error during parsing.</returns>
|
|
/// <param name="input">The input for parsing.</param>
|
|
/// <param name="table">The return value from <see cref="XmlLoadTable"/>.</param>
|
|
/// <param name="codeIndex">(Optional): This argument will be copied to <see cref="vl::parsing::ParsingTextRange::codeIndex"/> in every AST nodes. The default value is -1.</param>
|
|
extern vl::Ptr<XmlElement> XmlParseElement(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex = -1);
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
.\XML\PARSINGXML.H
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingXml
|
|
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_PARSING_XML_PARSINGXML
|
|
#define VCZH_PARSING_XML_PARSINGXML
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace xml
|
|
{
|
|
extern WString XmlEscapeValue(const WString& value);
|
|
extern WString XmlUnescapeValue(const WString& value);
|
|
extern WString XmlEscapeCData(const WString& value);
|
|
extern WString XmlUnescapeCData(const WString& value);
|
|
extern WString XmlEscapeComment(const WString& value);
|
|
extern WString XmlUnescapeComment(const WString& value);
|
|
|
|
/// <summary>Serialize XML to string.</summary>
|
|
/// <param name="node">The XML node to serialize.</param>
|
|
/// <param name="writer">The text writer to receive the string.</param>
|
|
extern void XmlPrint(Ptr<XmlNode> node, stream::TextWriter& writer);
|
|
|
|
/// <summary>Serialize sub nodes in an XML element to string.</summary>
|
|
/// <param name="element">The XML element in which sub nodes are to be serialized.</param>
|
|
/// <param name="writer">The text writer to receive the string.</param>
|
|
extern void XmlPrintContent(Ptr<XmlElement> element, stream::TextWriter& writer);
|
|
|
|
/// <summary>Serialize XML to string.</summary>
|
|
/// <returns>The serialized string.</returns>
|
|
/// <param name="node">The XML node to serialize.</param>
|
|
extern WString XmlToString(Ptr<XmlNode> node);
|
|
|
|
/// <summary>Try to read an attribute in an XML element.</summary>
|
|
/// <returns>The expected attribute. Returns null if it doesn't exist.</returns>
|
|
/// <param name="element">The element to find the attribute.</param>
|
|
/// <param name="name">The name of the attribute.</param>
|
|
extern Ptr<XmlAttribute> XmlGetAttribute(Ptr<XmlElement> element, const WString& name);
|
|
|
|
/// <summary>Try to read a sub element in an XML element.</summary>
|
|
/// <returns>The expected sub element. Returns null if it doesn't exist. If there are multiple elements of the expected name, returns the first one.</returns>
|
|
/// <param name="element">The element to find the sub element.</param>
|
|
/// <param name="name">The name of the sub element.</param>
|
|
extern Ptr<XmlElement> XmlGetElement(Ptr<XmlElement> element, const WString& name);
|
|
|
|
/// <summary>Get all sub elements in an XML element.</summary>
|
|
/// <returns>All sub elements in an XML element.</returns>
|
|
/// <param name="element">The container XML element.</param>
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element);
|
|
|
|
/// <summary>Try to read sub elements in an XML element.</summary>
|
|
/// <returns>Expected sub elements. All sub elements of the expected name will be returned.</returns>
|
|
/// <param name="element">The element to find sub elements.</param>
|
|
/// <param name="name">The name of sub elements.</param>
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element, const WString& name);
|
|
|
|
/// <summary>Serialize contents in an XML element.</summary>
|
|
/// <returns>The serialized contents in an XML element.</returns>
|
|
/// <param name="element">The XML element in which contents are to be serialized.</param>
|
|
extern WString XmlGetValue(Ptr<XmlElement> element);
|
|
|
|
extern Ptr<XmlAttribute> XmlGetAttribute(XmlElement* element, const WString& name);
|
|
extern Ptr<XmlElement> XmlGetElement(XmlElement* element, const WString& name);
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element);
|
|
extern collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element, const WString& name);
|
|
extern WString XmlGetValue(XmlElement* element);
|
|
|
|
class XmlElementWriter : public Object
|
|
{
|
|
protected:
|
|
Ptr<XmlElement> element;
|
|
const XmlElementWriter* previousWriter;
|
|
|
|
public:
|
|
XmlElementWriter(Ptr<XmlElement> _element, const XmlElementWriter* _previousWriter=0);
|
|
~XmlElementWriter();
|
|
|
|
const XmlElementWriter& Attribute(const WString& name, const WString& value)const;
|
|
XmlElementWriter Element(const WString& name)const;
|
|
const XmlElementWriter& End()const;
|
|
const XmlElementWriter& Text(const WString& value)const;
|
|
const XmlElementWriter& CData(const WString& value)const;
|
|
const XmlElementWriter& Comment(const WString& value)const;
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|