mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-07 12:41:38 +08:00
11183 lines
367 KiB
C++
11183 lines
367 KiB
C++
/***********************************************************************
|
|
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
|
|
DEVELOPER: Zihan Chen(vczh)
|
|
***********************************************************************/
|
|
#include "VlppParser.h"
|
|
|
|
/***********************************************************************
|
|
.\PARSING.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace tabling
|
|
{
|
|
using namespace definitions;
|
|
using namespace analyzing;
|
|
using namespace collections;
|
|
using namespace regex;
|
|
|
|
/***********************************************************************
|
|
ParsingGeneralParser
|
|
***********************************************************************/
|
|
|
|
ParsingGeneralParser::ParsingGeneralParser(Ptr<ParsingTable> _table)
|
|
:table(_table)
|
|
{
|
|
}
|
|
|
|
ParsingGeneralParser::~ParsingGeneralParser()
|
|
{
|
|
}
|
|
|
|
Ptr<ParsingTable> ParsingGeneralParser::GetTable()
|
|
{
|
|
return table;
|
|
}
|
|
|
|
void ParsingGeneralParser::BeginParse()
|
|
{
|
|
}
|
|
|
|
bool ParsingGeneralParser::Parse(ParsingState& state, ParsingTransitionProcessor& processor, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
BeginParse();
|
|
processor.Reset();
|
|
|
|
for(vint i=0;i<state.GetTokens().Count();i++)
|
|
{
|
|
const RegexToken* token=&state.GetTokens().Get(i);
|
|
if(token->token==-1 || !token->completeToken)
|
|
{
|
|
errors.Add(new ParsingError(token, L"Unrecognizable token: \""+WString(token->reading, token->length)+L"\"."));
|
|
}
|
|
}
|
|
|
|
while(true)
|
|
{
|
|
ParsingState::TransitionResult result=ParseStep(state, errors);
|
|
if(!result)
|
|
{
|
|
const RegexToken* token=state.GetToken(state.GetCurrentToken());
|
|
errors.Add(new ParsingError(token, L"Internal error when parsing."));
|
|
return false;
|
|
}
|
|
else if(result.transitionType==ParsingState::TransitionResult::SkipToken)
|
|
{
|
|
if(state.GetCurrentTableTokenIndex()==ParsingTable::TokenFinish)
|
|
{
|
|
const RegexToken* token=state.GetToken(state.GetCurrentToken());
|
|
errors.Add(new ParsingError(token, L"Failed to recover error when reaching the end of the input."));
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
state.SkipCurrentToken();
|
|
continue;
|
|
}
|
|
}
|
|
else if(!processor.Run(result))
|
|
{
|
|
const RegexToken* token=state.GetToken(state.GetCurrentToken());
|
|
errors.Add(new ParsingError(token, L"Internal error when building the parsing tree."));
|
|
return false;
|
|
}
|
|
if(result.tableTokenIndex==ParsingTable::TokenFinish && !processor.GetProcessingAmbiguityBranch())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Ptr<ParsingTreeNode> ParsingGeneralParser::Parse(ParsingState& state, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
ParsingTreeBuilder builder;
|
|
Parse(state, builder, errors);
|
|
|
|
Ptr<ParsingTreeNode> node=builder.GetNode();
|
|
if(!node)
|
|
{
|
|
errors.Add(new ParsingError(L"Internal error when building the parsing tree after a succeeded parsing process."));
|
|
return 0;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
Ptr<ParsingTreeNode> ParsingGeneralParser::Parse(const WString& input, const WString& rule, collections::List<Ptr<ParsingError>>& errors, vint codeIndex)
|
|
{
|
|
ParsingState state(input, table, codeIndex);
|
|
if(state.Reset(rule)==-1)
|
|
{
|
|
errors.Add(new ParsingError(L"Rule \""+rule+L"\" does not exist."));
|
|
return 0;
|
|
}
|
|
return Parse(state, errors);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingStrictParser
|
|
***********************************************************************/
|
|
|
|
bool ParsingStrictParser::OnTestErrorRecoverExists()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
void ParsingStrictParser::OnClearErrorRecover()
|
|
{
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingStrictParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
const RegexToken* token=state.GetToken(state.GetCurrentToken());
|
|
errors.Add(new ParsingError(token, (token==0?L"Error happened during parsing when reaching the end of the input.":L"Error happened during parsing.")));
|
|
return ParsingState::TransitionResult();
|
|
}
|
|
|
|
ParsingStrictParser::ParsingStrictParser(Ptr<ParsingTable> _table)
|
|
:ParsingGeneralParser(_table)
|
|
{
|
|
}
|
|
|
|
ParsingStrictParser::~ParsingStrictParser()
|
|
{
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingStrictParser::ParseStep(ParsingState& state, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
ParsingState::TransitionResult result;
|
|
if (OnTestErrorRecoverExists())
|
|
{
|
|
result = OnErrorRecover(state, -1, errors);
|
|
}
|
|
else
|
|
{
|
|
result = state.ReadToken();
|
|
if (result)
|
|
{
|
|
OnClearErrorRecover();
|
|
}
|
|
else
|
|
{
|
|
vint currentTokenIndex = state.GetCurrentTableTokenIndex();
|
|
if (currentTokenIndex != -1)
|
|
{
|
|
result = OnErrorRecover(state, currentTokenIndex, errors);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingAutoRecoverParser
|
|
***********************************************************************/
|
|
|
|
ParsingAutoRecoverParser::RecoverFuture& ParsingAutoRecoverParser::GetRecoverFuture(vint index)
|
|
{
|
|
return recoverFutures[index];
|
|
}
|
|
|
|
ParsingAutoRecoverParser::RecoverFuture& ParsingAutoRecoverParser::CreateRecoverFuture(vint index, vint previousIndex)
|
|
{
|
|
RecoverFuture* rf = 0;
|
|
if (index >= recoverFutures.Count())
|
|
{
|
|
CHECK_ERROR(index == recoverFutures.Count(), L"ParsingAutoRecoverParser::CreateRecoverFuture(vint, vint)#Wrong argument: index.");
|
|
RecoverFuture recoverFuture;
|
|
recoverFuture.future = new ParsingState::Future;
|
|
index = recoverFutures.Add(recoverFuture);
|
|
}
|
|
rf = &GetRecoverFuture(index);
|
|
rf->index = index;
|
|
rf->previousIndex = previousIndex;
|
|
return *rf;
|
|
}
|
|
|
|
bool ParsingAutoRecoverParser::OnTestErrorRecoverExists()
|
|
{
|
|
return recoveringFutureIndex != -1;
|
|
}
|
|
|
|
void ParsingAutoRecoverParser::OnClearErrorRecover()
|
|
{
|
|
recoveringFutureIndex = -1;
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingAutoRecoverParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
if(recoveringFutureIndex==-1)
|
|
{
|
|
List<vint> prioritizedTokens;
|
|
prioritizedTokens.Add(ParsingTable::TokenFinish);
|
|
CopyFrom(
|
|
prioritizedTokens,
|
|
Range<vint>(ParsingTable::UserTokenStart, table->GetTokenCount() - ParsingTable::UserTokenStart)
|
|
);
|
|
prioritizedTokens.Add(ParsingTable::LeftRecursiveReduce);
|
|
prioritizedTokens.Add(ParsingTable::NormalReduce);
|
|
prioritizedTokens.Remove(currentTokenIndex);
|
|
prioritizedTokens.Insert(0, currentTokenIndex);
|
|
|
|
vint processingFutureIndex=-1;
|
|
vint usedFutureCount=0;
|
|
while(processingFutureIndex<usedFutureCount)
|
|
{
|
|
RecoverFuture previous;
|
|
if(processingFutureIndex!=-1)
|
|
{
|
|
previous = GetRecoverFuture(processingFutureIndex);
|
|
}
|
|
processingFutureIndex++;
|
|
if(previous.future && previous.future->currentState==-1) continue;
|
|
|
|
FOREACH(vint, currentTableTokenIndex, prioritizedTokens)
|
|
{
|
|
vint newInsertedTokenCount = previous.insertedTokenCount;
|
|
if (currentTableTokenIndex != ParsingTable::NormalReduce && currentTableTokenIndex != ParsingTable::LeftRecursiveReduce)
|
|
{
|
|
newInsertedTokenCount++;
|
|
}
|
|
if (currentTableTokenIndex != currentTokenIndex && newInsertedTokenCount > maxInsertedTokenCount)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
RecoverFuture& now = CreateRecoverFuture(usedFutureCount, previous.index);
|
|
now.insertedTokenCount = newInsertedTokenCount;
|
|
|
|
if(state.ReadTokenInFuture(currentTableTokenIndex, previous.future, now.future, 0))
|
|
{
|
|
if(currentTableTokenIndex==currentTokenIndex)
|
|
{
|
|
if(previous.future)
|
|
{
|
|
recoveringFutureIndex = previous.index;
|
|
RecoverFuture* rf = &GetRecoverFuture(previous.index);
|
|
while(rf->future->previous)
|
|
{
|
|
RecoverFuture* prf = &GetRecoverFuture(rf->previousIndex);
|
|
prf->nextIndex = rf->index;
|
|
prf->future->next = rf->future;
|
|
rf = prf;
|
|
}
|
|
recoveringFutureIndex = rf->index;
|
|
}
|
|
else
|
|
{
|
|
recoveringFutureIndex = 0;
|
|
}
|
|
goto FOUND_ERROR_RECOVER_SOLUTION;
|
|
}
|
|
else
|
|
{
|
|
usedFutureCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FOUND_ERROR_RECOVER_SOLUTION:
|
|
|
|
RecoverFuture* rf = 0;
|
|
if (recoveringFutureIndex != -1)
|
|
{
|
|
rf = &GetRecoverFuture(recoveringFutureIndex);
|
|
if(rf->future->next)
|
|
{
|
|
recoveringFutureIndex = rf->nextIndex;
|
|
}
|
|
else
|
|
{
|
|
recoveringFutureIndex = -1;
|
|
}
|
|
}
|
|
|
|
if(rf)
|
|
{
|
|
return state.RunTransition(rf->future->selectedItem, 0);
|
|
}
|
|
else
|
|
{
|
|
return ParsingState::TransitionResult(ParsingState::TransitionResult::SkipToken);
|
|
}
|
|
}
|
|
|
|
ParsingAutoRecoverParser::ParsingAutoRecoverParser(Ptr<ParsingTable> _table, vint _maxInsertedTokenCount)
|
|
:ParsingStrictParser(_table)
|
|
, recoveringFutureIndex(-1)
|
|
, maxInsertedTokenCount(_maxInsertedTokenCount == -1 ? 4 : _maxInsertedTokenCount)
|
|
{
|
|
}
|
|
|
|
ParsingAutoRecoverParser::~ParsingAutoRecoverParser()
|
|
{
|
|
FOREACH(RecoverFuture, future, recoverFutures)
|
|
{
|
|
delete future.future;
|
|
}
|
|
}
|
|
|
|
void ParsingAutoRecoverParser::BeginParse()
|
|
{
|
|
recoveringFutureIndex = -1;
|
|
ParsingStrictParser::BeginParse();
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingAmbiguousParser
|
|
***********************************************************************/
|
|
|
|
ParsingAmbiguousParser::ParsingAmbiguousParser(Ptr<ParsingTable> _table)
|
|
:ParsingGeneralParser(_table)
|
|
,consumedDecisionCount(0)
|
|
{
|
|
}
|
|
|
|
ParsingAmbiguousParser::~ParsingAmbiguousParser()
|
|
{
|
|
}
|
|
|
|
void ParsingAmbiguousParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
begin=end;
|
|
}
|
|
|
|
vint ParsingAmbiguousParser::GetResolvableFutureLevels(collections::List<ParsingState::Future*>& futures, vint begin, vint end)
|
|
{
|
|
if(end-begin<2)
|
|
{
|
|
return 1;
|
|
}
|
|
List<ParsingState::Future*> resolvingFutures;
|
|
for(vint i=begin;i<end;i++)
|
|
{
|
|
resolvingFutures.Add(futures[i]);
|
|
}
|
|
|
|
vint level=0;
|
|
while(true)
|
|
{
|
|
for(vint i=0;i<resolvingFutures.Count()-1;i++)
|
|
{
|
|
ParsingState::Future* first=resolvingFutures[i];
|
|
ParsingState::Future* second=resolvingFutures[i+1];
|
|
|
|
if(first->currentState!=second->currentState
|
|
|| first->reduceStateCount!=second->reduceStateCount
|
|
|| first->shiftStates.Count()!=second->shiftStates.Count()
|
|
)
|
|
{
|
|
return level;
|
|
}
|
|
else
|
|
{
|
|
for(vint j=0;j<first->shiftStates.Count();j++)
|
|
{
|
|
if(first->shiftStates[j]!=second->shiftStates[j])
|
|
{
|
|
return level;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
level++;
|
|
|
|
for(vint i=0;i<resolvingFutures.Count();i++)
|
|
{
|
|
if(!(resolvingFutures[i]=resolvingFutures[i]->previous))
|
|
{
|
|
return level;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vint ParsingAmbiguousParser::SearchPathForOneStep(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
futures.Add(state.ExploreCreateRootFuture());
|
|
vint previousBegin = 0;
|
|
vint previousEnd = 1;
|
|
vint resolvableFutureLevels = 0;
|
|
bool errorRecovered = false;
|
|
|
|
while(true)
|
|
{
|
|
// keep all futures that consumed a token in a list
|
|
List<ParsingState::Future*> consumedTokenFutures;
|
|
vint processBegin = previousBegin;
|
|
vint processEnd = previousEnd;
|
|
while (processEnd > processBegin)
|
|
{
|
|
// explore the current token
|
|
if (state.ExploreStep(futures, processBegin, processEnd - processBegin, futures))
|
|
{
|
|
CopyFrom(
|
|
consumedTokenFutures,
|
|
From(futures)
|
|
.Skip(processEnd)
|
|
.Take(futures.Count() - processEnd),
|
|
true
|
|
);
|
|
futures.RemoveRange(processEnd, futures.Count() - processEnd);
|
|
}
|
|
|
|
// explore left recursive reduce and normal reduce
|
|
state.ExploreLeftRecursiveReduce(futures, processBegin, processEnd - processBegin, futures);
|
|
state.ExploreNormalReduce(futures, processBegin, processEnd - processBegin, futures);
|
|
|
|
// if a token is consumed, then for those reduce futures, explore them until a token is consumed, and discard all failed futures
|
|
processBegin = processEnd;
|
|
processEnd = futures.Count();
|
|
}
|
|
|
|
if (consumedTokenFutures.Count() == 0)
|
|
{
|
|
// failed to get any future that consumed a token, do error recovering
|
|
vint tokenIndex = state.GetCurrentTableTokenIndex();
|
|
OnErrorRecover(state, tokenIndex, futures, previousBegin, previousEnd, errors);
|
|
if (previousBegin == previousEnd)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
state.SkipCurrentToken();
|
|
// put all futures that consumed a token from consumedTokenFutures back to future list
|
|
previousBegin = futures.Count();
|
|
CopyFrom(futures, consumedTokenFutures, true);
|
|
previousEnd = futures.Count();
|
|
|
|
// resolve all futures and see if all futures collapsed into a equivalent single future
|
|
resolvableFutureLevels = GetResolvableFutureLevels(futures, previousBegin, previousEnd);
|
|
if (resolvableFutureLevels != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
begin = previousBegin;
|
|
end = previousEnd;
|
|
return resolvableFutureLevels;
|
|
}
|
|
|
|
vint ParsingAmbiguousParser::GetConflictReduceCount(collections::List<ParsingState::Future*>& futures)
|
|
{
|
|
vint conflictReduceCount=-1;
|
|
for(vint i=0;i<futures.Count()-1;i++)
|
|
{
|
|
vint count=0;
|
|
ParsingState::Future* first=futures[i];
|
|
ParsingState::Future* second=futures[i+1];
|
|
vint firstIndex=first->selectedItem->instructions.Count();
|
|
vint secondIndex=second->selectedItem->instructions.Count();
|
|
while(--firstIndex>=0 && --secondIndex>=0)
|
|
{
|
|
ParsingTable::Instruction* firstIns=&first->selectedItem->instructions[firstIndex];
|
|
ParsingTable::Instruction* secondIns=&second->selectedItem->instructions[secondIndex];
|
|
if(firstIns && secondIns)
|
|
{
|
|
if(firstIns->instructionType==secondIns->instructionType
|
|
&& firstIns->nameParameter==secondIns->nameParameter
|
|
&& firstIns->stateParameter==secondIns->stateParameter
|
|
&& firstIns->value==secondIns->value
|
|
)
|
|
{
|
|
if(firstIns->instructionType==ParsingTable::Instruction::Reduce || firstIns->instructionType==ParsingTable::Instruction::LeftRecursiveReduce)
|
|
{
|
|
count++;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if(conflictReduceCount==-1 || conflictReduceCount>count)
|
|
{
|
|
conflictReduceCount=count;
|
|
}
|
|
}
|
|
if(conflictReduceCount==-1)
|
|
{
|
|
conflictReduceCount=0;
|
|
}
|
|
return conflictReduceCount;
|
|
}
|
|
|
|
void ParsingAmbiguousParser::GetConflictReduceIndices(collections::List<ParsingState::Future*>& futures, vint conflictReduceCount, collections::Array<vint>& conflictReduceIndices)
|
|
{
|
|
conflictReduceIndices.Resize(futures.Count());
|
|
for(vint i=0;i<futures.Count();i++)
|
|
{
|
|
ParsingState::Future* future=futures[i];
|
|
vint index=future->selectedItem->instructions.Count();
|
|
vint count=0;
|
|
while(count<conflictReduceCount && index>0)
|
|
{
|
|
switch(future->selectedItem->instructions[--index].instructionType)
|
|
{
|
|
case ParsingTable::Instruction::Reduce:
|
|
case ParsingTable::Instruction::LeftRecursiveReduce:
|
|
count++;
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
conflictReduceIndices[i]=index;
|
|
}
|
|
}
|
|
vint ParsingAmbiguousParser::GetAffectedStackNodeCount(collections::List<ParsingState::Future*>& futures, collections::Array<vint>& conflictReduceIndices)
|
|
{
|
|
vint affectedStackNodeCount=-1;
|
|
for(vint i=0;i<futures.Count();i++)
|
|
{
|
|
ParsingState::Future* future=futures[i];
|
|
vint count=1;
|
|
while(future && future->selectedItem)
|
|
{
|
|
vint start=(future==futures[i]?conflictReduceIndices[i]:future->selectedItem->instructions.Count())-1;
|
|
for(vint j=start;j>=0;j--)
|
|
{
|
|
switch(future->selectedItem->instructions[j].instructionType)
|
|
{
|
|
case ParsingTable::Instruction::Reduce:
|
|
count++;
|
|
break;
|
|
case ParsingTable::Instruction::Shift:
|
|
count--;
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
future=future->previous;
|
|
}
|
|
|
|
if(affectedStackNodeCount==-1)
|
|
{
|
|
affectedStackNodeCount=count;
|
|
}
|
|
else if(affectedStackNodeCount!=count)
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
return affectedStackNodeCount;
|
|
}
|
|
|
|
void ParsingAmbiguousParser::BuildSingleDecisionPath(ParsingState& state, ParsingState::Future* future, vint lastAvailableInstructionCount)
|
|
{
|
|
List<Pair<ParsingTable::TransitionItem*, regex::RegexToken*>> path;
|
|
while(future && future->selectedToken!=-1)
|
|
{
|
|
path.Add(Pair<ParsingTable::TransitionItem*, regex::RegexToken*>(future->selectedItem, future->selectedRegexToken));
|
|
future = future->previous;
|
|
}
|
|
|
|
for (vint j = path.Count() - 1; j >= 0; j--)
|
|
{
|
|
if(j==0 && lastAvailableInstructionCount!=-1)
|
|
{
|
|
decisions.Add(state.RunTransition(path[j].key, path[j].value, 0, lastAvailableInstructionCount, false));
|
|
}
|
|
else
|
|
{
|
|
decisions.Add(state.RunTransition(path[j].key, path[j].value));
|
|
}
|
|
}
|
|
}
|
|
|
|
void ParsingAmbiguousParser::BuildAmbiguousDecisions(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
List<ParsingState::Future*> resolvingFutures;
|
|
CopyFrom(
|
|
resolvingFutures,
|
|
From(futures)
|
|
.Skip(begin)
|
|
.Take(end - begin)
|
|
);
|
|
for (vint i = 1; i < resolvableFutureLevels; i++)
|
|
{
|
|
for(vint j=0;j<resolvingFutures.Count();j++)
|
|
{
|
|
resolvingFutures[j] = resolvingFutures[j]->previous;
|
|
}
|
|
}
|
|
|
|
Array<vint> conflictReduceIndices;
|
|
vint conflictReduceCount=GetConflictReduceCount(resolvingFutures);
|
|
GetConflictReduceIndices(resolvingFutures, conflictReduceCount, conflictReduceIndices);
|
|
|
|
WString ambiguityNodeType, ambiguityRuleName;
|
|
if(resolvingFutures[0]->selectedItem->instructions.Count()==conflictReduceIndices[0])
|
|
{
|
|
vint rootStartState=state.GetParsingRuleStartState();
|
|
ambiguityNodeType=state.GetTable()->GetStateInfo(rootStartState).ruleAmbiguousType;
|
|
ambiguityRuleName=state.GetParsingRule();
|
|
}
|
|
else
|
|
{
|
|
ParsingTable::Instruction& ins=resolvingFutures[0]->selectedItem->instructions[conflictReduceIndices[0]];
|
|
ambiguityNodeType=state.GetTable()->GetStateInfo(ins.stateParameter).ruleAmbiguousType;
|
|
ambiguityRuleName=state.GetTable()->GetStateInfo(ins.stateParameter).ruleName;
|
|
}
|
|
if(ambiguityNodeType==L"")
|
|
{
|
|
const RegexToken* token=state.GetToken(state.GetCurrentToken());
|
|
errors.Add(new ParsingError(token, L"Ambiguity happens when reducing rule \""+ambiguityRuleName+L"\" but this rule does not have an associated ambiguous node type."));
|
|
return;
|
|
}
|
|
|
|
vint affectedStackNodeCount=GetAffectedStackNodeCount(resolvingFutures, conflictReduceIndices);
|
|
if(affectedStackNodeCount==-1)
|
|
{
|
|
const RegexToken* token=state.GetToken(state.GetCurrentToken());
|
|
errors.Add(new ParsingError(token, (token==0?L"Failed to pass ambiguity checking during parsing when reaching to the end of the input.":L"Failed to pass ambiguity checking during parsing.")));
|
|
return;
|
|
}
|
|
|
|
Ptr<ParsingState::StateGroup> stateGroup;
|
|
for(vint i=0;i<resolvingFutures.Count();i++)
|
|
{
|
|
if(stateGroup)
|
|
{
|
|
state.RestoreSnapshot(stateGroup);
|
|
}
|
|
else
|
|
{
|
|
stateGroup=state.TakeSnapshot();
|
|
}
|
|
{
|
|
ParsingState::TransitionResult result(
|
|
i==0
|
|
?ParsingState::TransitionResult::AmbiguityBegin
|
|
:ParsingState::TransitionResult::AmbiguityBranch
|
|
);
|
|
if(i==0)
|
|
{
|
|
result.ambiguityAffectedStackNodeCount=affectedStackNodeCount;
|
|
}
|
|
decisions.Add(result);
|
|
}
|
|
{
|
|
BuildSingleDecisionPath(state, resolvingFutures[i], conflictReduceIndices[i]);
|
|
|
|
if(i==resolvingFutures.Count()-1)
|
|
{
|
|
ParsingState::TransitionResult result(ParsingState::TransitionResult::AmbiguityEnd);
|
|
result.ambiguityNodeType=ambiguityNodeType;
|
|
decisions.Add(result);
|
|
|
|
vint start=conflictReduceIndices[i];
|
|
ParsingState::TransitionResult lastDecision=decisions[decisions.Count()-2];
|
|
decisions.Add(state.RunTransition(lastDecision.transition, lastDecision.token, start, lastDecision.transition->instructions.Count()-start, true));
|
|
}
|
|
}
|
|
}
|
|
|
|
ParsingState::Future* lastFuture=futures[end-1];
|
|
ParsingState::Future** futureCleaner=&lastFuture;
|
|
for(int i=1;i<resolvableFutureLevels;i++)
|
|
{
|
|
futureCleaner=&(*futureCleaner)->previous;
|
|
}
|
|
*futureCleaner=0;
|
|
|
|
if(lastFuture)
|
|
{
|
|
BuildSingleDecisionPath(state, lastFuture, -1);
|
|
}
|
|
}
|
|
|
|
void ParsingAmbiguousParser::BuildDecisions(ParsingState& state, collections::List<ParsingState::Future*>& futures, vint begin, vint end, vint resolvableFutureLevels, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
if(end-begin==0)
|
|
{
|
|
const RegexToken* token=state.GetToken(state.GetCurrentToken());
|
|
errors.Add(new ParsingError(token, (token==0?L"Error happened during parsing when reaching to the end of the input.":L"Error happened during parsing.")));
|
|
}
|
|
else if(end-begin==1)
|
|
{
|
|
BuildSingleDecisionPath(state, futures[begin], -1);
|
|
}
|
|
else
|
|
{
|
|
BuildAmbiguousDecisions(state, futures, begin, end, resolvableFutureLevels, errors);
|
|
}
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingAmbiguousParser::ParseStep(ParsingState& state, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
if(decisions.Count()==consumedDecisionCount)
|
|
{
|
|
List<ParsingState::Future*> futures;
|
|
vint resultBegin=0;
|
|
vint resultEnd=0;
|
|
|
|
vint resolvableFutureLevels=SearchPathForOneStep(state, futures, resultBegin, resultEnd, errors);
|
|
BuildDecisions(state, futures, resultBegin, resultEnd, resolvableFutureLevels, errors);
|
|
|
|
FOREACH(ParsingState::Future*, future, futures)
|
|
{
|
|
delete future;
|
|
}
|
|
}
|
|
|
|
if(decisions.Count()>consumedDecisionCount)
|
|
{
|
|
ParsingState::TransitionResult result=decisions[consumedDecisionCount++];
|
|
if(consumedDecisionCount==decisions.Count())
|
|
{
|
|
decisions.Clear();
|
|
consumedDecisionCount=0;
|
|
}
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
return ParsingState::TransitionResult();
|
|
}
|
|
}
|
|
|
|
void ParsingAmbiguousParser::BeginParse()
|
|
{
|
|
decisions.Clear();
|
|
consumedDecisionCount=0;
|
|
ParsingGeneralParser::BeginParse();
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingAutoRecoverAmbiguousParser
|
|
***********************************************************************/
|
|
|
|
void ParsingAutoRecoverAmbiguousParser::OnErrorRecover(ParsingState& state, vint currentTokenIndex, collections::List<ParsingState::Future*>& futures, vint& begin, vint& end, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
vint insertedTokenCount = 0;
|
|
while (insertedTokenCount++ < maxInsertedTokenCount)
|
|
{
|
|
// keep all futures that consumed a token in a list
|
|
List<ParsingState::Future*> consumedTokenFutures;
|
|
vint processBegin = begin;
|
|
vint processEnd = end;
|
|
while (processEnd > processBegin)
|
|
{
|
|
// explore all tokens
|
|
for (vint i = processBegin; i < processEnd; i++)
|
|
{
|
|
state.Explore(ParsingTable::TokenFinish, futures[i], futures);
|
|
for (vint token = ParsingTable::UserTokenStart; token < state.GetTable()->GetTokenCount(); token++)
|
|
{
|
|
state.Explore(token, futures[i], futures);
|
|
}
|
|
}
|
|
// copy all futures that consumed a token to consumedTokenFutures
|
|
if (futures.Count() > processEnd)
|
|
{
|
|
CopyFrom(
|
|
consumedTokenFutures,
|
|
From(futures)
|
|
.Skip(processEnd)
|
|
.Take(futures.Count() - processEnd),
|
|
true
|
|
);
|
|
futures.RemoveRange(processEnd, futures.Count() - processEnd);
|
|
}
|
|
|
|
// explore left recursive reduce and normal reduce
|
|
state.ExploreLeftRecursiveReduce(futures, processBegin, processEnd - processBegin, futures);
|
|
state.ExploreNormalReduce(futures, processBegin, processEnd - processBegin, futures);
|
|
|
|
// if a token is consumed, then for those reduce futures, explore them until a token is consumed, and discard all failed futures
|
|
processBegin = processEnd;
|
|
processEnd = futures.Count();
|
|
}
|
|
|
|
if (consumedTokenFutures.Count() == 0)
|
|
{
|
|
// failed to get any future that consumed a token
|
|
goto ERROR_RECOVERY_FAILED;
|
|
}
|
|
else
|
|
{
|
|
// try to see if the target token is reached
|
|
List<ParsingState::Future*> recoveryFutures;
|
|
FOREACH(ParsingState::Future*, future, consumedTokenFutures)
|
|
{
|
|
if (future->selectedToken == currentTokenIndex)
|
|
{
|
|
// because this is reached by error recoverying, so all futures in availableFutures should have previous futures
|
|
recoveryFutures.Add(future->previous);
|
|
}
|
|
}
|
|
|
|
if (recoveryFutures.Count()>0)
|
|
{
|
|
// finally reached the expected currentTokenIndex
|
|
// move these previous futures to the end
|
|
// then the original parser algorith, will use these previous futures to reach the currentTokenIndex in the next step
|
|
FOREACH(ParsingState::Future*, future, recoveryFutures)
|
|
{
|
|
futures.Remove(future);
|
|
futures.Add(future);
|
|
}
|
|
begin = futures.Count() - recoveryFutures.Count();
|
|
end = futures.Count();
|
|
|
|
// delete all futures in consumedTokenFutures
|
|
FOREACH(ParsingState::Future*, future, consumedTokenFutures)
|
|
{
|
|
delete future;
|
|
}
|
|
goto ERROR_RECOVERY_SUCCEEDED;
|
|
}
|
|
else
|
|
{
|
|
// put all futures that consumed a token from consumedTokenFutures back to future list
|
|
begin = futures.Count();
|
|
CopyFrom(futures, consumedTokenFutures, true);
|
|
end = futures.Count();
|
|
}
|
|
}
|
|
}
|
|
// if the maxInsertedTokenCount is exceeded, then we get here
|
|
ERROR_RECOVERY_FAILED:
|
|
begin = end = futures.Count();
|
|
return;
|
|
ERROR_RECOVERY_SUCCEEDED:
|
|
return;
|
|
}
|
|
|
|
ParsingAutoRecoverAmbiguousParser::ParsingAutoRecoverAmbiguousParser(Ptr<ParsingTable> _table, vint _maxInsertedTokenCount)
|
|
:ParsingAmbiguousParser(_table)
|
|
, maxInsertedTokenCount(_maxInsertedTokenCount == -1 ? 4 : _maxInsertedTokenCount)
|
|
{
|
|
}
|
|
|
|
ParsingAutoRecoverAmbiguousParser::~ParsingAutoRecoverAmbiguousParser()
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
Ptr<ParsingGeneralParser> CreateStrictParser(Ptr<ParsingTable> table)
|
|
{
|
|
if(table)
|
|
{
|
|
if(table->GetAmbiguity())
|
|
{
|
|
return new ParsingAmbiguousParser(table);
|
|
}
|
|
else
|
|
{
|
|
return new ParsingStrictParser(table);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Ptr<ParsingGeneralParser> CreateAutoRecoverParser(Ptr<ParsingTable> table)
|
|
{
|
|
if(table)
|
|
{
|
|
if(table->GetAmbiguity())
|
|
{
|
|
return new ParsingAutoRecoverAmbiguousParser(table);
|
|
}
|
|
else
|
|
{
|
|
return new ParsingAutoRecoverParser(table);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Ptr<ParsingGeneralParser> CreateBootstrapStrictParser()
|
|
{
|
|
List<Ptr<ParsingError>> errors;
|
|
Ptr<ParsingDefinition> definition=CreateParserDefinition();
|
|
Ptr<ParsingTable> table=GenerateTable(definition, false, errors);
|
|
return CreateStrictParser(table);
|
|
}
|
|
|
|
Ptr<ParsingGeneralParser> CreateBootstrapAutoRecoverParser()
|
|
{
|
|
List<Ptr<ParsingError>> errors;
|
|
Ptr<ParsingDefinition> definition=CreateParserDefinition();
|
|
Ptr<ParsingTable> table=GenerateTable(definition, false, errors);
|
|
return CreateAutoRecoverParser(table);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Reflection
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
using namespace parsing;
|
|
|
|
PARSINGREFLECTION_TYPELIST(IMPL_VL_TYPE_INFO)
|
|
|
|
/***********************************************************************
|
|
Type Declaration
|
|
***********************************************************************/
|
|
|
|
#define _ ,
|
|
|
|
BEGIN_STRUCT_MEMBER(ParsingTextPos)
|
|
STRUCT_MEMBER(index)
|
|
STRUCT_MEMBER(row)
|
|
STRUCT_MEMBER(column)
|
|
END_STRUCT_MEMBER(ParsingTextPos)
|
|
|
|
BEGIN_STRUCT_MEMBER(ParsingTextRange)
|
|
STRUCT_MEMBER(start)
|
|
STRUCT_MEMBER(end)
|
|
END_STRUCT_MEMBER(ParsingTextRange)
|
|
|
|
BEGIN_CLASS_MEMBER(ParsingTreeNode)
|
|
CLASS_MEMBER_PROPERTY_FAST(CodeRange)
|
|
CLASS_MEMBER_PROPERTY_READONLY_FAST(Parent)
|
|
CLASS_MEMBER_PROPERTY_READONLY_FAST(SubNodes)
|
|
|
|
CLASS_MEMBER_METHOD(Clone, NO_PARAMETER)
|
|
CLASS_MEMBER_METHOD(InitializeQueryCache, NO_PARAMETER)
|
|
CLASS_MEMBER_METHOD(ClearQueryCache, NO_PARAMETER)
|
|
CLASS_MEMBER_METHOD_OVERLOAD(FindSubNode, {L"position"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextPos&))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(FindSubNode, {L"range"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextRange&))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(FindDeepestNode, {L"position"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextPos&))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(FindDeepestNode, {L"range"}, ParsingTreeNode*(ParsingTreeNode::*)(const ParsingTextRange&))
|
|
END_CLASS_MEMBER(ParsingTreeNode)
|
|
|
|
BEGIN_CLASS_MEMBER(ParsingTreeToken)
|
|
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingTreeToken>(const WString&, vint), {L"value" _ L"tokenIndex"})
|
|
|
|
CLASS_MEMBER_PROPERTY_FAST(TokenIndex)
|
|
CLASS_MEMBER_PROPERTY_FAST(Value)
|
|
END_CLASS_MEMBER(ParsingTreeToken)
|
|
|
|
BEGIN_CLASS_MEMBER(ParsingTreeObject)
|
|
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingTreeObject>(const WString&), {L"type"})
|
|
|
|
CLASS_MEMBER_PROPERTY_FAST(Type)
|
|
CLASS_MEMBER_PROPERTY_READONLY_FAST(Members)
|
|
CLASS_MEMBER_PROPERTY_READONLY_FAST(MemberNames)
|
|
CLASS_MEMBER_PROPERTY_READONLY_FAST(CreatorRules)
|
|
|
|
CLASS_MEMBER_METHOD(GetMember, {L"name"})
|
|
CLASS_MEMBER_METHOD(SetMember, {L"name" _ L"node"})
|
|
END_CLASS_MEMBER(ParsingTreeObject)
|
|
|
|
BEGIN_CLASS_MEMBER(ParsingTreeArray)
|
|
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingTreeObject>(const WString&), {L"elementType"})
|
|
|
|
CLASS_MEMBER_PROPERTY_FAST(ElementType)
|
|
CLASS_MEMBER_PROPERTY_READONLY_FAST(Items)
|
|
|
|
CLASS_MEMBER_METHOD(GetItem, {L"index"})
|
|
CLASS_MEMBER_METHOD(SetItem, {L"index" _ L"node"})
|
|
CLASS_MEMBER_METHOD(AddItem, {L"node"})
|
|
CLASS_MEMBER_METHOD(InsertItem, {L"index" _ L"node"})
|
|
CLASS_MEMBER_METHOD_OVERLOAD(RemoveItem, {L"index"}, bool(ParsingTreeArray::*)(vint))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(RemoveItem, {L"node"}, bool(ParsingTreeArray::*)(ParsingTreeNode*))
|
|
CLASS_MEMBER_METHOD(IndexOfItem, {L"node"})
|
|
CLASS_MEMBER_METHOD(ContainsItem, {L"node"})
|
|
CLASS_MEMBER_METHOD(Clone, NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_METHOD_RENAME(GetCount, Count, NO_PARAMETER)
|
|
CLASS_MEMBER_PROPERTY_READONLY(Count, GetCount)
|
|
END_CLASS_MEMBER(ParsingTreeArray)
|
|
|
|
BEGIN_CLASS_MEMBER(ParsingTreeCustomBase)
|
|
CLASS_MEMBER_FIELD(codeRange)
|
|
CLASS_MEMBER_FIELD(creatorRules)
|
|
END_CLASS_MEMBER(ParsingTreeCustomBase)
|
|
|
|
BEGIN_CLASS_MEMBER(ParsingToken)
|
|
CLASS_MEMBER_BASE(ParsingTreeCustomBase)
|
|
|
|
CLASS_MEMBER_FIELD(tokenIndex)
|
|
CLASS_MEMBER_FIELD(value)
|
|
END_CLASS_MEMBER(ParsingToken)
|
|
|
|
BEGIN_CLASS_MEMBER(ParsingError)
|
|
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingError>(), NO_PARAMETER)
|
|
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingError>(const WString&), {L"errorMessage"})
|
|
CLASS_MEMBER_CONSTRUCTOR(Ptr<ParsingError>(ParsingTreeCustomBase*, const WString&), {L"parsingTree" _ L"errorMessage"})
|
|
|
|
CLASS_MEMBER_FIELD(codeRange)
|
|
CLASS_MEMBER_FIELD(parsingTree)
|
|
CLASS_MEMBER_FIELD(errorMessage)
|
|
END_CLASS_MEMBER(ParsingError)
|
|
#undef _
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
|
|
/***********************************************************************
|
|
Type Loader
|
|
***********************************************************************/
|
|
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
class ParsingTypeLoader : public Object, public ITypeLoader
|
|
{
|
|
public:
|
|
void Load(ITypeManager* manager)
|
|
{
|
|
PARSINGREFLECTION_TYPELIST(ADD_TYPE_INFO)
|
|
}
|
|
|
|
void Unload(ITypeManager* manager)
|
|
{
|
|
}
|
|
};
|
|
#endif
|
|
|
|
bool LoadParsingTypes()
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
ITypeManager* manager=GetGlobalTypeManager();
|
|
if(manager)
|
|
{
|
|
Ptr<ITypeLoader> loader=new ParsingTypeLoader;
|
|
return manager->AddTypeLoader(loader);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGANALYZER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
ParsingSymbol
|
|
***********************************************************************/
|
|
|
|
bool ParsingSymbol::AddSubSymbol(ParsingSymbol* subSymbol)
|
|
{
|
|
if(subSymbol->GetParentSymbol()) return false;
|
|
if(subSymbolMap.Keys().IndexOf(subSymbol->GetName())!=-1) return false;
|
|
switch(type)
|
|
{
|
|
case Global:
|
|
switch(subSymbol->GetType())
|
|
{
|
|
case EnumType: break;
|
|
case ClassType: break;
|
|
case TokenDef: break;
|
|
case RuleDef: break;
|
|
default: return false;
|
|
}
|
|
break;
|
|
case EnumType:
|
|
switch(subSymbol->GetType())
|
|
{
|
|
case EnumItem: break;
|
|
default: return false;
|
|
}
|
|
break;
|
|
case ClassType:
|
|
switch(subSymbol->GetType())
|
|
{
|
|
case EnumType:
|
|
case ClassType:
|
|
case ClassField: break;
|
|
default: return false;
|
|
}
|
|
break;
|
|
default: return false;
|
|
}
|
|
|
|
subSymbol->parentSymbol=this;
|
|
subSymbolList.Add(subSymbol);
|
|
subSymbolMap.Add(subSymbol->GetName(), subSymbol);
|
|
return true;
|
|
}
|
|
|
|
ParsingSymbol::ParsingSymbol(ParsingSymbolManager* _manager, SymbolType _type, const WString& _name, ParsingSymbol* _descriptorSymbol, const WString& _descriptorString)
|
|
:manager(_manager)
|
|
,type(_type)
|
|
,name(_name)
|
|
,descriptorSymbol(_descriptorSymbol)
|
|
,descriptorString(_descriptorString)
|
|
,parentSymbol(0)
|
|
,arrayTypeSymbol(0)
|
|
{
|
|
}
|
|
|
|
ParsingSymbol::~ParsingSymbol()
|
|
{
|
|
}
|
|
|
|
ParsingSymbolManager* ParsingSymbol::GetManager()
|
|
{
|
|
return manager;
|
|
}
|
|
|
|
ParsingSymbol::SymbolType ParsingSymbol::GetType()
|
|
{
|
|
return type;
|
|
}
|
|
|
|
const WString& ParsingSymbol::GetName()
|
|
{
|
|
return name;
|
|
}
|
|
|
|
vint ParsingSymbol::GetSubSymbolCount()
|
|
{
|
|
return subSymbolList.Count();
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbol::GetSubSymbol(vint index)
|
|
{
|
|
if(0<=index && index<subSymbolList.Count())
|
|
{
|
|
return subSymbolList[index];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbol::GetSubSymbolByName(const WString& name)
|
|
{
|
|
vint index=subSymbolMap.Keys().IndexOf(name);
|
|
if(index==-1)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return subSymbolMap.Values().Get(index);
|
|
}
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbol::GetDescriptorSymbol()
|
|
{
|
|
return descriptorSymbol;
|
|
}
|
|
|
|
WString ParsingSymbol::GetDescriptorString()
|
|
{
|
|
return descriptorString;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbol::GetParentSymbol()
|
|
{
|
|
return parentSymbol;
|
|
}
|
|
|
|
bool ParsingSymbol::IsType()
|
|
{
|
|
switch(type)
|
|
{
|
|
case ParsingSymbol::ClassType:
|
|
case ParsingSymbol::EnumType:
|
|
case ParsingSymbol::ArrayType:
|
|
case ParsingSymbol::TokenType:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbol::SearchClassSubSymbol(const WString& name)
|
|
{
|
|
if(type==ParsingSymbol::ClassType)
|
|
{
|
|
ParsingSymbol* scope=this;
|
|
while(scope)
|
|
{
|
|
ParsingSymbol* subSymbol=scope->GetSubSymbolByName(name);
|
|
if(subSymbol)
|
|
{
|
|
return subSymbol;
|
|
}
|
|
else
|
|
{
|
|
scope=scope->GetDescriptorSymbol();
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbol::SearchCommonBaseClass(ParsingSymbol* classType)
|
|
{
|
|
if(type==ParsingSymbol::ClassType && classType->GetType()==ParsingSymbol::ClassType)
|
|
{
|
|
vint aCount=0;
|
|
vint bCount=0;
|
|
ParsingSymbol* a=this;
|
|
ParsingSymbol* b=classType;
|
|
while(a || b)
|
|
{
|
|
if(a)
|
|
{
|
|
aCount++;
|
|
a=a->GetDescriptorSymbol();
|
|
}
|
|
if(b)
|
|
{
|
|
bCount++;
|
|
b=b->GetDescriptorSymbol();
|
|
}
|
|
}
|
|
|
|
a=this;
|
|
b=classType;
|
|
vint min=aCount<bCount?aCount:bCount;
|
|
for(vint i=aCount;i>min;i--)
|
|
{
|
|
a=a->GetDescriptorSymbol();
|
|
}
|
|
for(vint i=bCount;i>min;i--)
|
|
{
|
|
b=b->GetDescriptorSymbol();
|
|
}
|
|
|
|
while(a!=b)
|
|
{
|
|
a=a->GetDescriptorSymbol();
|
|
b=b->GetDescriptorSymbol();
|
|
}
|
|
return a;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingSymbolManager
|
|
***********************************************************************/
|
|
|
|
bool ParsingSymbolManager::TryAddSubSymbol(Ptr<ParsingSymbol> subSymbol, ParsingSymbol* parentSymbol)
|
|
{
|
|
if(parentSymbol->AddSubSymbol(subSymbol.Obj()))
|
|
{
|
|
createdSymbols.Add(subSymbol);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ParsingSymbolManager::ParsingSymbolManager()
|
|
{
|
|
globalSymbol=new ParsingSymbol(this, ParsingSymbol::Global, L"", 0, L"");
|
|
tokenTypeSymbol=new ParsingSymbol(this, ParsingSymbol::TokenType, L"token", 0, L"");
|
|
createdSymbols.Add(globalSymbol);
|
|
createdSymbols.Add(tokenTypeSymbol);
|
|
}
|
|
|
|
ParsingSymbolManager::~ParsingSymbolManager()
|
|
{
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::GetGlobal()
|
|
{
|
|
return globalSymbol;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::GetTokenType()
|
|
{
|
|
return tokenTypeSymbol;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::GetArrayType(ParsingSymbol* elementType)
|
|
{
|
|
if(elementType->IsType())
|
|
{
|
|
if(!elementType->arrayTypeSymbol)
|
|
{
|
|
elementType->arrayTypeSymbol=new ParsingSymbol(this, ParsingSymbol::ArrayType, L"", elementType, L"");
|
|
createdSymbols.Add(elementType->arrayTypeSymbol);
|
|
}
|
|
return elementType->arrayTypeSymbol;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::AddClass(definitions::ParsingDefinitionClassDefinition* classDef, ParsingSymbol* baseType, ParsingSymbol* parentType)
|
|
{
|
|
if((!baseType || baseType->GetType()==ParsingSymbol::ClassType) && (!parentType || parentType->IsType()))
|
|
{
|
|
ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::ClassType, classDef->name, baseType, L"");
|
|
if(TryAddSubSymbol(symbol, parentType?parentType:globalSymbol))
|
|
{
|
|
symbolClassDefinitionCache.Add(symbol, classDef);
|
|
classDefinitionSymbolCache.Add(classDef, symbol);
|
|
return symbol;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::AddField(const WString& name, ParsingSymbol* classType, ParsingSymbol* fieldType)
|
|
{
|
|
if(classType && classType->GetType()==ParsingSymbol::ClassType && fieldType && fieldType->IsType())
|
|
{
|
|
ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::ClassField, name, fieldType, L"");
|
|
if(TryAddSubSymbol(symbol, classType))
|
|
{
|
|
return symbol;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::AddEnum(const WString& name, ParsingSymbol* parentType)
|
|
{
|
|
if(!parentType || parentType->GetType()==ParsingSymbol::ClassType)
|
|
{
|
|
ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::EnumType, name, 0, L"");
|
|
if(TryAddSubSymbol(symbol, parentType?parentType:globalSymbol))
|
|
{
|
|
return symbol;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::AddEnumItem(const WString& name, ParsingSymbol* enumType)
|
|
{
|
|
if(enumType && enumType->GetType()==ParsingSymbol::EnumType)
|
|
{
|
|
ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::EnumItem, name, enumType, L"");
|
|
if(TryAddSubSymbol(symbol, enumType))
|
|
{
|
|
return symbol;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::AddTokenDefinition(const WString& name, const WString& regex)
|
|
{
|
|
ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::TokenDef, name, tokenTypeSymbol, regex);
|
|
if(TryAddSubSymbol(symbol, globalSymbol))
|
|
{
|
|
return symbol;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::AddRuleDefinition(const WString& name, ParsingSymbol* ruleType)
|
|
{
|
|
if(ruleType && ruleType->IsType())
|
|
{
|
|
ParsingSymbol* symbol=new ParsingSymbol(this, ParsingSymbol::RuleDef, name, ruleType, L"");
|
|
if(TryAddSubSymbol(symbol, globalSymbol))
|
|
{
|
|
return symbol;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingSymbolManager::ClassDefinition* ParsingSymbolManager::CacheGetClassDefinition(ParsingSymbol* type)
|
|
{
|
|
vint index=symbolClassDefinitionCache.Keys().IndexOf(type);
|
|
return index==-1?0:symbolClassDefinitionCache.Values().Get(index);
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::CacheGetClassType(ClassDefinition* type)
|
|
{
|
|
vint index=classDefinitionSymbolCache.Keys().IndexOf(type);
|
|
return index==-1?0:classDefinitionSymbolCache.Values().Get(index);
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::CacheGetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope)
|
|
{
|
|
DefinitionTypeScopePair key(type, scope);
|
|
vint index=definitionTypeSymbolCache.Keys().IndexOf(key);
|
|
return index==-1?0:definitionTypeSymbolCache.Values().Get(index);
|
|
}
|
|
|
|
bool ParsingSymbolManager::CacheSetType(definitions::ParsingDefinitionType* type, ParsingSymbol* scope, ParsingSymbol* symbol)
|
|
{
|
|
DefinitionTypeScopePair key(type, scope);
|
|
vint index=definitionTypeSymbolCache.Keys().IndexOf(key);
|
|
if(index==-1)
|
|
{
|
|
definitionTypeSymbolCache.Add(key, symbol);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::CacheGetSymbol(definitions::ParsingDefinitionGrammar* grammar)
|
|
{
|
|
vint index=definitionGrammarSymbolCache.Keys().IndexOf(grammar);
|
|
return index==-1?0:definitionGrammarSymbolCache.Values().Get(index);
|
|
}
|
|
|
|
bool ParsingSymbolManager::CacheSetSymbol(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* symbol)
|
|
{
|
|
vint index=definitionGrammarSymbolCache.Keys().IndexOf(grammar);
|
|
if(index==-1)
|
|
{
|
|
definitionGrammarSymbolCache.Add(grammar, symbol);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
ParsingSymbol* ParsingSymbolManager::CacheGetType(definitions::ParsingDefinitionGrammar* grammar)
|
|
{
|
|
vint index=definitionGrammarTypeCache.Keys().IndexOf(grammar);
|
|
return index==-1?0:definitionGrammarTypeCache.Values().Get(index);
|
|
}
|
|
|
|
bool ParsingSymbolManager::CacheSetType(definitions::ParsingDefinitionGrammar* grammar, ParsingSymbol* type)
|
|
{
|
|
vint index=definitionGrammarTypeCache.Keys().IndexOf(grammar);
|
|
if(index==-1)
|
|
{
|
|
definitionGrammarTypeCache.Add(grammar, type);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
FindType
|
|
***********************************************************************/
|
|
|
|
WString GetTypeFullName(ParsingSymbol* type)
|
|
{
|
|
if(type->GetType()==ParsingSymbol::ArrayType)
|
|
{
|
|
return GetTypeFullName(type->GetDescriptorSymbol())+L"[]";
|
|
}
|
|
else
|
|
{
|
|
WString name=type->GetName();
|
|
type=type->GetParentSymbol();
|
|
while(type && type!=type->GetManager()->GetGlobal())
|
|
{
|
|
name=type->GetName()+L"."+name;
|
|
type=type->GetParentSymbol();
|
|
}
|
|
return name;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
FindType
|
|
***********************************************************************/
|
|
|
|
class FindTypeVisitor : public Object, public ParsingDefinitionType::IVisitor
|
|
{
|
|
public:
|
|
ParsingSymbolManager* manager;
|
|
ParsingSymbol* scope;
|
|
List<Ptr<ParsingError>>& errors;
|
|
ParsingSymbol* result;
|
|
|
|
FindTypeVisitor(ParsingSymbolManager* _manager, ParsingSymbol* _scope, List<Ptr<ParsingError>>& _errors)
|
|
:manager(_manager)
|
|
,scope(_scope)
|
|
,errors(_errors)
|
|
,result(0)
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveType* node)override
|
|
{
|
|
ParsingSymbol* currentScope=scope;
|
|
while(currentScope)
|
|
{
|
|
ParsingSymbol* type=currentScope->GetSubSymbolByName(node->name);
|
|
if(type)
|
|
{
|
|
if(type->IsType())
|
|
{
|
|
result=type;
|
|
}
|
|
else
|
|
{
|
|
errors.Add(new ParsingError(node, L"\""+node->name+L"\" in current scope is not a type."));
|
|
}
|
|
return;
|
|
}
|
|
currentScope=currentScope->GetParentSymbol();
|
|
}
|
|
errors.Add(new ParsingError(node, L"Cannot not find \""+node->name+L"\" in current scope."));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTokenType* node)override
|
|
{
|
|
result=manager->GetTokenType();
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSubType* node)override
|
|
{
|
|
ParsingSymbol* type=FindType(node->parentType.Obj(), manager, scope, errors);
|
|
if(type)
|
|
{
|
|
ParsingSymbol* subType=type->SearchClassSubSymbol(node->subTypeName);
|
|
if(!subType)
|
|
{
|
|
errors.Add(new ParsingError(node, L"\""+GetTypeFullName(type)+L"\" does not has a sub type called \""+node->subTypeName+L"\"."));
|
|
}
|
|
else if(subType->IsType())
|
|
{
|
|
result=subType;
|
|
}
|
|
else
|
|
{
|
|
errors.Add(new ParsingError(node, L"\""+GetTypeFullName(type)+L"\" contains a sub definition called \""+node->subTypeName+L"\" but this is not a type."));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionArrayType* node)override
|
|
{
|
|
ParsingSymbol* type=FindType(node->elementType.Obj(), manager, scope, errors);
|
|
if(type)
|
|
{
|
|
result=manager->GetArrayType(type);
|
|
}
|
|
}
|
|
};
|
|
|
|
ParsingSymbol* FindType(definitions::ParsingDefinitionType* type, ParsingSymbolManager* manager, ParsingSymbol* scope, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
ParsingSymbol* result=manager->CacheGetType(type, scope);
|
|
if(!result)
|
|
{
|
|
FindTypeVisitor visitor(manager, (scope?scope:manager->GetGlobal()), errors);
|
|
type->Accept(&visitor);
|
|
result=visitor.result;
|
|
manager->CacheSetType(type, scope, result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/***********************************************************************
|
|
PrepareSymbols
|
|
***********************************************************************/
|
|
|
|
class PrepareSymbolsTypeDefinitionVisitor : public Object, public ParsingDefinitionTypeDefinition::IVisitor
|
|
{
|
|
public:
|
|
ParsingSymbolManager* manager;
|
|
ParsingSymbol* scope;
|
|
List<Ptr<ParsingError>>& errors;
|
|
|
|
PrepareSymbolsTypeDefinitionVisitor(ParsingSymbolManager* _manager, ParsingSymbol* _scope, List<Ptr<ParsingError>>& _errors)
|
|
:manager(_manager)
|
|
,scope(_scope)
|
|
,errors(_errors)
|
|
{
|
|
}
|
|
|
|
bool EnsureNameNotExists(ParsingDefinitionTypeDefinition* node, const WString& subjectName)
|
|
{
|
|
if(scope->SearchClassSubSymbol(node->name))
|
|
{
|
|
errors.Add(new ParsingError(node, L"Cannot redefine \""+node->name+L"\" to be "+subjectName+L"."));
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionClassMemberDefinition* node)override
|
|
{
|
|
if(EnsureNameNotExists(node, L"a class field"))
|
|
{
|
|
ParsingSymbol* fieldType=FindType(node->type.Obj(), manager, scope, errors);
|
|
if(fieldType)
|
|
{
|
|
ParsingSymbol* field=manager->AddField(node->name, scope, fieldType);
|
|
if(!field)
|
|
{
|
|
errors.Add(new ParsingError(node, L"A class field cannot be defined here."));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionClassDefinition* node)override
|
|
{
|
|
if(EnsureNameNotExists(node, L"a class type"))
|
|
{
|
|
ParsingSymbol* baseType=0;
|
|
if(node->parentType)
|
|
{
|
|
baseType=FindType(node->parentType.Obj(), manager, scope, errors);
|
|
}
|
|
ParsingSymbol* classType=manager->AddClass(node, baseType, (scope->GetType()==ParsingSymbol::Global?0:scope));
|
|
if(classType)
|
|
{
|
|
PrepareSymbolsTypeDefinitionVisitor visitor(manager, classType, errors);
|
|
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, subType, node->subTypes)
|
|
{
|
|
subType->Accept(&visitor);
|
|
}
|
|
FOREACH(Ptr<ParsingDefinitionClassMemberDefinition>, member, node->members)
|
|
{
|
|
member->Accept(&visitor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errors.Add(new ParsingError(node, L"A class type cannot be defined here."));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionEnumMemberDefinition* node)override
|
|
{
|
|
if(EnsureNameNotExists(node, L"an enum item"))
|
|
{
|
|
ParsingSymbol* enumItem=manager->AddEnumItem(node->name, scope);
|
|
if(!enumItem)
|
|
{
|
|
errors.Add(new ParsingError(node, L"An enum item cannot be defined here."));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionEnumDefinition* node)override
|
|
{
|
|
if(EnsureNameNotExists(node, L"an enum type"))
|
|
{
|
|
ParsingSymbol* enumType=manager->AddEnum(node->name, (scope->GetType()==ParsingSymbol::Global?0:scope));
|
|
if(enumType)
|
|
{
|
|
PrepareSymbolsTypeDefinitionVisitor visitor(manager, enumType, errors);
|
|
FOREACH(Ptr<ParsingDefinitionEnumMemberDefinition>, member, node->members)
|
|
{
|
|
member->Accept(&visitor);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errors.Add(new ParsingError(node, L"An enum type cannot be defined here."));
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void PrepareSymbols(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
{
|
|
PrepareSymbolsTypeDefinitionVisitor visitor(manager, manager->GetGlobal(), errors);
|
|
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, typeDefinition, definition->types)
|
|
{
|
|
typeDefinition->Accept(&visitor);
|
|
}
|
|
}
|
|
|
|
FOREACH(Ptr<ParsingDefinitionTokenDefinition>, token, definition->tokens)
|
|
{
|
|
if(manager->GetGlobal()->GetSubSymbolByName(token->name))
|
|
{
|
|
errors.Add(new ParsingError(token.Obj(), L"Cannot redefine \""+token->name+L"\" to be a token definition."));
|
|
}
|
|
else
|
|
{
|
|
manager->AddTokenDefinition(token->name, token->regex);
|
|
try
|
|
{
|
|
regex_internal::ParseRegexExpression(token->regex);
|
|
}
|
|
catch(const ParsingException& ex)
|
|
{
|
|
errors.Add(new ParsingError(token.Obj(), L"Wrong token definition for \""+token->name+L"\": "+ex.Message()));
|
|
}
|
|
}
|
|
}
|
|
|
|
FOREACH(Ptr<ParsingDefinitionRuleDefinition>, rule, definition->rules)
|
|
{
|
|
if(manager->GetGlobal()->GetSubSymbolByName(rule->name))
|
|
{
|
|
errors.Add(new ParsingError(rule.Obj(), L"Cannot redefine \""+rule->name+L"\" to be a rule definition."));
|
|
}
|
|
else
|
|
{
|
|
ParsingSymbol* type=FindType(rule->type.Obj(), manager, 0, errors);
|
|
if(type)
|
|
{
|
|
if(type->GetType()!=ParsingSymbol::ClassType)
|
|
{
|
|
errors.Add(new ParsingError(rule.Obj(), L"\""+GetTypeFullName(type)+L"\" cannot be a type of a rule because this is not a class type."));
|
|
}
|
|
manager->AddRuleDefinition(rule->name, type);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ValidateRuleStructure
|
|
***********************************************************************/
|
|
|
|
class ValidateRuleStructureVisitor : public Object, public ParsingDefinitionGrammar::IVisitor
|
|
{
|
|
public:
|
|
Ptr<ParsingDefinition> definition;
|
|
ParsingSymbolManager* manager;
|
|
ParsingDefinitionRuleDefinition* rule;
|
|
List<Ptr<ParsingError>>& errors;
|
|
vint loopCount;
|
|
|
|
ValidateRuleStructureVisitor(Ptr<ParsingDefinition> _definition, ParsingSymbolManager* _manager, ParsingDefinitionRuleDefinition* _rule, List<Ptr<ParsingError>>& _errors)
|
|
:definition(_definition)
|
|
,manager(_manager)
|
|
,errors(_errors)
|
|
,rule(_rule)
|
|
,loopCount(0)
|
|
{
|
|
}
|
|
|
|
void CheckCreationType(ParsingDefinitionGrammar* node, ParsingSymbol* nodeType)
|
|
{
|
|
if(nodeType->GetType()==ParsingSymbol::ClassType)
|
|
{
|
|
ParsingSymbol* ruleType=manager->GetGlobal()->GetSubSymbolByName(rule->name)->GetDescriptorSymbol();
|
|
ParsingSymbol* currentType=nodeType;
|
|
while(currentType && currentType!=ruleType)
|
|
{
|
|
currentType=currentType->GetDescriptorSymbol();
|
|
}
|
|
if(!currentType)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Cannot create type \""+GetTypeFullName(nodeType)+L"\" in a rule of type \""+GetTypeFullName(ruleType)+L"\" because there are no implicit conversions from the created type to the rule type."));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errors.Add(new ParsingError(node, L"\""+GetTypeFullName(nodeType)+L"\" cannot be created because this is not a class type."));
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveGrammar* node)override
|
|
{
|
|
ParsingSymbol* symbol=manager->GetGlobal()->GetSubSymbolByName(node->name);
|
|
if(!symbol)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Cannot find a token or a rule with name \""+node->name+L"\"."));
|
|
}
|
|
else switch(symbol->GetType())
|
|
{
|
|
case ParsingSymbol::TokenDef:
|
|
{
|
|
bool discard=false;
|
|
FOREACH(Ptr<ParsingDefinitionTokenDefinition>, token, definition->tokens)
|
|
{
|
|
if(token->name==symbol->GetName())
|
|
{
|
|
discard=token->discard;
|
|
break;
|
|
}
|
|
}
|
|
if(discard)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Cannot use discard token \""+node->name+L"\" as input."));
|
|
break;
|
|
}
|
|
}
|
|
case ParsingSymbol::RuleDef:
|
|
{
|
|
ParsingSymbol* symbolType=symbol->GetDescriptorSymbol();
|
|
manager->CacheSetSymbol(node, symbol);
|
|
manager->CacheSetType(node, symbolType);
|
|
}
|
|
break;
|
|
default:
|
|
errors.Add(new ParsingError(node, L"\""+node->name+L"\" is not a token definition or rule definition."));
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTextGrammar* node)override
|
|
{
|
|
WString regex=regex_internal::EscapeTextForRegex(node->text);
|
|
for(vint i=0;i<manager->GetGlobal()->GetSubSymbolCount();i++)
|
|
{
|
|
ParsingSymbol* symbol=manager->GetGlobal()->GetSubSymbol(i);
|
|
if(symbol->GetType()==ParsingSymbol::TokenDef)
|
|
{
|
|
WString normalizedRegex=regex_internal::NormalizeEscapedTextForRegex(symbol->GetDescriptorString());
|
|
if(normalizedRegex==regex)
|
|
{
|
|
manager->CacheSetSymbol(node, symbol);
|
|
manager->CacheSetType(node, manager->GetTokenType());
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
errors.Add(new ParsingError(node, L"Cannot find a token whose definition is exactly \""+regex+L"\"."));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSequenceGrammar* node)override
|
|
{
|
|
node->first->Accept(this);
|
|
node->second->Accept(this);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAlternativeGrammar* node)override
|
|
{
|
|
node->first->Accept(this);
|
|
node->second->Accept(this);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionLoopGrammar* node)override
|
|
{
|
|
loopCount++;
|
|
node->grammar->Accept(this);
|
|
loopCount--;
|
|
}
|
|
|
|
void Visit(ParsingDefinitionOptionalGrammar* node)override
|
|
{
|
|
node->grammar->Accept(this);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionCreateGrammar* node)override
|
|
{
|
|
if(loopCount>0)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Parsing tree node creation (the \"as\" operator) is not allowed inside loops."));
|
|
}
|
|
if(ParsingSymbol* nodeType=FindType(node->type.Obj(), manager, 0, errors))
|
|
{
|
|
CheckCreationType(node, nodeType);
|
|
}
|
|
node->grammar->Accept(this);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAssignGrammar* node)override
|
|
{
|
|
if(!node->grammar.Cast<ParsingDefinitionPrimitiveGrammar>() && !node->grammar.Cast<ParsingDefinitionTextGrammar>())
|
|
{
|
|
errors.Add(new ParsingError(node, L"Only parsing tree node returned from a rule or a token can be assigned to a class field."));
|
|
}
|
|
node->grammar->Accept(this);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionUseGrammar* node)override
|
|
{
|
|
if(loopCount>0)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Parsing tree node reusing (the \"!\" operator) is not allowed inside loops."));
|
|
}
|
|
if(!node->grammar.Cast<ParsingDefinitionPrimitiveGrammar>())
|
|
{
|
|
errors.Add(new ParsingError(node, L"Only parsing tree node returned from a rule can be reused."));
|
|
}
|
|
else if(ParsingSymbol* symbol=manager->CacheGetSymbol(node->grammar.Obj()))
|
|
{
|
|
if(symbol->GetType()!=ParsingSymbol::RuleDef)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Only parsing tree node returned from a rule can be reused."));
|
|
}
|
|
}
|
|
if(ParsingSymbol* nodeType=manager->CacheGetType(node->grammar.Obj()))
|
|
{
|
|
CheckCreationType(node, nodeType);
|
|
}
|
|
node->grammar->Accept(this);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSetterGrammar* node)override
|
|
{
|
|
node->grammar->Accept(this);
|
|
}
|
|
};
|
|
|
|
void ValidateRuleStructure(Ptr<definitions::ParsingDefinition> definition, Ptr<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
FOREACH(Ptr<ParsingDefinitionGrammar>, grammar, rule->grammars)
|
|
{
|
|
ValidateRuleStructureVisitor visitor(definition, manager, rule.Obj(), errors);
|
|
grammar->Accept(&visitor);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ResolveRuleSymbols
|
|
***********************************************************************/
|
|
|
|
struct GrammarPathFragment
|
|
{
|
|
// primitive, text -> transition
|
|
// loop, optional, create, use assign, setter -> epsilon
|
|
GrammarPathFragment* previousFragment;
|
|
ParsingDefinitionGrammar* grammar;
|
|
bool epsilon;
|
|
ParsingSymbol* createdType;
|
|
|
|
GrammarPathFragment()
|
|
:previousFragment(0)
|
|
,grammar(0)
|
|
,epsilon(false)
|
|
,createdType(0)
|
|
{
|
|
}
|
|
};
|
|
|
|
struct GrammarPath
|
|
{
|
|
List<Ptr<GrammarPathFragment>> fragments;
|
|
ParsingSymbol* pathType;
|
|
|
|
GrammarPath()
|
|
:pathType(0)
|
|
{
|
|
}
|
|
|
|
WString ToString()
|
|
{
|
|
WString result;
|
|
FOREACH(Ptr<GrammarPathFragment>, fragment, fragments)
|
|
{
|
|
if(!fragment->epsilon)
|
|
{
|
|
if(result!=L"") result+=L" ";
|
|
result+=GrammarToString(fragment->grammar);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
};
|
|
|
|
struct GrammarPathContainer
|
|
{
|
|
List<Ptr<GrammarPath>> paths;
|
|
};
|
|
|
|
class EnumerateGrammarPathVisitor : public Object, public ParsingDefinitionGrammar::IVisitor
|
|
{
|
|
public:
|
|
ParsingSymbolManager* manager;
|
|
ParsingDefinitionRuleDefinition* rule;
|
|
|
|
List<Ptr<GrammarPathFragment>> createdFragments;
|
|
List<GrammarPathFragment*> currentFragmentEnds;
|
|
|
|
EnumerateGrammarPathVisitor(ParsingSymbolManager* _manager, ParsingDefinitionRuleDefinition* _rule)
|
|
:manager(_manager)
|
|
,rule(_rule)
|
|
{
|
|
}
|
|
|
|
EnumerateGrammarPathVisitor(const EnumerateGrammarPathVisitor& visitor)
|
|
:manager(visitor.manager)
|
|
,rule(visitor.rule)
|
|
{
|
|
CopyFrom(currentFragmentEnds, visitor.currentFragmentEnds);
|
|
}
|
|
|
|
void Join(const EnumerateGrammarPathVisitor& visitor)
|
|
{
|
|
CopyFrom(createdFragments, visitor.createdFragments, true);
|
|
CopyFrom(currentFragmentEnds, visitor.currentFragmentEnds, true);
|
|
}
|
|
|
|
void AddFragment(ParsingDefinitionGrammar* node, bool epsilon, ParsingSymbol* createdType)
|
|
{
|
|
if(currentFragmentEnds.Count()==0)
|
|
{
|
|
GrammarPathFragment* fragment=new GrammarPathFragment;
|
|
fragment->grammar=node;
|
|
fragment->epsilon=epsilon;
|
|
fragment->createdType=createdType;
|
|
createdFragments.Add(fragment);
|
|
currentFragmentEnds.Add(fragment);
|
|
}
|
|
else for(vint i=0;i<currentFragmentEnds.Count();i++)
|
|
{
|
|
GrammarPathFragment* fragment=new GrammarPathFragment;
|
|
fragment->grammar=node;
|
|
fragment->epsilon=epsilon;
|
|
fragment->createdType=createdType;
|
|
createdFragments.Add(fragment);
|
|
fragment->previousFragment=currentFragmentEnds[i];
|
|
currentFragmentEnds[i]=fragment;
|
|
}
|
|
}
|
|
|
|
void BuildPath(List<Ptr<GrammarPath>>& paths)
|
|
{
|
|
FOREACH(GrammarPathFragment*, fragment, currentFragmentEnds)
|
|
{
|
|
Ptr<GrammarPath> path=new GrammarPath;
|
|
paths.Add(path);
|
|
|
|
GrammarPathFragment* current=fragment;
|
|
while(current)
|
|
{
|
|
path->fragments.Insert(0, createdFragments[createdFragments.IndexOf(current)]);
|
|
current=current->previousFragment;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveGrammar* node)override
|
|
{
|
|
AddFragment(node, false, 0);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTextGrammar* node)override
|
|
{
|
|
AddFragment(node, false, 0);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSequenceGrammar* node)override
|
|
{
|
|
node->first->Accept(this);
|
|
node->second->Accept(this);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAlternativeGrammar* node)override
|
|
{
|
|
EnumerateGrammarPathVisitor visitor(*this);
|
|
node->second->Accept(&visitor);
|
|
node->first->Accept(this);
|
|
Join(visitor);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionLoopGrammar* node)override
|
|
{
|
|
EnumerateGrammarPathVisitor visitor(*this);
|
|
node->grammar->Accept(&visitor);
|
|
AddFragment(node, true, 0);
|
|
Join(visitor);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionOptionalGrammar* node)override
|
|
{
|
|
EnumerateGrammarPathVisitor visitor(*this);
|
|
node->grammar->Accept(&visitor);
|
|
AddFragment(node, true, 0);
|
|
Join(visitor);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionCreateGrammar* node)override
|
|
{
|
|
node->grammar->Accept(this);
|
|
AddFragment(node, true, manager->CacheGetType(node->type.Obj(), 0));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAssignGrammar* node)override
|
|
{
|
|
node->grammar->Accept(this);
|
|
AddFragment(node, true, 0);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionUseGrammar* node)override
|
|
{
|
|
node->grammar->Accept(this);
|
|
AddFragment(node, true, manager->CacheGetSymbol(node->grammar.Obj())->GetDescriptorSymbol());
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSetterGrammar* node)override
|
|
{
|
|
node->grammar->Accept(this);
|
|
AddFragment(node, true, 0);
|
|
}
|
|
};
|
|
|
|
class ResolveAssignerGrammarVisitor : public Object, public ParsingDefinitionGrammar::IVisitor
|
|
{
|
|
public:
|
|
typedef Dictionary<ParsingDefinitionGrammar*, Ptr<GrammarPathContainer>> GrammarPathMap;
|
|
ParsingSymbolManager* manager;
|
|
List<Ptr<ParsingError>>& errors;
|
|
GrammarPathMap& grammarPaths;
|
|
|
|
ResolveAssignerGrammarVisitor(ParsingSymbolManager* _manager, List<Ptr<ParsingError>>& _errors, GrammarPathMap& _grammarPaths)
|
|
:manager(_manager)
|
|
,errors(_errors)
|
|
,grammarPaths(_grammarPaths)
|
|
{
|
|
}
|
|
|
|
ParsingSymbol* GetFieldFromCombined(ParsingDefinitionGrammar* node, const WString& fieldName)
|
|
{
|
|
Ptr<GrammarPathContainer> paths=grammarPaths[node];
|
|
ParsingSymbol* pathType=paths->paths[0]->pathType;
|
|
for(vint i=1;i<paths->paths.Count();i++)
|
|
{
|
|
pathType=pathType->SearchCommonBaseClass(paths->paths[i]->pathType);
|
|
if(!pathType) break;
|
|
}
|
|
|
|
WString pathNames;
|
|
WString typeNames;
|
|
for(int i=0;i<paths->paths.Count();i++)
|
|
{
|
|
if(i>0)
|
|
{
|
|
pathNames+=L", ";
|
|
typeNames+=L", ";
|
|
}
|
|
pathNames+=L"{"+paths->paths[i]->ToString()+L"}";
|
|
typeNames+=L"\""+GetTypeFullName(paths->paths[i]->pathType)+L"\"";
|
|
}
|
|
|
|
if(pathType)
|
|
{
|
|
ParsingSymbol* field=pathType->SearchClassSubSymbol(fieldName);
|
|
if(!field)
|
|
{
|
|
errors.Add(new ParsingError(node, L"There are multiple grammar paths with different created types get through this operation for class field \""+fieldName+L"\", but the common base type \""+GetTypeFullName(pathType)+L"\" of these types doesn't contains the required class field. Types: "+typeNames+L"; Paths: "+pathNames+L"."));
|
|
}
|
|
else if(field->GetType()!=ParsingSymbol::ClassField)
|
|
{
|
|
errors.Add(new ParsingError(node, L"There are multiple grammar paths with different created types get through this operation for class field \""+fieldName+L"\", and the common base type \""+GetTypeFullName(pathType)+L"\" of these types contains a symbol called \""+fieldName+L"\", but this is not a class field. Types: "+typeNames+L"; Paths: "+pathNames+L"."));
|
|
}
|
|
else
|
|
{
|
|
return field;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
errors.Add(new ParsingError(node, L"There are multiple grammar paths with different created types get through this operation for class field \""+fieldName+L"\", but these types don't have a common base type. Types: "+typeNames+L"; Paths: "+pathNames+L"."));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTextGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSequenceGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAlternativeGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionLoopGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionOptionalGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionCreateGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAssignGrammar* node)override
|
|
{
|
|
if(ParsingSymbol* field=GetFieldFromCombined(node, node->memberName))
|
|
{
|
|
manager->CacheSetSymbol(node, field);
|
|
manager->CacheSetType(node, field->GetDescriptorSymbol());
|
|
|
|
ParsingSymbol* fieldType=field->GetDescriptorSymbol();
|
|
ParsingSymbol* valueType=manager->CacheGetType(node->grammar.Obj());
|
|
ParsingSymbol* targetFieldType=fieldType;
|
|
if(targetFieldType->GetType()==ParsingSymbol::ArrayType)
|
|
{
|
|
targetFieldType=targetFieldType->GetDescriptorSymbol();
|
|
}
|
|
if(targetFieldType!=valueType && valueType->SearchCommonBaseClass(targetFieldType)!=targetFieldType)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Cannot assign value from grammar {"+GrammarToString(node->grammar.Obj())+L"} of type \""+GetTypeFullName(valueType)+L"\" to the field \""+node->memberName+L"\" of type \""+GetTypeFullName(fieldType)+L"\"."));
|
|
}
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionUseGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSetterGrammar* node)override
|
|
{
|
|
if(ParsingSymbol* field=GetFieldFromCombined(node, node->memberName))
|
|
{
|
|
manager->CacheSetSymbol(node, field);
|
|
manager->CacheSetType(node, field->GetDescriptorSymbol());
|
|
|
|
if(field->GetDescriptorSymbol()->GetType()!=ParsingSymbol::EnumType)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Setter operation (the \"with\" operator) can only specify the value of a class field of an enum type. But \""+GetTypeFullName(field->GetDescriptorSymbol())+L"\" is not a enum type."));
|
|
}
|
|
else
|
|
{
|
|
ParsingSymbol* enumType=field->GetDescriptorSymbol();
|
|
ParsingSymbol* enumItem=enumType->GetSubSymbolByName(node->value);
|
|
if(!enumItem)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Type \""+GetTypeFullName(enumType)+L"\" from field \""+node->memberName+L"\" does not have an enum item called \""+node->value+L"\"."));
|
|
}
|
|
else if(enumItem->GetType()!=ParsingSymbol::EnumItem)
|
|
{
|
|
errors.Add(new ParsingError(node, L"Type \""+GetTypeFullName(enumType)+L"\" from field \""+node->memberName+L"\" has a symbol called \""+node->value+L"\", but this is not an enum item."));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
void ResolveRuleSymbols(Ptr<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
ParsingSymbol* ruleType=manager->GetGlobal()->GetSubSymbolByName(rule->name)->GetDescriptorSymbol();
|
|
|
|
FOREACH(Ptr<ParsingDefinitionGrammar>, grammar, rule->grammars)
|
|
{
|
|
List<Ptr<GrammarPath>> paths;
|
|
{
|
|
EnumerateGrammarPathVisitor visitor(manager, rule.Obj());
|
|
grammar->Accept(&visitor);
|
|
visitor.BuildPath(paths);
|
|
}
|
|
|
|
FOREACH(Ptr<GrammarPath>, path, paths)
|
|
{
|
|
path->pathType=ruleType;
|
|
vint createdTypeCount=0;
|
|
vint transitionCount=0;
|
|
FOREACH(Ptr<GrammarPathFragment>, fragment, path->fragments)
|
|
{
|
|
if(fragment->createdType)
|
|
{
|
|
createdTypeCount++;
|
|
path->pathType=fragment->createdType;
|
|
}
|
|
if(!fragment->epsilon)
|
|
{
|
|
transitionCount++;
|
|
}
|
|
}
|
|
|
|
if(createdTypeCount==0)
|
|
{
|
|
errors.Add(new ParsingError(grammar.Obj(), L"No parsing tree node is created if the following path is chosen: \""+path->ToString()+L"\" in rule \""+rule->name+L"\"."));
|
|
}
|
|
else if(createdTypeCount>1)
|
|
{
|
|
errors.Add(new ParsingError(grammar.Obj(), L"Multiple parsing tree nodes are created if the following path is chosen: \""+path->ToString()+L"\" in rule \""+rule->name+L"\"."));
|
|
}
|
|
if(transitionCount==0)
|
|
{
|
|
errors.Add(new ParsingError(grammar.Obj(), L"Rule \""+rule->name+L"\" is not allowed to infer to an empty token sequence."));
|
|
}
|
|
}
|
|
|
|
ResolveAssignerGrammarVisitor::GrammarPathMap grammarPathMap;
|
|
FOREACH(Ptr<GrammarPath>, path, paths)
|
|
{
|
|
FOREACH(Ptr<GrammarPathFragment>, fragment, path->fragments)
|
|
{
|
|
ParsingDefinitionGrammar* grammar=fragment->grammar;
|
|
Ptr<GrammarPathContainer> container;
|
|
vint index=grammarPathMap.Keys().IndexOf(grammar);
|
|
if(index==-1)
|
|
{
|
|
container=new GrammarPathContainer;
|
|
grammarPathMap.Add(grammar, container);
|
|
}
|
|
else
|
|
{
|
|
container=grammarPathMap.Values().Get(index);
|
|
}
|
|
container->paths.Add(path);
|
|
}
|
|
}
|
|
|
|
ResolveAssignerGrammarVisitor visitor(manager, errors, grammarPathMap);
|
|
FOREACH(ParsingDefinitionGrammar*, grammar, grammarPathMap.Keys())
|
|
{
|
|
grammar->Accept(&visitor);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ResolveSymbols
|
|
***********************************************************************/
|
|
|
|
void ResolveTypeSymbols(Ptr<ParsingDefinitionTypeDefinition> type, ParsingSymbolManager* manager, ParsingSymbol* scope, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
if(Ptr<ParsingDefinitionClassDefinition> node=type.Cast<ParsingDefinitionClassDefinition>())
|
|
{
|
|
if(node->ambiguousType)
|
|
{
|
|
ParsingSymbol* ambigiousType=FindType(node->ambiguousType.Obj(), manager, scope, errors);
|
|
WString ambiguousTypeText=TypeToString(node->ambiguousType.Obj());
|
|
if(!ambigiousType)
|
|
{
|
|
errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" does not exist."));
|
|
}
|
|
else if(ambigiousType->GetType()!=ParsingSymbol::ClassType)
|
|
{
|
|
errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" is not a type."));
|
|
}
|
|
else if(ambigiousType->GetDescriptorSymbol()!=manager->GetGlobal()->GetSubSymbolByName(node->name))
|
|
{
|
|
errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" does not inherit from \""+node->name+L"\"."));
|
|
}
|
|
else
|
|
{
|
|
bool correct=false;
|
|
if(ambigiousType->GetSubSymbolCount()==1)
|
|
{
|
|
ParsingSymbol* field=ambigiousType->GetSubSymbol(0);
|
|
if(field->GetName()==L"items" && field->GetType()==ParsingSymbol::ClassField)
|
|
{
|
|
ParsingSymbol* fieldType=field->GetDescriptorSymbol();
|
|
if(fieldType->GetType()==ParsingSymbol::ArrayType && fieldType->GetDescriptorSymbol()==ambigiousType->GetDescriptorSymbol())
|
|
{
|
|
correct=true;
|
|
}
|
|
}
|
|
}
|
|
if(!correct)
|
|
{
|
|
errors.Add(new ParsingError(node.Obj(), L"Ambiguous type \""+ambiguousTypeText+L"\" for type \""+node->name+L"\" can only contains one field called \"item\" which should be an array of \""+node->name+L"\"."));
|
|
}
|
|
}
|
|
}
|
|
|
|
ParsingSymbol* classType=manager->CacheGetClassType(node.Obj());
|
|
if(classType)
|
|
{
|
|
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, subType, node->subTypes)
|
|
{
|
|
ResolveTypeSymbols(subType, manager, classType, errors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ResolveSymbols(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, type, definition->types)
|
|
{
|
|
ResolveTypeSymbols(type, manager, manager->GetGlobal(), errors);
|
|
}
|
|
|
|
FOREACH(Ptr<ParsingDefinitionRuleDefinition>, rule, definition->rules)
|
|
{
|
|
vint errorCount=errors.Count();
|
|
ValidateRuleStructure(definition, rule, manager, errors);
|
|
if(errors.Count()==errorCount)
|
|
{
|
|
ResolveRuleSymbols(rule, manager, errors);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ValidateDefinition
|
|
***********************************************************************/
|
|
|
|
void ValidateDefinition(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
PrepareSymbols(definition, manager, errors);
|
|
if(errors.Count()>0) return;
|
|
ResolveSymbols(definition, manager, errors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
Action
|
|
***********************************************************************/
|
|
|
|
Action::Action()
|
|
:actionType(Create)
|
|
,actionSource(0)
|
|
,actionTarget(0)
|
|
,creatorRule(0)
|
|
,shiftReduceSource(0)
|
|
,shiftReduceTarget(0)
|
|
{
|
|
}
|
|
|
|
Action::~Action()
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
Transition
|
|
***********************************************************************/
|
|
|
|
Transition::Transition()
|
|
:source(0)
|
|
,target(0)
|
|
,transitionType(Epsilon)
|
|
,stackOperationType(None)
|
|
,transitionSymbol(0)
|
|
{
|
|
}
|
|
|
|
Transition::~Transition()
|
|
{
|
|
}
|
|
|
|
bool Transition::IsEquivalent(Transition* t1, Transition* t2, bool careSourceAndTarget)
|
|
{
|
|
if(careSourceAndTarget)
|
|
{
|
|
if(t1->source!=t2->source || t1->target!=t2->target)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
if( t1->actions.Count()!=t2->actions.Count() ||
|
|
t1->transitionType!=t2->transitionType ||
|
|
t1->transitionSymbol!=t2->transitionSymbol)
|
|
{
|
|
return false;
|
|
}
|
|
for(vint j=0;j<t1->actions.Count();j++)
|
|
{
|
|
Ptr<Action> a1=t1->actions[j];
|
|
Ptr<Action> a2=t2->actions[j];
|
|
if( a1->actionType!=a2->actionType ||
|
|
a1->actionSource!=a2->actionSource ||
|
|
a1->actionTarget!=a2->actionTarget ||
|
|
a1->shiftReduceSource!=a2->shiftReduceSource )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
State
|
|
***********************************************************************/
|
|
|
|
State::State()
|
|
:ownerRule(0)
|
|
,ownerRuleSymbol(0)
|
|
,grammarNode(0)
|
|
,stateNode(0)
|
|
,statePosition(BeforeNode)
|
|
,endState(false)
|
|
{
|
|
}
|
|
|
|
State::~State()
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
RuleInfo
|
|
***********************************************************************/
|
|
|
|
RuleInfo::RuleInfo()
|
|
:rootRuleStartState(0)
|
|
,rootRuleEndState(0)
|
|
,startState(0)
|
|
,stateNameCount(0)
|
|
{
|
|
}
|
|
|
|
RuleInfo::~RuleInfo()
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
Automaton
|
|
***********************************************************************/
|
|
|
|
Automaton::Automaton(ParsingSymbolManager* _symbolManager)
|
|
:symbolManager(_symbolManager)
|
|
{
|
|
}
|
|
|
|
Automaton::~Automaton()
|
|
{
|
|
}
|
|
|
|
void Automaton::AddRuleInfo(definitions::ParsingDefinitionRuleDefinition* rule, Ptr<RuleInfo> ruleInfo)
|
|
{
|
|
orderedRulesDefs.Add(rule);
|
|
ruleInfos.Add(ruleInfo);
|
|
ruleDefToInfoMap.Add(rule, ruleInfo);
|
|
}
|
|
|
|
State* Automaton::RuleStartState(definitions::ParsingDefinitionRuleDefinition* ownerRule)
|
|
{
|
|
State* state=new State;
|
|
states.Add(state);
|
|
|
|
state->ownerRule=ownerRule;
|
|
state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name);
|
|
state->stateName=ownerRule->name+L".Start";
|
|
state->stateExpression=L"@ <"+ownerRule->name+L">";
|
|
return state;
|
|
}
|
|
|
|
State* Automaton::RootRuleStartState(definitions::ParsingDefinitionRuleDefinition* ownerRule)
|
|
{
|
|
State* state=new State;
|
|
states.Add(state);
|
|
|
|
state->ownerRule=ownerRule;
|
|
state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name);
|
|
state->stateName=ownerRule->name+L".RootStart";
|
|
state->stateExpression=L"@ $<"+ownerRule->name+L">";
|
|
return state;
|
|
}
|
|
|
|
State* Automaton::RootRuleEndState(definitions::ParsingDefinitionRuleDefinition* ownerRule)
|
|
{
|
|
State* state=new State;
|
|
states.Add(state);
|
|
|
|
state->ownerRule=ownerRule;
|
|
state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name);
|
|
state->stateName=ownerRule->name+L".RootEnd";
|
|
state->stateExpression=L"$<"+ownerRule->name+L"> @";
|
|
return state;
|
|
}
|
|
|
|
State* Automaton::StartState(definitions::ParsingDefinitionRuleDefinition* ownerRule, definitions::ParsingDefinitionGrammar* grammarNode, definitions::ParsingDefinitionGrammar* stateNode)
|
|
{
|
|
State* state=new State;
|
|
states.Add(state);
|
|
|
|
state->ownerRule=ownerRule;
|
|
state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name);
|
|
state->grammarNode=grammarNode;
|
|
state->stateNode=stateNode;
|
|
state->statePosition=State::BeforeNode;
|
|
state->stateName=ownerRule->name+L"."+itow(++ruleDefToInfoMap[ownerRule]->stateNameCount);
|
|
stateNode=FindAppropriateGrammarState(grammarNode, stateNode, true);
|
|
state->stateExpression=L"<"+ownerRule->name+L">: "+GrammarStateToString(grammarNode, stateNode, true);
|
|
return state;
|
|
}
|
|
|
|
State* Automaton::EndState(definitions::ParsingDefinitionRuleDefinition* ownerRule, definitions::ParsingDefinitionGrammar* grammarNode, definitions::ParsingDefinitionGrammar* stateNode)
|
|
{
|
|
State* state=new State;
|
|
states.Add(state);
|
|
|
|
state->ownerRule=ownerRule;
|
|
state->ownerRuleSymbol=symbolManager->GetGlobal()->GetSubSymbolByName(ownerRule->name);
|
|
state->grammarNode=grammarNode;
|
|
state->stateNode=stateNode;
|
|
state->statePosition=State::AfterNode;
|
|
state->stateName=ownerRule->name+L"."+itow(++ruleDefToInfoMap[ownerRule]->stateNameCount);
|
|
stateNode=FindAppropriateGrammarState(grammarNode, stateNode, false);
|
|
state->stateExpression=L"<"+ownerRule->name+L">: "+GrammarStateToString(grammarNode, stateNode, false);
|
|
return state;
|
|
}
|
|
|
|
State* Automaton::CopyState(State* oldState)
|
|
{
|
|
State* resultState=0;
|
|
if(oldState->statePosition==State::BeforeNode)
|
|
{
|
|
resultState=StartState(oldState->ownerRule, oldState->grammarNode, oldState->stateNode);
|
|
}
|
|
else
|
|
{
|
|
resultState=EndState(oldState->ownerRule, oldState->grammarNode, oldState->stateNode);
|
|
}
|
|
resultState->endState=oldState->endState;
|
|
return resultState;
|
|
}
|
|
|
|
Transition* Automaton::CreateTransition(State* start, State* end)
|
|
{
|
|
Transition* transition=new Transition;
|
|
transitions.Add(transition);
|
|
|
|
start->transitions.Add(transition);
|
|
end->inputs.Add(transition);
|
|
|
|
transition->source=start;
|
|
transition->target=end;
|
|
return transition;
|
|
}
|
|
|
|
Transition* Automaton::TokenBegin(State* start, State* end)
|
|
{
|
|
Transition* transition=CreateTransition(start, end);
|
|
transition->transitionType=Transition::TokenBegin;
|
|
return transition;
|
|
}
|
|
|
|
Transition* Automaton::TokenFinish(State* start, State* end)
|
|
{
|
|
Transition* transition=CreateTransition(start, end);
|
|
transition->transitionType=Transition::TokenFinish;
|
|
return transition;
|
|
}
|
|
|
|
Transition* Automaton::NormalReduce(State* start, State* end)
|
|
{
|
|
Transition* transition=CreateTransition(start, end);
|
|
transition->transitionType=Transition::NormalReduce;
|
|
return transition;
|
|
}
|
|
|
|
Transition* Automaton::LeftRecursiveReduce(State* start, State* end)
|
|
{
|
|
Transition* transition=CreateTransition(start, end);
|
|
transition->transitionType=Transition::LeftRecursiveReduce;
|
|
return transition;
|
|
}
|
|
|
|
Transition* Automaton::Epsilon(State* start, State* end)
|
|
{
|
|
Transition* transition=CreateTransition(start, end);
|
|
transition->transitionType=Transition::Epsilon;
|
|
return transition;
|
|
}
|
|
|
|
Transition* Automaton::Symbol(State* start, State* end, ParsingSymbol* transitionSymbol)
|
|
{
|
|
Transition* transition=CreateTransition(start, end);
|
|
transition->transitionType=Transition::Symbol;
|
|
transition->transitionSymbol=transitionSymbol;
|
|
return transition;
|
|
}
|
|
|
|
Transition* Automaton::CopyTransition(State* start, State* end, Transition* oldTransition)
|
|
{
|
|
Transition* transition=CreateTransition(start, end);
|
|
transition->transitionType=oldTransition->transitionType;
|
|
transition->stackOperationType=oldTransition->stackOperationType;
|
|
transition->transitionSymbol=oldTransition->transitionSymbol;
|
|
return transition;
|
|
}
|
|
|
|
void Automaton::DeleteTransition(Transition* transition)
|
|
{
|
|
transition->source->transitions.Remove(transition);
|
|
transition->target->inputs.Remove(transition);
|
|
transitions.Remove(transition);
|
|
}
|
|
|
|
void Automaton::DeleteState(State* state)
|
|
{
|
|
while(state->inputs.Count())
|
|
{
|
|
DeleteTransition(state->inputs[0]);
|
|
}
|
|
while(state->transitions.Count())
|
|
{
|
|
DeleteTransition(state->transitions[0]);
|
|
}
|
|
states.Remove(state);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON_CLOSURE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
CreateNondeterministicPDAFromEpsilonPDA::closure_searching
|
|
***********************************************************************/
|
|
|
|
// closure function for searching <epsilon* symbol> reachable states
|
|
ClosureItem::SearchResult EpsilonClosure(Transition* transition)
|
|
{
|
|
return
|
|
transition->transitionType!=Transition::Epsilon?ClosureItem::Hit:
|
|
//transition->target->endState?ClosureItem::Blocked:
|
|
ClosureItem::Continue;
|
|
}
|
|
|
|
// closure searching function
|
|
void SearchClosureInternal(ClosureItem::SearchResult(*closurePredicate)(Transition*), List<Transition*>& transitionPath, Transition* transition, State* state, List<ClosureItem>& closure)
|
|
{
|
|
FOREACH(Transition*, singleTransitionPath, transitionPath)
|
|
{
|
|
if(singleTransitionPath->source==state && closurePredicate(singleTransitionPath)!=ClosureItem::Blocked)
|
|
{
|
|
Ptr<List<Transition*>> path=new List<Transition*>;
|
|
CopyFrom(*path.Obj(), transitionPath);
|
|
closure.Add(ClosureItem(state, path, true));
|
|
return;
|
|
}
|
|
}
|
|
|
|
ClosureItem::SearchResult result=transition?closurePredicate(transition):ClosureItem::Continue;
|
|
switch(result)
|
|
{
|
|
case ClosureItem::Continue:
|
|
{
|
|
FOREACH(Transition*, newTransition, state->transitions)
|
|
{
|
|
if(!transitionPath.Contains(newTransition))
|
|
{
|
|
transitionPath.Add(newTransition);
|
|
SearchClosureInternal(closurePredicate, transitionPath, newTransition, newTransition->target, closure);
|
|
transitionPath.RemoveAt(transitionPath.Count()-1);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ClosureItem::Hit:
|
|
{
|
|
Ptr<List<Transition*>> path=new List<Transition*>;
|
|
CopyFrom(*path.Obj(), transitionPath);
|
|
closure.Add(ClosureItem(state, path, false));
|
|
}
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
|
|
void SearchClosure(ClosureItem::SearchResult(*closurePredicate)(Transition*), State* startState, List<ClosureItem>& closure)
|
|
{
|
|
List<Transition*> transitionPath;
|
|
SearchClosureInternal(closurePredicate, transitionPath, 0, startState, closure);
|
|
}
|
|
|
|
// map old state to new state and track all states that are not visited yet
|
|
State* GetMappedState(Ptr<Automaton> newAutomaton, State* oldState, List<State*>& scanningStates, Dictionary<State*, State*>& oldNewStateMap)
|
|
{
|
|
State* newState=0;
|
|
vint mapIndex=oldNewStateMap.Keys().IndexOf(oldState);
|
|
if(mapIndex==-1)
|
|
{
|
|
newState=newAutomaton->CopyState(oldState);
|
|
oldNewStateMap.Add(oldState, newState);
|
|
}
|
|
else
|
|
{
|
|
newState=oldNewStateMap.Values().Get(mapIndex);
|
|
}
|
|
if(!scanningStates.Contains(oldState))
|
|
{
|
|
scanningStates.Add(oldState);
|
|
}
|
|
return newState;
|
|
}
|
|
|
|
/***********************************************************************
|
|
RemoveEpsilonTransitions
|
|
***********************************************************************/
|
|
|
|
void RemoveEpsilonTransitions(collections::Dictionary<State*, State*>& oldNewStateMap, collections::List<State*>& scanningStates, Ptr<Automaton> automaton)
|
|
{
|
|
vint currentStateIndex=0;
|
|
|
|
while(currentStateIndex<scanningStates.Count())
|
|
{
|
|
// map visiting state to new state
|
|
State* currentOldState=scanningStates[currentStateIndex++];
|
|
State* currentNewState=GetMappedState(automaton, currentOldState, scanningStates, oldNewStateMap);
|
|
|
|
// search for epsilon closure
|
|
List<ClosureItem> closure;
|
|
SearchClosure(&EpsilonClosure, currentOldState, closure);
|
|
FOREACH(ClosureItem, closureItem, closure)
|
|
{
|
|
Transition* oldTransition=closureItem.transitions->Get(closureItem.transitions->Count()-1);
|
|
if(!closureItem.cycle || oldTransition->transitionType!=Transition::Epsilon)
|
|
{
|
|
// if the oldTransition begins from an end state
|
|
if(oldTransition->source->endState && closureItem.transitions->Count()>1)
|
|
{
|
|
// keep a epsilon transition that without the last "TokenFinish"
|
|
State* newEndState=GetMappedState(automaton, oldTransition->source, scanningStates, oldNewStateMap);
|
|
Transition* transition=automaton->Epsilon(currentNewState, newEndState);
|
|
FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj())
|
|
{
|
|
if(pathTransition==oldTransition) break;
|
|
CopyFrom(transition->actions, pathTransition->actions, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// build compacted non-epsilon transition to the target state of the path
|
|
State* newEndState=GetMappedState(automaton, oldTransition->target, scanningStates, oldNewStateMap);
|
|
Transition* transition=automaton->CopyTransition(currentNewState, newEndState, oldTransition);
|
|
FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj())
|
|
{
|
|
CopyFrom(transition->actions, pathTransition->actions, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON_EPDA.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
CreateEpsilonPDAVisitor
|
|
***********************************************************************/
|
|
|
|
class CreateEpsilonPDAVisitor : public Object, public ParsingDefinitionGrammar::IVisitor
|
|
{
|
|
public:
|
|
Ptr<Automaton> automaton;
|
|
ParsingDefinitionRuleDefinition* rule;
|
|
ParsingDefinitionGrammar* ruleGrammar;
|
|
State* startState;
|
|
State* endState;
|
|
Transition* result;
|
|
|
|
CreateEpsilonPDAVisitor(Ptr<Automaton> _automaton, ParsingDefinitionRuleDefinition* _rule, ParsingDefinitionGrammar* _ruleGrammar, State* _startState, State* _endState)
|
|
:automaton(_automaton)
|
|
,rule(_rule)
|
|
,ruleGrammar(_ruleGrammar)
|
|
,startState(_startState)
|
|
,endState(_endState)
|
|
,result(0)
|
|
{
|
|
}
|
|
|
|
static Transition* Create(ParsingDefinitionGrammar* grammar, Ptr<Automaton> automaton, ParsingDefinitionRuleDefinition* rule, ParsingDefinitionGrammar* ruleGrammar, State* startState, State* endState)
|
|
{
|
|
CreateEpsilonPDAVisitor visitor(automaton, rule, ruleGrammar, startState, endState);
|
|
grammar->Accept(&visitor);
|
|
return visitor.result;
|
|
}
|
|
|
|
Transition* Create(ParsingDefinitionGrammar* grammar, State* startState, State* endState)
|
|
{
|
|
return Create(grammar, automaton, rule, ruleGrammar, startState, endState);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveGrammar* node)override
|
|
{
|
|
result=automaton->Symbol(startState, endState, automaton->symbolManager->CacheGetSymbol(node));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTextGrammar* node)override
|
|
{
|
|
result=automaton->Symbol(startState, endState, automaton->symbolManager->CacheGetSymbol(node));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSequenceGrammar* node)override
|
|
{
|
|
State* middleState=automaton->EndState(startState->ownerRule, ruleGrammar, node->first.Obj());
|
|
Create(node->first.Obj(), startState, middleState);
|
|
Create(node->second.Obj(), middleState, endState);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAlternativeGrammar* node)override
|
|
{
|
|
Create(node->first.Obj(), startState, endState);
|
|
Create(node->second.Obj(), startState, endState);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionLoopGrammar* node)override
|
|
{
|
|
State* loopStart=automaton->StartState(startState->ownerRule, ruleGrammar, node->grammar.Obj());
|
|
automaton->Epsilon(startState, loopStart);
|
|
automaton->Epsilon(loopStart, endState);
|
|
Create(node->grammar.Obj(), loopStart, loopStart);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionOptionalGrammar* node)override
|
|
{
|
|
Create(node->grammar.Obj(), startState, endState);
|
|
automaton->Epsilon(startState, endState);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionCreateGrammar* node)override
|
|
{
|
|
State* middleState=automaton->EndState(startState->ownerRule, ruleGrammar, node->grammar.Obj());
|
|
Create(node->grammar.Obj(), startState, middleState);
|
|
Transition* transition=automaton->Epsilon(middleState, endState);
|
|
|
|
Ptr<Action> action=new Action;
|
|
action->actionType=Action::Create;
|
|
action->actionSource=automaton->symbolManager->CacheGetType(node->type.Obj(), 0);
|
|
action->creatorRule=rule;
|
|
transition->actions.Add(action);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAssignGrammar* node)override
|
|
{
|
|
Transition* transition=Create(node->grammar.Obj(), startState, endState);
|
|
|
|
Ptr<Action> action=new Action;
|
|
action->actionType=Action::Assign;
|
|
action->actionSource=automaton->symbolManager->CacheGetSymbol(node);
|
|
action->creatorRule=rule;
|
|
transition->actions.Add(action);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionUseGrammar* node)override
|
|
{
|
|
Transition* transition=Create(node->grammar.Obj(), startState, endState);
|
|
|
|
Ptr<Action> action=new Action;
|
|
action->actionType=Action::Using;
|
|
action->creatorRule=rule;
|
|
transition->actions.Add(action);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSetterGrammar* node)override
|
|
{
|
|
State* middleState=automaton->EndState(startState->ownerRule, ruleGrammar, node->grammar.Obj());
|
|
Create(node->grammar.Obj(), startState, middleState);
|
|
Transition* transition=automaton->Epsilon(middleState, endState);
|
|
|
|
Ptr<Action> action=new Action;
|
|
action->actionType=Action::Setter;
|
|
action->actionSource=automaton->symbolManager->CacheGetSymbol(node);
|
|
action->actionTarget=action->actionSource->GetDescriptorSymbol()->GetSubSymbolByName(node->value);
|
|
action->creatorRule=rule;
|
|
transition->actions.Add(action);
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
CreateRuleEpsilonPDA
|
|
***********************************************************************/
|
|
|
|
void CreateRuleEpsilonPDA(Ptr<Automaton> automaton, Ptr<definitions::ParsingDefinitionRuleDefinition> rule, ParsingSymbolManager* manager)
|
|
{
|
|
Ptr<RuleInfo> ruleInfo=new RuleInfo;
|
|
automaton->AddRuleInfo(rule.Obj(), ruleInfo);
|
|
|
|
ruleInfo->rootRuleStartState=automaton->RootRuleStartState(rule.Obj());
|
|
ruleInfo->rootRuleEndState=automaton->RootRuleEndState(rule.Obj());
|
|
ruleInfo->startState=automaton->RuleStartState(rule.Obj());
|
|
automaton->TokenBegin(ruleInfo->rootRuleStartState, ruleInfo->startState);
|
|
|
|
FOREACH(Ptr<ParsingDefinitionGrammar>, grammar, rule->grammars)
|
|
{
|
|
State* grammarStartState=automaton->StartState(rule.Obj(), grammar.Obj(), grammar.Obj());
|
|
State* grammarEndState=automaton->EndState(rule.Obj(), grammar.Obj(), grammar.Obj());
|
|
grammarEndState->stateName+=L".End";
|
|
grammarEndState->endState=true;
|
|
automaton->Epsilon(ruleInfo->startState, grammarStartState);
|
|
automaton->TokenFinish(grammarEndState, ruleInfo->rootRuleEndState);
|
|
ruleInfo->endStates.Add(grammarEndState);
|
|
CreateEpsilonPDAVisitor::Create(grammar.Obj(), automaton, rule.Obj(), grammar.Obj(), grammarStartState, grammarEndState);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
CreateEpsilonPDA
|
|
***********************************************************************/
|
|
|
|
Ptr<Automaton> CreateEpsilonPDA(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager)
|
|
{
|
|
Ptr<Automaton> automaton=new Automaton(manager);
|
|
FOREACH(Ptr<ParsingDefinitionRuleDefinition>, rule, definition->rules)
|
|
{
|
|
CreateRuleEpsilonPDA(automaton, rule, manager);
|
|
}
|
|
return automaton;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON_GENERATETABLE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
using namespace tabling;
|
|
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
GetTypeNameForCreateInstruction
|
|
***********************************************************************/
|
|
|
|
WString GetTypeNameForCreateInstruction(ParsingSymbol* type)
|
|
{
|
|
ParsingSymbol* parent=type->GetParentSymbol();
|
|
if(parent->GetType()==ParsingSymbol::ClassType)
|
|
{
|
|
return GetTypeNameForCreateInstruction(parent)+L"."+type->GetName();
|
|
}
|
|
else
|
|
{
|
|
return type->GetName();
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
CreateLookAhead
|
|
***********************************************************************/
|
|
|
|
void CopyStableLookAheads(List<Ptr<ParsingTable::LookAheadInfo>>& la, List<Ptr<ParsingTable::LookAheadInfo>>& sla, const List<Ptr<ParsingTable::LookAheadInfo>>& la2)
|
|
{
|
|
CopyFrom(sla, From(la)
|
|
.Where([&](Ptr<ParsingTable::LookAheadInfo> lai)
|
|
{
|
|
return From(la2).All([&](Ptr<ParsingTable::LookAheadInfo> lai2)
|
|
{
|
|
return ParsingTable::LookAheadInfo::TestPrefix(lai, lai2)==ParsingTable::LookAheadInfo::NotPrefix;
|
|
});
|
|
}),
|
|
true);
|
|
}
|
|
|
|
void RemoveStableLookAheads(List<Ptr<ParsingTable::LookAheadInfo>>& la, const List<Ptr<ParsingTable::LookAheadInfo>>& sla)
|
|
{
|
|
for(vint i=la.Count()-1;i>=0;i--)
|
|
{
|
|
if(sla.Contains(la[i].Obj()))
|
|
{
|
|
la.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool WalkLookAheads(Ptr<ParsingTable> table, List<Ptr<ParsingTable::LookAheadInfo>>& la, vint maxTokenCount)
|
|
{
|
|
vint count=la.Count();
|
|
for(vint i=0;i<count;i++)
|
|
{
|
|
Ptr<ParsingTable::LookAheadInfo> lai=la[i];
|
|
if(lai->tokens.Count()==maxTokenCount)
|
|
{
|
|
return false;
|
|
}
|
|
ParsingTable::LookAheadInfo::Walk(table, lai, lai->state, la);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CompactLookAheads(Ptr<ParsingTable::TransitionItem> t, List<Ptr<ParsingTable::LookAheadInfo>>& sla)
|
|
{
|
|
CopyFrom(sla, t->lookAheads, true);
|
|
CopyFrom(t->lookAheads, From(sla)
|
|
.Where([&](Ptr<ParsingTable::LookAheadInfo> lai)
|
|
{
|
|
return From(sla).All([&](Ptr<ParsingTable::LookAheadInfo> lai2)
|
|
{
|
|
if(lai==lai2) return true;
|
|
ParsingTable::LookAheadInfo::PrefixResult result=ParsingTable::LookAheadInfo::TestPrefix(lai, lai2);
|
|
switch(result)
|
|
{
|
|
case ParsingTable::LookAheadInfo::Prefix:
|
|
return false;
|
|
case ParsingTable::LookAheadInfo::Equal:
|
|
return sla.IndexOf(lai.Obj()) < sla.IndexOf(lai2.Obj());
|
|
default:
|
|
return true;
|
|
}
|
|
});
|
|
}));
|
|
}
|
|
|
|
bool CreateLookAhead(Ptr<ParsingTable> table, Ptr<ParsingTable::TransitionItem> t1, Ptr<ParsingTable::TransitionItem> t2, vint maxTokenCount)
|
|
{
|
|
List<Ptr<ParsingTable::LookAheadInfo>> la1, la2, sla1, sla2;
|
|
|
|
// calculate 1-token look aheads
|
|
ParsingTable::LookAheadInfo::Walk(table, 0, t1->targetState, la1);
|
|
ParsingTable::LookAheadInfo::Walk(table, 0, t2->targetState, la2);
|
|
|
|
do
|
|
{
|
|
// pick up all stable look aheads and remove them from the look ahead list
|
|
// stable look ahead means, when the look ahead is satisfied, then the transition is picked up with full confidence
|
|
// non-stable look ahead means, when the look ahead is satisifed, it only increase confidence, needs further tokens for decision
|
|
CopyStableLookAheads(la1, sla1, la2);
|
|
CopyStableLookAheads(la2, sla2, la1);
|
|
RemoveStableLookAheads(la1, sla1);
|
|
RemoveStableLookAheads(la2, sla2);
|
|
|
|
// check if there are non-stable look aheads in two transitions points to the same state
|
|
// in such situation means that the two transition cannot always be determined using look aheads
|
|
FOREACH(Ptr<ParsingTable::LookAheadInfo>, lai1, la1)
|
|
{
|
|
FOREACH(Ptr<ParsingTable::LookAheadInfo>, lai2, la2)
|
|
{
|
|
if (lai1->state == lai2->state)
|
|
{
|
|
if (ParsingTable::LookAheadInfo::TestPrefix(lai1, lai2) != ParsingTable::LookAheadInfo::NotPrefix)
|
|
{
|
|
return false;
|
|
}
|
|
if (ParsingTable::LookAheadInfo::TestPrefix(lai2, lai1) != ParsingTable::LookAheadInfo::NotPrefix)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// use the non-stable look aheads to walk a token further
|
|
if(!WalkLookAheads(table, la1, maxTokenCount) || !WalkLookAheads(table, la2, maxTokenCount))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
while(la1.Count()>0 || la2.Count()>0);
|
|
|
|
CompactLookAheads(t1, sla1);
|
|
CompactLookAheads(t2, sla2);
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
CollectAttribute
|
|
***********************************************************************/
|
|
|
|
void CollectType(ParsingSymbol* symbol, List<ParsingSymbol*>& types)
|
|
{
|
|
if(symbol->GetType()==ParsingSymbol::ClassType)
|
|
{
|
|
types.Add(symbol);
|
|
}
|
|
vint count=symbol->GetSubSymbolCount();
|
|
for(vint i=0;i<count;i++)
|
|
{
|
|
CollectType(symbol->GetSubSymbol(i), types);
|
|
}
|
|
}
|
|
|
|
void CollectAttributeInfo(Ptr<ParsingTable::AttributeInfoList> att, List<Ptr<definitions::ParsingDefinitionAttribute>>& atts)
|
|
{
|
|
FOREACH(Ptr<definitions::ParsingDefinitionAttribute>, datt, atts)
|
|
{
|
|
Ptr<ParsingTable::AttributeInfo> tatt=new ParsingTable::AttributeInfo(datt->name);
|
|
CopyFrom(tatt->arguments, datt->arguments);
|
|
att->attributes.Add(tatt);
|
|
}
|
|
}
|
|
|
|
Ptr<ParsingTable::AttributeInfoList> CreateAttributeInfo(List<Ptr<definitions::ParsingDefinitionAttribute>>& atts)
|
|
{
|
|
Ptr<ParsingTable::AttributeInfoList> att=new ParsingTable::AttributeInfoList;
|
|
CollectAttributeInfo(att, atts);
|
|
return att;
|
|
}
|
|
|
|
/***********************************************************************
|
|
GenerateTable
|
|
***********************************************************************/
|
|
|
|
vint LookAheadConflictPriority(vint tableTokenIndex)
|
|
{
|
|
switch (tableTokenIndex)
|
|
{
|
|
case ParsingTable::NormalReduce:
|
|
return 0;
|
|
case ParsingTable::LeftRecursiveReduce:
|
|
return 1;
|
|
default:
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
void GenerateLookAhead(Ptr<ParsingTable> table, List<State*>& stateIds, vint state, vint token, Ptr<ParsingTable::TransitionItem> t1, Ptr<ParsingTable::TransitionItem> t2, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
if(ParsingTable::TransitionItem::CheckOrder(t1, t2, ParsingTable::TransitionItem::UnknownOrder)==ParsingTable::TransitionItem::UnknownOrder)
|
|
{
|
|
if(enableAmbiguity || !CreateLookAhead(table, t1, t2, 16))
|
|
{
|
|
if (LookAheadConflictPriority(t1->token) != LookAheadConflictPriority(t2->token))
|
|
{
|
|
return;
|
|
}
|
|
WString stateName=itow(state)+L"["+table->GetStateInfo(state).stateName+L"]";
|
|
WString tokenName=
|
|
token==ParsingTable::TokenBegin?WString(L"$TokenBegin"):
|
|
token==ParsingTable::TokenFinish?WString(L"$TokenFinish"):
|
|
token==ParsingTable::NormalReduce?WString(L"$NormalReduce"):
|
|
token==ParsingTable::LeftRecursiveReduce?WString(L"$LeftRecursiveReduce"):
|
|
table->GetTokenInfo(token).name;
|
|
switch (t1->token)
|
|
{
|
|
case ParsingTable::NormalReduce:
|
|
errors.Add(new ParsingError(stateIds[state]->ownerRule, L"Conflict happened with normal reduce in transition of \""+tokenName+L"\" of state \""+stateName+L"\"."));
|
|
break;
|
|
case ParsingTable::LeftRecursiveReduce:
|
|
errors.Add(new ParsingError(stateIds[state]->ownerRule, L"Conflict happened with left recursive reduce in transition of \""+tokenName+L"\" of state \""+stateName+L"\"."));
|
|
break;
|
|
default:
|
|
errors.Add(new ParsingError(stateIds[state]->ownerRule, L"Conflict happened in transition of \""+tokenName+L"\" of state \""+stateName+L"\"."));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Ptr<tabling::ParsingTable> GenerateTableFromPDA(Ptr<definitions::ParsingDefinition> definition, ParsingSymbolManager* manager, Ptr<Automaton> jointPDA, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
List<Ptr<ParsingTable::AttributeInfoList>> atts;
|
|
|
|
/***********************************************************************
|
|
find all class types
|
|
***********************************************************************/
|
|
List<ParsingSymbol*> types;
|
|
Dictionary<WString, vint> typeAtts;
|
|
Dictionary<Pair<WString, WString>, vint> treeFieldAtts;
|
|
|
|
// stable class field order
|
|
List<ParsingSymbol*> orderedChildTypeKeys;
|
|
Dictionary<ParsingSymbol*, Ptr<List<ParsingSymbol*>>> childTypeValues;
|
|
|
|
// find all class types
|
|
CollectType(manager->GetGlobal(), types);
|
|
FOREACH(ParsingSymbol*, type, types)
|
|
{
|
|
Ptr<ParsingTable::AttributeInfoList> typeAtt = new ParsingTable::AttributeInfoList;
|
|
ParsingSymbol* parent = type;
|
|
while (parent)
|
|
{
|
|
ParsingDefinitionClassDefinition* classDef = manager->CacheGetClassDefinition(parent);
|
|
CollectAttributeInfo(typeAtt, classDef->attributes);
|
|
|
|
Ptr<List<ParsingSymbol*>> children;
|
|
vint index = childTypeValues.Keys().IndexOf(parent);
|
|
if (index == -1)
|
|
{
|
|
children = new List<ParsingSymbol*>;
|
|
orderedChildTypeKeys.Add(parent);
|
|
childTypeValues.Add(parent, children);
|
|
}
|
|
else
|
|
{
|
|
children = childTypeValues.Values().Get(index);
|
|
}
|
|
|
|
children->Add(type);
|
|
parent = parent->GetDescriptorSymbol();
|
|
}
|
|
|
|
if (typeAtt->attributes.Count() > 0)
|
|
{
|
|
typeAtts.Add(GetTypeFullName(type), atts.Count());
|
|
atts.Add(typeAtt);
|
|
}
|
|
else
|
|
{
|
|
typeAtts.Add(GetTypeFullName(type), -1);
|
|
}
|
|
}
|
|
|
|
// find all class fields
|
|
FOREACH(ParsingSymbol*, type, orderedChildTypeKeys)
|
|
{
|
|
List<ParsingSymbol*>& children = *childTypeValues[type].Obj();
|
|
ParsingDefinitionClassDefinition* classDef = manager->CacheGetClassDefinition(type);
|
|
List<vint> fieldAtts;
|
|
|
|
FOREACH_INDEXER(Ptr<ParsingDefinitionClassMemberDefinition>, field, index, classDef->members)
|
|
{
|
|
if (field->attributes.Count() > 0)
|
|
{
|
|
fieldAtts.Add(atts.Count());
|
|
atts.Add(CreateAttributeInfo(field->attributes));
|
|
}
|
|
else
|
|
{
|
|
fieldAtts.Add(-1);
|
|
}
|
|
}
|
|
|
|
FOREACH(ParsingSymbol*, child, children)
|
|
{
|
|
WString type = GetTypeFullName(child);
|
|
FOREACH_INDEXER(Ptr<ParsingDefinitionClassMemberDefinition>, field, index, classDef->members)
|
|
{
|
|
treeFieldAtts.Add(Pair<WString, WString>(type, field->name), fieldAtts[index]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
find all tokens
|
|
***********************************************************************/
|
|
vint tokenCount = 0;
|
|
vint discardTokenCount = 0;
|
|
Dictionary<ParsingSymbol*, vint> tokenIds;
|
|
List<WString> discardTokens;
|
|
|
|
Dictionary<WString, vint> tokenAtts;
|
|
Dictionary<WString, vint> ruleAtts;
|
|
|
|
FOREACH(Ptr<ParsingDefinitionTokenDefinition>, token, definition->tokens)
|
|
{
|
|
if (token->attributes.Count() > 0)
|
|
{
|
|
tokenAtts.Add(token->name, atts.Count());
|
|
atts.Add(CreateAttributeInfo(token->attributes));
|
|
}
|
|
else
|
|
{
|
|
tokenAtts.Add(token->name, -1);
|
|
}
|
|
|
|
if (token->discard)
|
|
{
|
|
discardTokens.Add(token->name);
|
|
discardTokenCount++;
|
|
}
|
|
else
|
|
{
|
|
ParsingSymbol* tokenSymbol = jointPDA->symbolManager->GetGlobal()->GetSubSymbolByName(token->name);
|
|
tokenIds.Add(tokenSymbol, tokenIds.Count() + ParsingTable::UserTokenStart);
|
|
tokenCount++;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
find all rules
|
|
***********************************************************************/
|
|
FOREACH(Ptr<ParsingDefinitionRuleDefinition>, rule, definition->rules)
|
|
{
|
|
if (rule->attributes.Count() > 0)
|
|
{
|
|
ruleAtts.Add(rule->name, atts.Count());
|
|
atts.Add(CreateAttributeInfo(rule->attributes));
|
|
}
|
|
else
|
|
{
|
|
ruleAtts.Add(rule->name, -1);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
find all available states
|
|
***********************************************************************/
|
|
List<State*> stateIds;
|
|
vint availableStateCount = 0;
|
|
{
|
|
vint currentState = 0;
|
|
List<State*> scanningStates;
|
|
FOREACH(Ptr<RuleInfo>, ruleInfo, jointPDA->ruleInfos)
|
|
{
|
|
if (!scanningStates.Contains(ruleInfo->rootRuleStartState))
|
|
{
|
|
scanningStates.Add(ruleInfo->rootRuleStartState);
|
|
}
|
|
|
|
while (currentState < scanningStates.Count())
|
|
{
|
|
State* state = scanningStates[currentState++];
|
|
stateIds.Add(state);
|
|
|
|
FOREACH(Transition*, transition, state->transitions)
|
|
{
|
|
if (!scanningStates.Contains(transition->target))
|
|
{
|
|
scanningStates.Add(transition->target);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
availableStateCount = scanningStates.Count();
|
|
}
|
|
|
|
// there will be some states that is used in shift and reduce but it is not a reachable state
|
|
// so the state table will record all state
|
|
FOREACH(Ptr<State>, state, jointPDA->states)
|
|
{
|
|
if (!stateIds.Contains(state.Obj()))
|
|
{
|
|
stateIds.Add(state.Obj());
|
|
}
|
|
}
|
|
vint stateCount = stateIds.Count();
|
|
|
|
Ptr<ParsingTable> table = new ParsingTable(atts.Count(), typeAtts.Count(), treeFieldAtts.Count(), tokenCount, discardTokenCount, stateCount, definition->rules.Count());
|
|
|
|
/***********************************************************************
|
|
fill attribute infos
|
|
***********************************************************************/
|
|
FOREACH_INDEXER(Ptr<ParsingTable::AttributeInfoList>, att, index, atts)
|
|
{
|
|
table->SetAttributeInfo(index, att);
|
|
}
|
|
|
|
/***********************************************************************
|
|
fill tree type infos
|
|
***********************************************************************/
|
|
typedef Pair<WString, vint> TreeTypeAttsPair;
|
|
FOREACH_INDEXER(TreeTypeAttsPair, type, index, typeAtts)
|
|
{
|
|
table->SetTreeTypeInfo(index, ParsingTable::TreeTypeInfo(type.key, type.value));
|
|
}
|
|
|
|
/***********************************************************************
|
|
fill tree field infos
|
|
***********************************************************************/
|
|
typedef Pair<Pair<WString, WString>, vint> TreeFieldAttsPair;
|
|
FOREACH_INDEXER(TreeFieldAttsPair, field, index, treeFieldAtts)
|
|
{
|
|
table->SetTreeFieldInfo(index, ParsingTable::TreeFieldInfo(field.key.key, field.key.value, field.value));
|
|
}
|
|
|
|
/***********************************************************************
|
|
fill token infos
|
|
***********************************************************************/
|
|
FOREACH(ParsingSymbol*, symbol, tokenIds.Keys())
|
|
{
|
|
ParsingTable::TokenInfo info;
|
|
info.name = symbol->GetName();
|
|
info.regex = symbol->GetDescriptorString();
|
|
info.attributeIndex = tokenAtts[info.name];
|
|
|
|
vint id = tokenIds[symbol];
|
|
table->SetTokenInfo(id, info);
|
|
}
|
|
|
|
FOREACH_INDEXER(WString, name, i, discardTokens)
|
|
{
|
|
ParsingSymbol* symbol = jointPDA->symbolManager->GetGlobal()->GetSubSymbolByName(name);
|
|
|
|
ParsingTable::TokenInfo info;
|
|
info.name = symbol->GetName();
|
|
info.regex = symbol->GetDescriptorString();
|
|
info.attributeIndex = tokenAtts[info.name];
|
|
table->SetDiscardTokenInfo(i, info);
|
|
}
|
|
|
|
/***********************************************************************
|
|
fill rule infos
|
|
***********************************************************************/
|
|
FOREACH_INDEXER(ParsingDefinitionRuleDefinition*, rule, i, jointPDA->orderedRulesDefs)
|
|
{
|
|
Ptr<RuleInfo> pdaRuleInfo = jointPDA->ruleDefToInfoMap[rule];
|
|
ParsingTable::RuleInfo info;
|
|
info.name = rule->name;
|
|
info.type = TypeToString(rule->type.Obj());
|
|
info.rootStartState = stateIds.IndexOf(pdaRuleInfo->rootRuleStartState);
|
|
info.attributeIndex = ruleAtts[info.name];
|
|
|
|
if (Ptr<ParsingDefinitionPrimitiveType> classType = rule->type.Cast<ParsingDefinitionPrimitiveType>())
|
|
{
|
|
ParsingSymbol* ruleSymbol = manager->GetGlobal()->GetSubSymbolByName(rule->name);
|
|
ParsingSymbol* ruleType = ruleSymbol->GetDescriptorSymbol();
|
|
ParsingDefinitionClassDefinition* ruleTypeDef = manager->CacheGetClassDefinition(ruleType);
|
|
if (ruleTypeDef && ruleTypeDef->ambiguousType)
|
|
{
|
|
ParsingSymbol* ambiguousType = manager->CacheGetType(ruleTypeDef->ambiguousType.Obj(), ruleType->GetParentSymbol());
|
|
info.ambiguousType = GetTypeFullName(ambiguousType);
|
|
}
|
|
}
|
|
table->SetRuleInfo(i, info);
|
|
}
|
|
|
|
/***********************************************************************
|
|
fill state infos
|
|
***********************************************************************/
|
|
FOREACH_INDEXER(State*, state, i, stateIds)
|
|
{
|
|
ParsingTable::StateInfo info;
|
|
info.ruleName = state->ownerRule->name;
|
|
info.stateName = state->stateName;
|
|
info.stateExpression = state->stateExpression;
|
|
table->SetStateInfo(i, info);
|
|
}
|
|
|
|
/***********************************************************************
|
|
fill transition table
|
|
***********************************************************************/
|
|
FOREACH_INDEXER(State*, state, stateIndex, stateIds)
|
|
{
|
|
// if this state is not necessary, stop building the table
|
|
if (stateIndex >= availableStateCount) break;
|
|
|
|
FOREACH(Transition*, transition, state->transitions)
|
|
{
|
|
vint tokenIndex = -1;
|
|
switch (transition->transitionType)
|
|
{
|
|
case Transition::TokenBegin:
|
|
tokenIndex = ParsingTable::TokenBegin;
|
|
break;
|
|
case Transition::TokenFinish:
|
|
tokenIndex = ParsingTable::TokenFinish;
|
|
break;
|
|
case Transition::NormalReduce:
|
|
tokenIndex = ParsingTable::NormalReduce;
|
|
break;
|
|
case Transition::LeftRecursiveReduce:
|
|
tokenIndex = ParsingTable::LeftRecursiveReduce;
|
|
break;
|
|
case Transition::Symbol:
|
|
tokenIndex = tokenIds[transition->transitionSymbol];
|
|
break;
|
|
default:;
|
|
}
|
|
|
|
Ptr<ParsingTable::TransitionBag> bag = table->GetTransitionBag(stateIndex, tokenIndex);
|
|
if (!bag)
|
|
{
|
|
bag = new ParsingTable::TransitionBag;
|
|
table->SetTransitionBag(stateIndex, tokenIndex, bag);
|
|
}
|
|
|
|
Ptr<ParsingTable::TransitionItem> item = new ParsingTable::TransitionItem;
|
|
item->token = tokenIndex;
|
|
item->targetState = stateIds.IndexOf(transition->target);
|
|
bag->transitionItems.Add(item);
|
|
|
|
FOREACH(Ptr<Action>, action, transition->actions)
|
|
{
|
|
ParsingTable::Instruction ins;
|
|
switch (action->actionType)
|
|
{
|
|
case Action::Create:
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::Create;
|
|
ins.nameParameter = GetTypeNameForCreateInstruction(action->actionSource);
|
|
}
|
|
break;
|
|
case Action::Using:
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::Using;
|
|
}
|
|
break;
|
|
case Action::Assign:
|
|
{
|
|
if (action->actionSource->GetDescriptorSymbol()->GetType() == ParsingSymbol::ArrayType)
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::Item;
|
|
}
|
|
else
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::Assign;
|
|
}
|
|
ins.nameParameter = action->actionSource->GetName();
|
|
}
|
|
break;
|
|
case Action::Setter:
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::Setter;
|
|
ins.nameParameter = action->actionSource->GetName();
|
|
ins.value = action->actionTarget->GetName();
|
|
}
|
|
break;
|
|
case Action::Shift:
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::Shift;
|
|
ins.stateParameter = stateIds.IndexOf(action->shiftReduceSource);
|
|
}
|
|
break;
|
|
case Action::Reduce:
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::Reduce;
|
|
ins.stateParameter = stateIds.IndexOf(action->shiftReduceSource);
|
|
item->stackPattern.Add(ins.stateParameter);
|
|
}
|
|
break;
|
|
case Action::LeftRecursiveReduce:
|
|
{
|
|
ins.instructionType = ParsingTable::Instruction::LeftRecursiveReduce;
|
|
ins.stateParameter = stateIds.IndexOf(action->shiftReduceSource);
|
|
}
|
|
break;
|
|
}
|
|
ins.creatorRule = action->creatorRule->name;
|
|
item->instructions.Add(ins);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
check conflict and build look ahead table
|
|
***********************************************************************/
|
|
for (vint i = 0; i < table->GetStateCount(); i++)
|
|
{
|
|
for (vint j = 0; j < table->GetTokenCount(); j++)
|
|
{
|
|
Ptr<ParsingTable::TransitionBag> bag = table->GetTransitionBag(i, j);
|
|
if (bag)
|
|
{
|
|
CopyFrom(
|
|
bag->transitionItems,
|
|
From(bag->transitionItems)
|
|
.OrderBy([&](Ptr<ParsingTable::TransitionItem> t1, Ptr<ParsingTable::TransitionItem> t2)
|
|
{
|
|
// stable transition order
|
|
vint i1 = bag->transitionItems.IndexOf(t1.Obj());
|
|
vint i2 = bag->transitionItems.IndexOf(t2.Obj());
|
|
auto defaultOrder =
|
|
i1 < i2 ? ParsingTable::TransitionItem::CorrectOrder :
|
|
i1 > i2 ? ParsingTable::TransitionItem::WrongOrder :
|
|
ParsingTable::TransitionItem::SameOrder
|
|
;
|
|
return ParsingTable::TransitionItem::Compare(t1, t2, defaultOrder);
|
|
})
|
|
);
|
|
|
|
// build look ahead inside a transition
|
|
for (vint k1 = 0; k1 < bag->transitionItems.Count() - 1; k1++)
|
|
{
|
|
for (vint k2 = k1 + 1; k2 < bag->transitionItems.Count(); k2++)
|
|
{
|
|
Ptr<ParsingTable::TransitionItem> t1 = bag->transitionItems[k1];
|
|
Ptr<ParsingTable::TransitionItem> t2 = bag->transitionItems[k2];
|
|
GenerateLookAhead(table, stateIds, i, j, t1, t2, enableAmbiguity, errors);
|
|
}
|
|
}
|
|
|
|
// build look ahead between this transition and reduce transitions
|
|
for (vint t = ParsingTable::NormalReduce; t <= ParsingTable::LeftRecursiveReduce && t < j; t++)
|
|
{
|
|
if (Ptr<ParsingTable::TransitionBag> reduceBag = table->GetTransitionBag(i, t))
|
|
{
|
|
for (vint k1 = 0; k1 < reduceBag->transitionItems.Count(); k1++)
|
|
{
|
|
for (vint k2 = 0; k2 < bag->transitionItems.Count(); k2++)
|
|
{
|
|
Ptr<ParsingTable::TransitionItem> t1 = reduceBag->transitionItems[k1];
|
|
Ptr<ParsingTable::TransitionItem> t2 = bag->transitionItems[k2];
|
|
GenerateLookAhead(table, stateIds, i, j, t1, t2, enableAmbiguity, errors);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
initialize table
|
|
***********************************************************************/
|
|
if (errors.Count() > 0)
|
|
{
|
|
table->SetAmbiguity(true);
|
|
}
|
|
table->Initialize();
|
|
return table;
|
|
}
|
|
|
|
Ptr<tabling::ParsingTable> GenerateTable(Ptr<definitions::ParsingDefinition> definition, bool enableAmbiguity, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
errors.Clear();
|
|
ParsingSymbolManager symbolManager;
|
|
ValidateDefinition(definition, &symbolManager, errors);
|
|
if(errors.Count()==0)
|
|
{
|
|
Ptr<Automaton> epsilonPDA=CreateEpsilonPDA(definition, &symbolManager);
|
|
Ptr<Automaton> nondeterministicPDA=CreateNondeterministicPDAFromEpsilonPDA(epsilonPDA);
|
|
Ptr<Automaton> jointPDA=CreateJointPDAFromNondeterministicPDA(nondeterministicPDA);
|
|
CompactJointPDA(jointPDA);
|
|
MarkLeftRecursiveInJointPDA(jointPDA, errors);
|
|
if(errors.Count()==0)
|
|
{
|
|
Ptr<ParsingTable> table=GenerateTableFromPDA(definition, &symbolManager, jointPDA, enableAmbiguity, errors);
|
|
if(enableAmbiguity || errors.Count()==0)
|
|
{
|
|
return table;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON_JPDA.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
|
|
namespace analyzing
|
|
{
|
|
/***********************************************************************
|
|
CreateJointPDAFromNondeterministicPDA
|
|
***********************************************************************/
|
|
|
|
Ptr<Automaton> CreateJointPDAFromNondeterministicPDA(Ptr<Automaton> nondeterministicPDA)
|
|
{
|
|
Ptr<Automaton> automaton=new Automaton(nondeterministicPDA->symbolManager);
|
|
|
|
// build rule info data
|
|
Dictionary<WString, ParsingDefinitionRuleDefinition*> ruleMap;
|
|
Dictionary<State*, State*> oldNewStateMap;
|
|
FOREACH(ParsingDefinitionRuleDefinition*, rule, nondeterministicPDA->orderedRulesDefs)
|
|
{
|
|
// build new rule info
|
|
Ptr<RuleInfo> ruleInfo=nondeterministicPDA->ruleDefToInfoMap[rule];
|
|
Ptr<RuleInfo> newRuleInfo=new RuleInfo;
|
|
automaton->AddRuleInfo(rule, newRuleInfo);
|
|
ruleMap.Add(rule->name, rule);
|
|
|
|
newRuleInfo->rootRuleStartState=automaton->RootRuleStartState(rule);
|
|
newRuleInfo->rootRuleEndState=automaton->RootRuleEndState(rule);
|
|
newRuleInfo->startState=automaton->RuleStartState(rule);
|
|
|
|
oldNewStateMap.Add(ruleInfo->rootRuleStartState, newRuleInfo->rootRuleStartState);
|
|
oldNewStateMap.Add(ruleInfo->rootRuleEndState, newRuleInfo->rootRuleEndState);
|
|
oldNewStateMap.Add(ruleInfo->startState, newRuleInfo->startState);
|
|
|
|
newRuleInfo->rootRuleStartState->stateExpression=ruleInfo->rootRuleStartState->stateExpression;
|
|
newRuleInfo->rootRuleEndState->stateExpression=ruleInfo->rootRuleEndState->stateExpression;
|
|
newRuleInfo->startState->stateExpression=ruleInfo->startState->stateExpression;
|
|
}
|
|
|
|
FOREACH(Ptr<State>, oldState, nondeterministicPDA->states)
|
|
{
|
|
if((oldState->inputs.Count()>0 || oldState->transitions.Count()>0) && !oldNewStateMap.Keys().Contains(oldState.Obj()))
|
|
{
|
|
State* newState=automaton->CopyState(oldState.Obj());
|
|
oldNewStateMap.Add(oldState.Obj(), newState);
|
|
newState->stateExpression=oldState->stateExpression;
|
|
}
|
|
}
|
|
|
|
// create transitions
|
|
FOREACH(ParsingDefinitionRuleDefinition*, rule, nondeterministicPDA->orderedRulesDefs)
|
|
{
|
|
Ptr<RuleInfo> ruleInfo=nondeterministicPDA->ruleDefToInfoMap[rule];
|
|
Ptr<RuleInfo> newRuleInfo=automaton->ruleDefToInfoMap[rule];
|
|
|
|
// complete new rule info
|
|
FOREACH(State*, endState, ruleInfo->endStates)
|
|
{
|
|
newRuleInfo->endStates.Add(oldNewStateMap[endState]);
|
|
}
|
|
|
|
// create joint transitions according to old automaton
|
|
List<State*> scanningStates;
|
|
vint currentStateIndex=0;
|
|
scanningStates.Add(ruleInfo->rootRuleStartState);
|
|
|
|
while(currentStateIndex<scanningStates.Count())
|
|
{
|
|
State* currentOldState=scanningStates[currentStateIndex++];
|
|
State* currentNewState=oldNewStateMap[currentOldState];
|
|
FOREACH(Transition*, oldTransition, currentOldState->transitions)
|
|
{
|
|
State* oldSource=oldTransition->source;
|
|
State* oldTarget=oldTransition->target;
|
|
State* newSource=oldNewStateMap[oldSource];
|
|
State* newTarget=oldNewStateMap[oldTarget];
|
|
|
|
if(!scanningStates.Contains(oldSource)) scanningStates.Add(oldSource);
|
|
if(!scanningStates.Contains(oldTarget)) scanningStates.Add(oldTarget);
|
|
|
|
if(oldTransition->transitionType==Transition::Symbol && oldTransition->transitionSymbol->GetType()==ParsingSymbol::RuleDef)
|
|
{
|
|
// if this is a rule transition, create
|
|
// source -> ruleStart
|
|
// ruleEnd[] -> target
|
|
ParsingDefinitionRuleDefinition* rule=ruleMap[oldTransition->transitionSymbol->GetName()];
|
|
Ptr<RuleInfo> oldRuleInfo=nondeterministicPDA->ruleDefToInfoMap[rule];
|
|
|
|
{
|
|
Transition* shiftTransition=automaton->Epsilon(newSource, oldNewStateMap[oldRuleInfo->startState]);
|
|
Ptr<Action> action=new Action;
|
|
action->actionType=Action::Shift;
|
|
action->shiftReduceSource=newSource;
|
|
action->shiftReduceTarget=newTarget;
|
|
action->creatorRule=shiftTransition->source->ownerRule;
|
|
shiftTransition->actions.Add(action);
|
|
}
|
|
|
|
FOREACH(State*, oldEndState, oldRuleInfo->endStates)
|
|
{
|
|
Transition* reduceTransition=automaton->NormalReduce(oldNewStateMap[oldEndState], newTarget);
|
|
Ptr<Action> action=new Action;
|
|
action->actionType=Action::Reduce;
|
|
action->shiftReduceSource=newSource;
|
|
action->shiftReduceTarget=newTarget;
|
|
action->creatorRule=reduceTransition->source->ownerRule;
|
|
reduceTransition->actions.Add(action);
|
|
CopyFrom(reduceTransition->actions, oldTransition->actions, true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// if not, just copy
|
|
Transition* newTransition=automaton->CopyTransition(newSource, newTarget, oldTransition);
|
|
CopyFrom(newTransition->actions, oldTransition->actions);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return automaton;
|
|
}
|
|
|
|
/***********************************************************************
|
|
CompactJointPDA
|
|
***********************************************************************/
|
|
|
|
// closure function for searching shift-reduce-compact transition
|
|
ClosureItem::SearchResult ShiftReduceCompactClosure(Transition* transition)
|
|
{
|
|
return
|
|
transition->stackOperationType!=Transition::None?ClosureItem::Blocked:
|
|
transition->transitionType!=Transition::Epsilon?ClosureItem::Hit:
|
|
ClosureItem::Continue;
|
|
}
|
|
|
|
void CompactJointPDA(Ptr<Automaton> jointPDA)
|
|
{
|
|
FOREACH(Ptr<State>, state, jointPDA->states)
|
|
{
|
|
State* currentState=state.Obj();
|
|
|
|
// search for epsilon closure
|
|
List<ClosureItem> closure;
|
|
SearchClosure(&ShiftReduceCompactClosure, currentState, closure);
|
|
|
|
FOREACH(ClosureItem, closureItem, closure)
|
|
{
|
|
Transition* lastTransition=closureItem.transitions->Get(closureItem.transitions->Count()-1);
|
|
Transition::StackOperationType stackOperationType=Transition::None;
|
|
Transition::TransitionType transitionType=lastTransition->transitionType;
|
|
|
|
if(closureItem.cycle && lastTransition->transitionType==Transition::Epsilon)
|
|
{
|
|
bool containsShift=false;
|
|
bool containsReduce=false;
|
|
FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj())
|
|
{
|
|
FOREACH(Ptr<Action>, action, pathTransition->actions)
|
|
{
|
|
if(action->actionType==Action::Shift) containsShift=true;
|
|
if(action->actionType==Action::Reduce) containsReduce=true;
|
|
}
|
|
}
|
|
if(containsShift && !containsReduce)
|
|
{
|
|
// a left recursive compacted shift transition is found
|
|
// if the left recursive state is not the current state
|
|
// that means this transition path fall into other left recursive state
|
|
// e.g.
|
|
// Term = Factor | Term (here is a left recursion) * Factor
|
|
// Exp = Term (this rule symbol transition will fall into Term's left recursive state) ...
|
|
// if such a case happened, this transition path will be simply discarded
|
|
if(closureItem.state==currentState)
|
|
{
|
|
stackOperationType=Transition::LeftRecursive;
|
|
}
|
|
}
|
|
else if(!containsShift && containsReduce)
|
|
{
|
|
// a right recursive compacted reduce transition is found
|
|
// if this state will receive $TokenFinish, then the stack pattern number can be infinite
|
|
// e.g. for right recursive expression "a b c" == "(a (b c))"
|
|
// when trying to do a transition by $TokenFinish
|
|
// "a b" should reduce once
|
|
// "a b c" should reduce twice
|
|
// because that a reduce is not considered a virtual token, so this is not going to be happened
|
|
}
|
|
}
|
|
else if(closureItem.transitions->Count()>1)
|
|
{
|
|
// in joint PDA, only shift and reduce transitions are epsilon transition
|
|
// if there are more than one transition in a path, then there should be shift or reduce transitions in the path
|
|
stackOperationType=Transition::ShiftReduceCompacted;
|
|
}
|
|
|
|
if(stackOperationType!=Transition::None)
|
|
{
|
|
// build shift-reduce-compacted transition to the target state of the path
|
|
Transition* transition=jointPDA->CopyTransition(currentState, lastTransition->target, lastTransition);
|
|
transition->transitionType=transitionType;
|
|
transition->stackOperationType=stackOperationType;
|
|
|
|
// there will be <shift* token>, <reduce* token> or <reduce* shift* token>
|
|
// but there will not be something like <reduce* shift* reduce* token>
|
|
// so we can append stackPattern safely
|
|
FOREACH(Transition*, pathTransition, *closureItem.transitions.Obj())
|
|
{
|
|
CopyFrom(transition->actions, pathTransition->actions, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// delete unnecessary transactions
|
|
for(vint i=jointPDA->transitions.Count()-1;i>=0;i--)
|
|
{
|
|
Transition* transition=jointPDA->transitions[i].Obj();
|
|
if(transition->stackOperationType==Transition::None && transition->transitionType==Transition::Epsilon)
|
|
{
|
|
jointPDA->DeleteTransition(transition);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
MarkLeftRecursiveInJointPDA
|
|
***********************************************************************/
|
|
|
|
void MarkLeftRecursiveInJointPDA(Ptr<Automaton> jointPDA, collections::List<Ptr<ParsingError>>& errors)
|
|
{
|
|
vint errorCount=errors.Count();
|
|
// record all left recursive shifts and delete all left recursive epsilon transition
|
|
SortedList<Pair<State*, State*>> leftRecursiveShifts;
|
|
FOREACH(Ptr<State>, state, jointPDA->states)
|
|
{
|
|
for(vint i=state->transitions.Count()-1;i>=0;i--)
|
|
{
|
|
Transition* transition=state->transitions[i];
|
|
if(transition->stackOperationType==Transition::LeftRecursive)
|
|
{
|
|
Ptr<Action> shiftAction;
|
|
FOREACH(Ptr<Action>, action, transition->actions)
|
|
{
|
|
if(action->actionType==Action::Shift)
|
|
{
|
|
if(shiftAction)
|
|
{
|
|
errors.Add(new ParsingError(state->ownerRule, L"Indirect left recursive transition in rule \""+state->ownerRule->name+L"\" is not allowed."));
|
|
goto FOUND_INDIRECT_LEFT_RECURSIVE_TRANSITION;
|
|
}
|
|
else
|
|
{
|
|
shiftAction=action;
|
|
}
|
|
}
|
|
}
|
|
if(shiftAction)
|
|
{
|
|
leftRecursiveShifts.Add(Pair<State*, State*>(shiftAction->shiftReduceSource, shiftAction->shiftReduceTarget));
|
|
}
|
|
FOUND_INDIRECT_LEFT_RECURSIVE_TRANSITION:
|
|
jointPDA->DeleteTransition(transition);
|
|
}
|
|
}
|
|
}
|
|
if(errorCount!=errors.Count())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// change all reduce actions whose (shiftReduceSource, shiftReduceTarget) is recorded in leftRecursiveShifts to left-recursive-reduce
|
|
// when a reduce is converted to a left-recursive-reduce, the corresponding state in stackPattern should be removed
|
|
// so this will keep count(Reduce) == count(stackPattern)
|
|
FOREACH(Ptr<State>, state, jointPDA->states)
|
|
{
|
|
FOREACH(Transition*, transition, state->transitions)
|
|
{
|
|
for(vint i=transition->actions.Count()-1;i>=0;i--)
|
|
{
|
|
Ptr<Action> action=transition->actions[i];
|
|
if(action->actionType==Action::Reduce)
|
|
{
|
|
Pair<State*, State*> shift(action->shiftReduceSource, action->shiftReduceTarget);
|
|
if(leftRecursiveShifts.Contains(shift))
|
|
{
|
|
// check if this is a normal reduce transition, and change it to a left recursive reduce transition.
|
|
if (transition->transitionType == Transition::NormalReduce)
|
|
{
|
|
transition->transitionType = Transition::LeftRecursiveReduce;
|
|
// need to create a new action because in the previous phrases, these action object are shared and treated as read only
|
|
Ptr<Action> newAction=new Action;
|
|
newAction->actionType=Action::LeftRecursiveReduce;
|
|
newAction->actionSource=action->actionSource;
|
|
newAction->actionTarget=action->actionTarget;
|
|
newAction->creatorRule=action->creatorRule;
|
|
newAction->shiftReduceSource=action->shiftReduceSource;
|
|
newAction->shiftReduceTarget=action->shiftReduceTarget;
|
|
newAction->creatorRule=shift.key->ownerRule;
|
|
transition->actions[i]=newAction;
|
|
}
|
|
else
|
|
{
|
|
errors.Add(new ParsingError(state->ownerRule, L"Left recursive reduce action in non-normal-reduce found in rule \""+state->ownerRule->name+L"\" is not allowed."));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// delete complicated transitions
|
|
FOREACH(Ptr<State>, state, jointPDA->states)
|
|
{
|
|
while(true)
|
|
{
|
|
bool deleted=false;
|
|
FOREACH(Transition*, t1, state->transitions)
|
|
FOREACH(Transition*, t2, state->transitions)
|
|
if(t1!=t2)
|
|
{
|
|
if(Transition::IsEquivalent(t1, t2, true))
|
|
{
|
|
jointPDA->DeleteTransition(t2);
|
|
deleted=true;
|
|
goto TRANSITION_DELETED;
|
|
}
|
|
}
|
|
TRANSITION_DELETED:
|
|
if(!deleted) break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON_MERGESTATES.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
DeleteUnnecessaryStates
|
|
***********************************************************************/
|
|
|
|
void DeleteUnnecessaryStates(Ptr<Automaton> automaton, Ptr<RuleInfo> ruleInfo, List<State*>& newStates)
|
|
{
|
|
// delete all states that are not reachable to the end state
|
|
while(true)
|
|
{
|
|
// find a non-end state without out transitions
|
|
vint deleteCount=0;
|
|
for(vint i=newStates.Count()-1;i>=0;i--)
|
|
{
|
|
State* newState=newStates[i];
|
|
if(newState->transitions.Count()==0)
|
|
{
|
|
if(newState!=ruleInfo->rootRuleEndState && !newState->endState)
|
|
{
|
|
automaton->DeleteState(newState);
|
|
newStates.RemoveAt(i);
|
|
}
|
|
}
|
|
}
|
|
if(deleteCount==0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
IsMergableCandidate
|
|
***********************************************************************/
|
|
|
|
bool IsMergableCandidate(State* state, Ptr<RuleInfo> ruleInfo)
|
|
{
|
|
if(state==ruleInfo->rootRuleStartState || state==ruleInfo->rootRuleEndState || state==ruleInfo->startState)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
RearrangeState
|
|
***********************************************************************/
|
|
|
|
#define COMPARE_SYMBOL(S1, S2)\
|
|
if (S1 && S2)\
|
|
{\
|
|
if (S1->GetType() < S2->GetType()) return -1;\
|
|
if (S1->GetType() > S2->GetType()) return 1;\
|
|
if (S1->GetName() < S2->GetName()) return -1;\
|
|
if (S1->GetName() > S2->GetName()) return 1;\
|
|
}\
|
|
else if (S1)\
|
|
{\
|
|
return 1;\
|
|
}\
|
|
else if (S2)\
|
|
{\
|
|
return -1;\
|
|
}\
|
|
|
|
vint CompareTransitionForRearranging(Transition* t1, Transition* t2)
|
|
{
|
|
if (t1->transitionType < t2->transitionType) return -1;
|
|
if (t1->transitionType > t2->transitionType) return 1;
|
|
COMPARE_SYMBOL(t1->transitionSymbol, t2->transitionSymbol);
|
|
return 0;
|
|
}
|
|
|
|
vint CompareActionForRearranging(Ptr<Action> a1, Ptr<Action> a2)
|
|
{
|
|
if(a1->actionType<a2->actionType) return -1;
|
|
if(a1->actionType>a2->actionType) return 1;
|
|
COMPARE_SYMBOL(a1->actionSource, a2->actionSource);
|
|
COMPARE_SYMBOL(a1->actionTarget, a2->actionTarget);
|
|
return 0;
|
|
}
|
|
|
|
#undef COMPARE_SYMBOL
|
|
|
|
void RearrangeState(State* state, SortedList<State*>& stateContentSorted)
|
|
{
|
|
if(!stateContentSorted.Contains(state))
|
|
{
|
|
FOREACH(Transition*, transition, state->transitions)
|
|
{
|
|
CopyFrom(transition->actions, From(transition->actions).OrderBy(&CompareActionForRearranging));
|
|
}
|
|
CopyFrom(state->transitions, From(state->transitions).OrderBy(&CompareTransitionForRearranging));
|
|
stateContentSorted.Add(state);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
MoveActionsForMergingState
|
|
***********************************************************************/
|
|
|
|
void MoveActionsForMergingState(Transition* transition)
|
|
{
|
|
// collect all movable actions
|
|
List<Ptr<Action>> movableActions;
|
|
for(vint i=transition->actions.Count()-1;i>=0;i--)
|
|
{
|
|
switch(transition->actions[i]->actionType)
|
|
{
|
|
// Using and Assign actions are not movable
|
|
case Action::Using:
|
|
case Action::Assign:
|
|
break;
|
|
default:
|
|
movableActions.Add(transition->actions[i]);
|
|
transition->actions.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
// copy all movable actions
|
|
FOREACH(Transition*, t, transition->source->inputs)
|
|
{
|
|
CopyFrom(t->actions, movableActions, true);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
IsMergableBecause(Transitions|Input)
|
|
***********************************************************************/
|
|
|
|
bool IsMergableBecauseTransitions(State* state1, State* state2)
|
|
{
|
|
if(state1->transitions.Count()!=state2->transitions.Count()) return false;
|
|
if(state1->transitions.Count()==1 && state2->transitions.Count()==1)
|
|
{
|
|
Transition* t1=state1->transitions[0];
|
|
Transition* t2=state2->transitions[0];
|
|
if(CompareTransitionForRearranging(t1, t2)==0 && !Transition::IsEquivalent(t1, t2, false) && t1->target==t2->target)
|
|
{
|
|
MoveActionsForMergingState(t1);
|
|
MoveActionsForMergingState(t2);
|
|
}
|
|
}
|
|
for(vint i=0;i<state1->transitions.Count();i++)
|
|
{
|
|
Transition* t1=state1->transitions[i];
|
|
Transition* t2=state2->transitions[i];
|
|
if(!Transition::IsEquivalent(t1, t2, false) || t1->target!=t2->target)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool IsMergableBecauseInputs(State* state1, State* state2)
|
|
{
|
|
if(state1->inputs.Count()!=state2->inputs.Count()) return false;
|
|
for(vint i=0;i<state1->inputs.Count();i++)
|
|
{
|
|
Transition* t1=state1->inputs[i];
|
|
Transition* t2=state2->inputs[i];
|
|
if(!Transition::IsEquivalent(t1, t2, false) || t1->source!=t2->source)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
MergeState2ToState1Because(Transitions|Input)
|
|
***********************************************************************/
|
|
|
|
void MergeState2ToState1BecauseTransitions(Ptr<Automaton> automaton, State* state1, State* state2)
|
|
{
|
|
// modify state1's expression
|
|
state1->stateExpression+=L"\r\n"+state2->stateExpression;
|
|
|
|
// retarget state2's input to state1
|
|
for(vint i=state2->inputs.Count()-1;i>=0;i--)
|
|
{
|
|
Transition* t2=state2->inputs[i];
|
|
bool add=true;
|
|
FOREACH(Transition*, t1, state1->inputs)
|
|
{
|
|
if(Transition::IsEquivalent(t1, t2, false) && t1->source==t2->source)
|
|
{
|
|
add=false;
|
|
break;
|
|
}
|
|
}
|
|
if(add)
|
|
{
|
|
state1->inputs.Add(t2);
|
|
t2->target=state1;
|
|
state2->inputs.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
automaton->DeleteState(state2);
|
|
}
|
|
|
|
void MergeState2ToState1BecauseInputs(Ptr<Automaton> automaton, State* state1, State* state2)
|
|
{
|
|
// modify state1's expression
|
|
state1->stateExpression+=L"\r\n"+state2->stateExpression;
|
|
|
|
// retarget state2's input to state1
|
|
for(vint i=state2->transitions.Count()-1;i>=0;i--)
|
|
{
|
|
Transition* t2=state2->transitions[i];
|
|
bool add=true;
|
|
FOREACH(Transition*, t1, state1->transitions)
|
|
{
|
|
if(Transition::IsEquivalent(t1, t2, false) && t1->target==t2->target)
|
|
{
|
|
add=false;
|
|
break;
|
|
}
|
|
}
|
|
if(add)
|
|
{
|
|
state1->transitions.Add(t2);
|
|
t2->source=state1;
|
|
state2->transitions.RemoveAt(i);
|
|
}
|
|
}
|
|
|
|
automaton->DeleteState(state2);
|
|
}
|
|
|
|
/***********************************************************************
|
|
MergeStates
|
|
***********************************************************************/
|
|
|
|
void MergeStates(Ptr<Automaton> automaton, Ptr<RuleInfo> ruleInfo, List<State*>& newStates)
|
|
{
|
|
SortedList<State*> stateContentSorted;
|
|
while(true)
|
|
{
|
|
for(vint i=0;i<newStates.Count();i++)
|
|
{
|
|
State* state1=newStates[i];
|
|
if(IsMergableCandidate(state1, ruleInfo))
|
|
{
|
|
for(vint j=i+1;j<newStates.Count();j++)
|
|
{
|
|
State* state2=newStates[j];
|
|
if(state1!=state2 && IsMergableCandidate(state2, ruleInfo))
|
|
{
|
|
RearrangeState(state1, stateContentSorted);
|
|
RearrangeState(state2, stateContentSorted);
|
|
if(IsMergableBecauseTransitions(state1, state2))
|
|
{
|
|
MergeState2ToState1BecauseTransitions(automaton, state1, state2);
|
|
newStates.RemoveAt(j);
|
|
goto MERGED_STATES_PAIR;
|
|
}
|
|
else if(IsMergableBecauseInputs(state1, state2))
|
|
{
|
|
MergeState2ToState1BecauseInputs(automaton, state1, state2);
|
|
newStates.RemoveAt(j);
|
|
goto MERGED_STATES_PAIR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
MERGED_STATES_PAIR:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGAUTOMATON_NPDA.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
using namespace collections;
|
|
using namespace definitions;
|
|
|
|
namespace analyzing
|
|
{
|
|
|
|
/***********************************************************************
|
|
CreateNondeterministicPDAFromEpsilonPDA
|
|
***********************************************************************/
|
|
|
|
Ptr<Automaton> CreateNondeterministicPDAFromEpsilonPDA(Ptr<Automaton> epsilonPDA)
|
|
{
|
|
Ptr<Automaton> automaton=new Automaton(epsilonPDA->symbolManager);
|
|
FOREACH(ParsingDefinitionRuleDefinition*, rule, epsilonPDA->orderedRulesDefs)
|
|
{
|
|
// build new rule info
|
|
Ptr<RuleInfo> ruleInfo=epsilonPDA->ruleDefToInfoMap[rule];
|
|
Ptr<RuleInfo> newRuleInfo=new RuleInfo;
|
|
automaton->AddRuleInfo(rule, newRuleInfo);
|
|
|
|
newRuleInfo->rootRuleStartState=automaton->RootRuleStartState(rule);
|
|
newRuleInfo->rootRuleEndState=automaton->RootRuleEndState(rule);
|
|
newRuleInfo->startState=automaton->RuleStartState(rule);
|
|
|
|
// build state mapping and state visiting tracking
|
|
Dictionary<State*, State*> oldNewStateMap;
|
|
List<State*> scanningStates;
|
|
vint currentStateIndex=0;
|
|
oldNewStateMap.Add(ruleInfo->rootRuleStartState, newRuleInfo->rootRuleStartState);
|
|
oldNewStateMap.Add(ruleInfo->rootRuleEndState, newRuleInfo->rootRuleEndState);
|
|
oldNewStateMap.Add(ruleInfo->startState, newRuleInfo->startState);
|
|
// begin with a root rule state state
|
|
scanningStates.Add(ruleInfo->rootRuleStartState);
|
|
// remove epsilon transitions
|
|
RemoveEpsilonTransitions(oldNewStateMap, scanningStates, automaton);
|
|
|
|
// stable state orders
|
|
List<State*> newStates;
|
|
CopyFrom(
|
|
newStates,
|
|
From(epsilonPDA->states)
|
|
.Where([&](Ptr<State> s) {return oldNewStateMap.Keys().Contains(s.Obj()); })
|
|
.Select([&](Ptr<State> s) { return oldNewStateMap[s.Obj()]; })
|
|
);
|
|
DeleteUnnecessaryStates(automaton, newRuleInfo, newStates);
|
|
MergeStates(automaton, newRuleInfo, newStates);
|
|
|
|
// there should be at east one and only one transition that is TokenBegin from rootRuleStartState
|
|
// update the startState because the startState may be deleted
|
|
newRuleInfo->startState=newRuleInfo->rootRuleStartState->transitions[0]->target;
|
|
|
|
// record end states
|
|
FOREACH(State*, state, newStates)
|
|
{
|
|
if(state->endState)
|
|
{
|
|
newRuleInfo->endStates.Add(state);
|
|
}
|
|
}
|
|
}
|
|
return automaton;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGDEFINITIONS.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
using namespace collections;
|
|
|
|
namespace parsing
|
|
{
|
|
namespace definitions
|
|
{
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionType(Visitor)
|
|
***********************************************************************/
|
|
|
|
void ParsingDefinitionPrimitiveType::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionTokenType::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionSubType::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionArrayType::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionTypeDefinition(Visitor)
|
|
***********************************************************************/
|
|
|
|
void ParsingDefinitionClassMemberDefinition::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionClassDefinition::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionEnumMemberDefinition::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionEnumDefinition::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionGrammar(Visitor)
|
|
***********************************************************************/
|
|
|
|
void ParsingDefinitionPrimitiveGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionTextGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionSequenceGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionAlternativeGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionLoopGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionOptionalGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionCreateGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionAssignGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionUseGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void ParsingDefinitionSetterGrammar::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionTypeWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionAttributeWriter::ParsingDefinitionAttributeWriter(const WString& name)
|
|
{
|
|
attribute=new ParsingDefinitionAttribute;
|
|
attribute->name=name;
|
|
}
|
|
|
|
ParsingDefinitionAttributeWriter::ParsingDefinitionAttributeWriter(const ParsingDefinitionAttributeWriter& attributeWriter)
|
|
{
|
|
attribute=attributeWriter.attribute;
|
|
}
|
|
|
|
ParsingDefinitionAttributeWriter& ParsingDefinitionAttributeWriter::Argument(const WString& argument)
|
|
{
|
|
attribute->arguments.Add(argument);
|
|
return *this;
|
|
}
|
|
|
|
Ptr<ParsingDefinitionAttribute> ParsingDefinitionAttributeWriter::Attribute()const
|
|
{
|
|
return attribute;
|
|
}
|
|
|
|
ParsingDefinitionAttributeWriter Attribute(const WString& name)
|
|
{
|
|
return ParsingDefinitionAttributeWriter(name);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionTypeWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(Ptr<ParsingDefinitionType> internalType)
|
|
{
|
|
type=internalType;
|
|
}
|
|
|
|
ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(const ParsingDefinitionTypeWriter& typeWriter)
|
|
{
|
|
type=typeWriter.type;
|
|
}
|
|
|
|
ParsingDefinitionTypeWriter::ParsingDefinitionTypeWriter(const WString& name)
|
|
{
|
|
Ptr<ParsingDefinitionPrimitiveType> primitiveType=new ParsingDefinitionPrimitiveType;
|
|
primitiveType->name=name;
|
|
type=primitiveType;
|
|
}
|
|
|
|
ParsingDefinitionTypeWriter ParsingDefinitionTypeWriter::Sub(const WString& subTypeName)const
|
|
{
|
|
Ptr<ParsingDefinitionSubType> subType=new ParsingDefinitionSubType;
|
|
subType->parentType=type;
|
|
subType->subTypeName=subTypeName;
|
|
return ParsingDefinitionTypeWriter(subType);
|
|
}
|
|
|
|
ParsingDefinitionTypeWriter ParsingDefinitionTypeWriter::Array()const
|
|
{
|
|
Ptr<ParsingDefinitionArrayType> arrayType=new ParsingDefinitionArrayType;
|
|
arrayType->elementType=type;
|
|
return ParsingDefinitionTypeWriter(arrayType);
|
|
}
|
|
|
|
Ptr<ParsingDefinitionType> ParsingDefinitionTypeWriter::Type()const
|
|
{
|
|
return type;
|
|
}
|
|
|
|
ParsingDefinitionTypeWriter Type(const WString& name)
|
|
{
|
|
return ParsingDefinitionTypeWriter(name);
|
|
}
|
|
|
|
ParsingDefinitionTypeWriter TokenType()
|
|
{
|
|
Ptr<ParsingDefinitionTokenType> type=new ParsingDefinitionTokenType;
|
|
return ParsingDefinitionTypeWriter(type);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionClassDefinitionWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionClassDefinitionWriter::ParsingDefinitionClassDefinitionWriter(const WString& name)
|
|
{
|
|
definition=new ParsingDefinitionClassDefinition;
|
|
definition->name=name;
|
|
currentDefinition=definition;
|
|
}
|
|
|
|
ParsingDefinitionClassDefinitionWriter::ParsingDefinitionClassDefinitionWriter(const WString& name, const ParsingDefinitionTypeWriter& parentType)
|
|
{
|
|
definition=new ParsingDefinitionClassDefinition;
|
|
definition->name=name;
|
|
definition->parentType=parentType.Type();
|
|
currentDefinition=definition;
|
|
}
|
|
|
|
ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::AmbiguousType(const ParsingDefinitionTypeWriter& ambiguousType)
|
|
{
|
|
definition->ambiguousType=ambiguousType.Type();
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::Member(const WString& name, const ParsingDefinitionTypeWriter& type, const WString& unescapingFunction)
|
|
{
|
|
Ptr<ParsingDefinitionClassMemberDefinition> member=new ParsingDefinitionClassMemberDefinition;
|
|
member->name=name;
|
|
member->type=type.Type();
|
|
member->unescapingFunction=unescapingFunction;
|
|
definition->members.Add(member);
|
|
currentDefinition=member;
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::SubType(const ParsingDefinitionTypeDefinitionWriter& type)
|
|
{
|
|
definition->subTypes.Add(type.Definition());
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionClassDefinitionWriter& ParsingDefinitionClassDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute)
|
|
{
|
|
currentDefinition->attributes.Add(attribute.Attribute());
|
|
return *this;
|
|
}
|
|
|
|
Ptr<ParsingDefinitionTypeDefinition> ParsingDefinitionClassDefinitionWriter::Definition()const
|
|
{
|
|
return definition;
|
|
}
|
|
|
|
ParsingDefinitionClassDefinitionWriter Class(const WString& name)
|
|
{
|
|
return ParsingDefinitionClassDefinitionWriter(name);
|
|
}
|
|
|
|
ParsingDefinitionClassDefinitionWriter Class(const WString& name, const ParsingDefinitionTypeWriter& parentType)
|
|
{
|
|
return ParsingDefinitionClassDefinitionWriter(name, parentType);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionEnumDefinitionWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionEnumDefinitionWriter::ParsingDefinitionEnumDefinitionWriter(const WString& name)
|
|
{
|
|
definition=new ParsingDefinitionEnumDefinition;
|
|
definition->name=name;
|
|
currentDefinition=definition;
|
|
}
|
|
|
|
ParsingDefinitionEnumDefinitionWriter& ParsingDefinitionEnumDefinitionWriter::Member(const WString& name)
|
|
{
|
|
Ptr<ParsingDefinitionEnumMemberDefinition> member=new ParsingDefinitionEnumMemberDefinition;
|
|
member->name=name;
|
|
definition->members.Add(member);
|
|
currentDefinition=member;
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionEnumDefinitionWriter& ParsingDefinitionEnumDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute)
|
|
{
|
|
currentDefinition->attributes.Add(attribute.Attribute());
|
|
return *this;
|
|
}
|
|
|
|
Ptr<ParsingDefinitionTypeDefinition> ParsingDefinitionEnumDefinitionWriter::Definition()const
|
|
{
|
|
return definition;
|
|
}
|
|
|
|
ParsingDefinitionEnumDefinitionWriter Enum(const WString& name)
|
|
{
|
|
return ParsingDefinitionEnumDefinitionWriter(name);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionGrammarWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionGrammarWriter::ParsingDefinitionGrammarWriter(Ptr<ParsingDefinitionGrammar> internalGrammar)
|
|
{
|
|
grammar=internalGrammar;
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter::ParsingDefinitionGrammarWriter(const ParsingDefinitionGrammarWriter& grammarWriter)
|
|
{
|
|
grammar=grammarWriter.grammar;
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator+(const ParsingDefinitionGrammarWriter& next)const
|
|
{
|
|
Ptr<ParsingDefinitionSequenceGrammar> sequence=new ParsingDefinitionSequenceGrammar;
|
|
sequence->first=grammar;
|
|
sequence->second=next.Grammar();
|
|
return ParsingDefinitionGrammarWriter(sequence);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator|(const ParsingDefinitionGrammarWriter& next)const
|
|
{
|
|
Ptr<ParsingDefinitionAlternativeGrammar> alternative=new ParsingDefinitionAlternativeGrammar;
|
|
alternative->first=grammar;
|
|
alternative->second=next.Grammar();
|
|
return ParsingDefinitionGrammarWriter(alternative);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator*()const
|
|
{
|
|
Ptr<ParsingDefinitionLoopGrammar> loop=new ParsingDefinitionLoopGrammar;
|
|
loop->grammar=grammar;
|
|
return ParsingDefinitionGrammarWriter(loop);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::As(const ParsingDefinitionTypeWriter& type)const
|
|
{
|
|
Ptr<ParsingDefinitionCreateGrammar> create=new ParsingDefinitionCreateGrammar;
|
|
create->grammar=grammar;
|
|
create->type=type.Type();
|
|
return ParsingDefinitionGrammarWriter(create);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator[](const WString& memberName)const
|
|
{
|
|
Ptr<ParsingDefinitionAssignGrammar> assign=new ParsingDefinitionAssignGrammar;
|
|
assign->grammar=grammar;
|
|
assign->memberName=memberName;
|
|
return ParsingDefinitionGrammarWriter(assign);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::operator!()const
|
|
{
|
|
Ptr<ParsingDefinitionUseGrammar> use=new ParsingDefinitionUseGrammar;
|
|
use->grammar=grammar;
|
|
return ParsingDefinitionGrammarWriter(use);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter ParsingDefinitionGrammarWriter::Set(const WString& memberName, const WString& value)const
|
|
{
|
|
Ptr<ParsingDefinitionSetterGrammar> setter=new ParsingDefinitionSetterGrammar;
|
|
setter->grammar=grammar;
|
|
setter->memberName=memberName;
|
|
setter->value=value;
|
|
return ParsingDefinitionGrammarWriter(setter);
|
|
}
|
|
|
|
Ptr<ParsingDefinitionGrammar> ParsingDefinitionGrammarWriter::Grammar()const
|
|
{
|
|
return grammar;
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter Rule(const WString& name)
|
|
{
|
|
Ptr<ParsingDefinitionPrimitiveGrammar> grammar=new ParsingDefinitionPrimitiveGrammar;
|
|
grammar->name=name;
|
|
return ParsingDefinitionGrammarWriter(grammar);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter Text(const WString& text)
|
|
{
|
|
Ptr<ParsingDefinitionTextGrammar> grammar=new ParsingDefinitionTextGrammar;
|
|
grammar->text=text;
|
|
return ParsingDefinitionGrammarWriter(grammar);
|
|
}
|
|
|
|
ParsingDefinitionGrammarWriter Opt(const ParsingDefinitionGrammarWriter& writer)
|
|
{
|
|
Ptr<ParsingDefinitionOptionalGrammar> grammar=new ParsingDefinitionOptionalGrammar;
|
|
grammar->grammar=writer.Grammar();
|
|
return ParsingDefinitionGrammarWriter(grammar);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionTokenDefinitionWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionTokenDefinitionWriter::ParsingDefinitionTokenDefinitionWriter(ParsingDefinitionWriter& _owner, Ptr<ParsingDefinitionTokenDefinition> _token)
|
|
:owner(_owner)
|
|
,token(_token)
|
|
{
|
|
}
|
|
|
|
ParsingDefinitionTokenDefinitionWriter& ParsingDefinitionTokenDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute)
|
|
{
|
|
token->attributes.Add(attribute.Attribute());
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionWriter& ParsingDefinitionTokenDefinitionWriter::EndToken()
|
|
{
|
|
return owner;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionRuleDefinitionWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionRuleDefinitionWriter::ParsingDefinitionRuleDefinitionWriter(ParsingDefinitionWriter& _owner, Ptr<ParsingDefinitionRuleDefinition> _rule)
|
|
:owner(_owner)
|
|
,rule(_rule)
|
|
{
|
|
}
|
|
|
|
ParsingDefinitionRuleDefinitionWriter& ParsingDefinitionRuleDefinitionWriter::Imply(const ParsingDefinitionGrammarWriter& grammar)
|
|
{
|
|
rule->grammars.Add(grammar.Grammar());
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionRuleDefinitionWriter& ParsingDefinitionRuleDefinitionWriter::Attribute(const ParsingDefinitionAttributeWriter& attribute)
|
|
{
|
|
rule->attributes.Add(attribute.Attribute());
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionWriter& ParsingDefinitionRuleDefinitionWriter::EndRule()
|
|
{
|
|
return owner;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingDefinitionWriter
|
|
***********************************************************************/
|
|
|
|
ParsingDefinitionWriter::ParsingDefinitionWriter()
|
|
{
|
|
definition=new ParsingDefinition;
|
|
}
|
|
|
|
ParsingDefinitionWriter& ParsingDefinitionWriter::Type(const ParsingDefinitionTypeDefinitionWriter& type)
|
|
{
|
|
definition->types.Add(type.Definition());
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionWriter& ParsingDefinitionWriter::Token(const WString& name, const WString& regex)
|
|
{
|
|
return TokenAtt(name, regex).EndToken();
|
|
}
|
|
|
|
ParsingDefinitionTokenDefinitionWriter ParsingDefinitionWriter::TokenAtt(const WString& name, const WString& regex)
|
|
{
|
|
Ptr<ParsingDefinitionTokenDefinition> token=new ParsingDefinitionTokenDefinition;
|
|
token->name=name;
|
|
token->regex=regex;
|
|
token->discard=false;
|
|
definition->tokens.Add(token);
|
|
return ParsingDefinitionTokenDefinitionWriter(*this, token);
|
|
}
|
|
|
|
ParsingDefinitionWriter& ParsingDefinitionWriter::Discard(const WString& name, const WString& regex)
|
|
{
|
|
Ptr<ParsingDefinitionTokenDefinition> token=new ParsingDefinitionTokenDefinition;
|
|
token->name=name;
|
|
token->regex=regex;
|
|
token->discard=true;
|
|
definition->tokens.Add(token);
|
|
return *this;
|
|
}
|
|
|
|
ParsingDefinitionRuleDefinitionWriter ParsingDefinitionWriter::Rule(const WString& name, const ParsingDefinitionTypeWriter& type)
|
|
{
|
|
Ptr<ParsingDefinitionRuleDefinition> rule=new ParsingDefinitionRuleDefinition;
|
|
rule->name=name;
|
|
rule->type=type.Type();
|
|
definition->rules.Add(rule);
|
|
return ParsingDefinitionRuleDefinitionWriter(*this, rule);
|
|
}
|
|
|
|
Ptr<ParsingDefinition> ParsingDefinitionWriter::Definition()const
|
|
{
|
|
return definition;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\PARSINGDEFINITIONS_CREATEPARSERDEFINITION.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace definitions
|
|
{
|
|
using namespace collections;
|
|
|
|
/***********************************************************************
|
|
Bootstrap
|
|
***********************************************************************/
|
|
|
|
Ptr<ParsingDefinition> CreateParserDefinition()
|
|
{
|
|
ParsingDefinitionWriter definitionWriter;
|
|
|
|
definitionWriter
|
|
.Type(
|
|
Class(L"AttributeDef")
|
|
.Member(L"name", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"Attribute"))
|
|
.Member(L"arguments", TokenType().Array())
|
|
)
|
|
.Type(
|
|
Class(L"DefBase")
|
|
.Member(L"attributes", Type(L"AttributeDef").Array())
|
|
)
|
|
//-------------------------------------
|
|
.Type(
|
|
Class(L"TypeObj")
|
|
)
|
|
|
|
.Type(
|
|
Class(L"PrimitiveTypeObj", Type(L"TypeObj"))
|
|
.Member(L"name", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"Type"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"TokenTypeObj", Type(L"TypeObj"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"SubTypeObj", Type(L"TypeObj"))
|
|
.Member(L"parentType", Type(L"TypeObj"))
|
|
.Member(L"name", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"Type"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"ArrayTypeObj", Type(L"TypeObj"))
|
|
.Member(L"elementType", Type(L"TypeObj"))
|
|
)
|
|
//-------------------------------------
|
|
.Type(
|
|
Class(L"TypeDef", Type(L"DefBase"))
|
|
.Member(L"name", TokenType())
|
|
.Attribute(Attribute(L"Color").Argument(L"Type"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"ClassMemberDef", Type(L"DefBase"))
|
|
.Member(L"type", Type(L"TypeObj"))
|
|
.Member(L"name", TokenType())
|
|
.Member(L"unescapingFunction", TokenType())
|
|
)
|
|
|
|
.Type(
|
|
Class(L"ClassTypeDef", Type(L"TypeDef"))
|
|
.Member(L"ambiguousType", Type(L"TypeObj"))
|
|
.Member(L"parentType", Type(L"TypeObj"))
|
|
.Member(L"members", Type(L"ClassMemberDef").Array())
|
|
.Member(L"subTypes", Type(L"TypeDef").Array())
|
|
)
|
|
|
|
.Type(
|
|
Class(L"EnumMemberDef", Type(L"DefBase"))
|
|
.Member(L"name", TokenType())
|
|
)
|
|
|
|
.Type(
|
|
Class(L"EnumTypeDef", Type(L"TypeDef"))
|
|
.Member(L"members", Type(L"EnumMemberDef").Array())
|
|
)
|
|
//-------------------------------------
|
|
.Type(
|
|
Class(L"GrammarDef")
|
|
)
|
|
|
|
.Type(
|
|
Class(L"PrimitiveGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"name", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"Token").Argument(L"Rule"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"TextGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"text", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"Literal"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"SequenceGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"first", Type(L"GrammarDef"))
|
|
.Member(L"second", Type(L"GrammarDef"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"AlternativeGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"first", Type(L"GrammarDef"))
|
|
.Member(L"second", Type(L"GrammarDef"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"LoopGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"grammar", Type(L"GrammarDef"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"OptionalGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"grammar", Type(L"GrammarDef"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"CreateGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"grammar", Type(L"GrammarDef"))
|
|
.Member(L"type", Type(L"TypeObj"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"AssignGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"grammar", Type(L"GrammarDef"))
|
|
.Member(L"memberName", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"Field"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"UseGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"grammar", Type(L"GrammarDef"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"SetterGrammarDef", Type(L"GrammarDef"))
|
|
.Member(L"grammar", Type(L"GrammarDef"))
|
|
.Member(L"memberName", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"Field"))
|
|
.Member(L"value", TokenType())
|
|
.Attribute(Attribute(L"Semantic").Argument(L"EnumValue"))
|
|
)
|
|
//-------------------------------------
|
|
.Type(
|
|
Class(L"TokenDef", Type(L"DefBase"))
|
|
.SubType(
|
|
Enum(L"DiscardOption")
|
|
.Member(L"DiscardToken")
|
|
.Member(L"KeepToken")
|
|
)
|
|
.Member(L"name", TokenType())
|
|
.Attribute(Attribute(L"Color").Argument(L"Token"))
|
|
.Member(L"regex", TokenType())
|
|
.Member(L"discard", Type(L"DiscardOption"))
|
|
)
|
|
|
|
.Type(
|
|
Class(L"RuleDef", Type(L"DefBase"))
|
|
.Member(L"name", TokenType())
|
|
.Attribute(Attribute(L"Color").Argument(L"Rule"))
|
|
.Member(L"type", Type(L"TypeObj"))
|
|
.Member(L"grammars", Type(L"GrammarDef").Array())
|
|
)
|
|
|
|
.Type(
|
|
Class(L"ParserDef")
|
|
.Member(L"definitions", Type(L"DefBase").Array())
|
|
)
|
|
//-------------------------------------
|
|
.TokenAtt(L"CLASS", L"class")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
.TokenAtt(L"AMBIGUOUS", L"ambiguous")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
.TokenAtt(L"ENUM", L"enum")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
.TokenAtt(L"TOKEN", L"token")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
.TokenAtt(L"DISCARDTOKEN", L"discardtoken")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
.TokenAtt(L"RULE", L"rule")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
.TokenAtt(L"AS", L"as")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
.TokenAtt(L"WITH", L"with")
|
|
.Attribute(Attribute(L"Color").Argument(L"Keyword"))
|
|
.Attribute(Attribute(L"Candidate"))
|
|
.EndToken()
|
|
|
|
.Token(L"OPEN", L"/{")
|
|
.Token(L"CLOSE", L"/}")
|
|
.Token(L"SEMICOLON", L";")
|
|
.Token(L"COLON", L":")
|
|
.Token(L"COMMA", L",")
|
|
.Token(L"DOT", L".")
|
|
.Token(L"ASSIGN", L"/=")
|
|
.Token(L"USING", L"/!")
|
|
.Token(L"OR", L"/|")
|
|
.Token(L"OPTOPEN", L"/[")
|
|
.Token(L"OPTCLOSE", L"/]")
|
|
.Token(L"PREOPEN", L"/(")
|
|
.Token(L"PRECLOSE", L"/)")
|
|
.TokenAtt(L"ATT", L"@")
|
|
.Attribute(Attribute(L"Color").Argument(L"Attribute"))
|
|
.EndToken()
|
|
|
|
.TokenAtt(L"NAME", L"[a-zA-Z_]/w*")
|
|
.Attribute(Attribute(L"Color").Argument(L"Default"))
|
|
.Attribute(Attribute(L"ContextColor"))
|
|
.Attribute(Attribute(L"AutoComplete"))
|
|
.EndToken()
|
|
.TokenAtt(L"STRING", L"\"([^\"]|\"\")*\"")
|
|
.Attribute(Attribute(L"Color").Argument(L"String"))
|
|
.Attribute(Attribute(L"AutoComplete"))
|
|
.EndToken()
|
|
.Discard(L"SPACE", L"/s+")
|
|
.Discard(L"COMMENT", L"////[^\\r\\n]*")
|
|
//-------------------------------------
|
|
.Rule(L"Attribute", Type(L"AttributeDef"))
|
|
.Imply(
|
|
(Text(L"@") + Rule(L"NAME")[L"name"] + Text(L"(") + Opt(Rule(L"STRING")[L"arguments"] + *(Text(L",") + Rule(L"STRING")[L"arguments"])) + Text(L")"))
|
|
.As(Type(L"AttributeDef"))
|
|
)
|
|
.EndRule()
|
|
//-------------------------------------
|
|
.Rule(L"Type", Type(L"TypeObj"))
|
|
.Imply(
|
|
(Rule(L"NAME")[L"name"])
|
|
.As(Type(L"PrimitiveTypeObj"))
|
|
)
|
|
.Imply(
|
|
Text(L"token")
|
|
.As(Type(L"TokenTypeObj"))
|
|
)
|
|
.Imply(
|
|
(Rule(L"Type")[L"parentType"] + Text(L".") + Rule(L"NAME")[L"name"])
|
|
.As(Type(L"SubTypeObj"))
|
|
)
|
|
.Imply(
|
|
(Rule(L"Type")[L"elementType"] + Text(L"[") + Text(L"]"))
|
|
.As(Type(L"ArrayTypeObj"))
|
|
)
|
|
.EndRule()
|
|
//-------------------------------------
|
|
.Rule(L"EnumMember", Type(L"EnumMemberDef"))
|
|
.Imply(
|
|
(
|
|
Rule(L"NAME")[L"name"]
|
|
+ Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"]))
|
|
+ Text(L",")
|
|
)
|
|
.As(Type(L"EnumMemberDef"))
|
|
)
|
|
.EndRule()
|
|
.Rule(L"Enum", Type(L"EnumTypeDef"))
|
|
.Imply(
|
|
(
|
|
Text(L"enum") + Rule(L"NAME")[L"name"]
|
|
+ Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"]))
|
|
+ Text(L"{")
|
|
+ *(Rule(L"EnumMember")[L"members"])
|
|
+ Text(L"}")
|
|
)
|
|
.As(Type(L"EnumTypeDef"))
|
|
)
|
|
.EndRule()
|
|
.Rule(L"ClassMember", Type(L"ClassMemberDef"))
|
|
.Imply(
|
|
(
|
|
Rule(L"Type")[L"type"] + Rule(L"NAME")[L"name"]
|
|
+ Opt(Text(L"(") + Rule(L"NAME")[L"unescapingFunction"] + Text(L")"))
|
|
+ Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"]))
|
|
+ Text(L";")
|
|
)
|
|
.As(Type(L"ClassMemberDef"))
|
|
)
|
|
.EndRule()
|
|
.Rule(L"Class", Type(L"ClassTypeDef"))
|
|
.Imply(
|
|
(
|
|
Text(L"class") + Rule(L"NAME")[L"name"]
|
|
+ Opt(Text(L"ambiguous") + Text(L"(") + Rule(L"Type")[L"ambiguousType"] + Text(L")"))
|
|
+ Opt(Text(L":") + Rule(L"Type")[L"parentType"])
|
|
+ Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"]))
|
|
+ Text(L"{")
|
|
+ *(Rule(L"ClassMember")[L"members"] | Rule(L"TypeDecl")[L"subTypes"])
|
|
+ Text(L"}")
|
|
)
|
|
.As(Type(L"ClassTypeDef"))
|
|
)
|
|
.EndRule()
|
|
.Rule(L"TypeDecl", Type(L"TypeDef"))
|
|
.Imply(!Rule(L"Enum") | !Rule(L"Class"))
|
|
.EndRule()
|
|
//------------------------------------
|
|
.Rule(L"PrimitiveGrammar", Type(L"GrammarDef"))
|
|
.Imply(
|
|
(Rule(L"NAME")[L"name"])
|
|
.As(Type(L"PrimitiveGrammarDef"))
|
|
)
|
|
.Imply(
|
|
(Rule(L"STRING")[L"text"])
|
|
.As(Type(L"TextGrammarDef"))
|
|
)
|
|
.Imply(
|
|
(Rule(L"PrimitiveGrammar")[L"grammar"] + Text(L":") + Rule(L"NAME")[L"memberName"])
|
|
.As(Type(L"AssignGrammarDef"))
|
|
)
|
|
.Imply(
|
|
(Text(L"!") + Rule(L"PrimitiveGrammar")[L"grammar"])
|
|
.As(Type(L"UseGrammarDef"))
|
|
)
|
|
.Imply(
|
|
(Text(L"[") + Rule(L"Grammar")[L"grammar"] + Text(L"]"))
|
|
.As(Type(L"OptionalGrammarDef"))
|
|
)
|
|
.Imply(
|
|
(Text(L"{") + Rule(L"Grammar")[L"grammar"] + Text(L"}"))
|
|
.As(Type(L"LoopGrammarDef"))
|
|
)
|
|
.Imply(
|
|
(Text(L"(") + !Rule(L"Grammar") + Text(L")"))
|
|
)
|
|
.EndRule()
|
|
|
|
.Rule(L"SequenceGrammar", Type(L"GrammarDef"))
|
|
.Imply(
|
|
!Rule(L"PrimitiveGrammar")
|
|
)
|
|
.Imply(
|
|
(Rule(L"SequenceGrammar")[L"first"] + Rule(L"PrimitiveGrammar")[L"second"])
|
|
.As(Type(L"SequenceGrammarDef"))
|
|
)
|
|
.EndRule()
|
|
|
|
.Rule(L"AlternativeGrammar", Type(L"GrammarDef"))
|
|
.Imply(
|
|
!Rule(L"SequenceGrammar")
|
|
)
|
|
.Imply(
|
|
(Rule(L"AlternativeGrammar")[L"first"] + Text(L"|") + Rule(L"SequenceGrammar")[L"second"])
|
|
.As(Type(L"AlternativeGrammarDef"))
|
|
)
|
|
.EndRule()
|
|
|
|
.Rule(L"Grammar", Type(L"GrammarDef"))
|
|
.Imply(
|
|
!Rule(L"AlternativeGrammar")
|
|
)
|
|
.Imply(
|
|
(Rule(L"Grammar")[L"grammar"] + Text(L"as") + Rule(L"Type")[L"type"])
|
|
.As(Type(L"CreateGrammarDef"))
|
|
)
|
|
.Imply(
|
|
(Rule(L"Grammar")[L"grammar"] + Text(L"with") + Text(L"{") + Rule(L"NAME")[L"memberName"] + Text(L"=") + Rule(L"STRING")[L"value"] + Text(L"}"))
|
|
.As(Type(L"SetterGrammarDef"))
|
|
)
|
|
.EndRule()
|
|
//------------------------------------
|
|
.Rule(L"TokenDecl", Type(L"TokenDef"))
|
|
.Imply(
|
|
(
|
|
Text(L"token") + Rule(L"NAME")[L"name"]
|
|
+ Text(L"=") + Rule(L"STRING")[L"regex"]
|
|
+ Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"]))
|
|
+ Text(L";")
|
|
)
|
|
.As(Type(L"TokenDef"))
|
|
.Set(L"discard", L"KeepToken")
|
|
)
|
|
.Imply(
|
|
(Text(L"discardtoken") + Rule(L"NAME")[L"name"] + Text(L"=") + Rule(L"STRING")[L"regex"] + Text(L";"))
|
|
.As(Type(L"TokenDef"))
|
|
.Set(L"discard", L"DiscardToken")
|
|
)
|
|
.EndRule()
|
|
|
|
.Rule(L"RuleDecl", Type(L"RuleDef"))
|
|
.Imply(
|
|
(
|
|
Text(L"rule") + Rule(L"Type")[L"type"] + Rule(L"NAME")[L"name"]
|
|
+ Opt(Rule(L"Attribute")[L"attributes"] + *(Text(L",") + Rule(L"Attribute")[L"attributes"]))
|
|
+ *(Text(L"=") + Rule(L"Grammar")[L"grammars"])
|
|
+ Text(L";")
|
|
)
|
|
.As(Type(L"RuleDef"))
|
|
)
|
|
.EndRule()
|
|
//------------------------------------
|
|
.Rule(L"ParserDecl", Type(L"ParserDef"))
|
|
.Imply(
|
|
(
|
|
*(
|
|
Rule(L"TypeDecl")[L"definitions"] |
|
|
Rule(L"TokenDecl")[L"definitions"] |
|
|
Rule(L"RuleDecl")[L"definitions"]
|
|
)
|
|
+(
|
|
Rule(L"TypeDecl")[L"definitions"] |
|
|
Rule(L"TokenDecl")[L"definitions"] |
|
|
Rule(L"RuleDecl")[L"definitions"]
|
|
)
|
|
)
|
|
.As(Type(L"ParserDef"))
|
|
)
|
|
.EndRule()
|
|
;
|
|
|
|
return definitionWriter.Definition();
|
|
}
|
|
|
|
WString DeserializeString(const WString& value)
|
|
{
|
|
if(value.Length()>=2 && value[0]==L'"' && value[value.Length()-1]==L'"')
|
|
{
|
|
Array<wchar_t> chars(value.Length());
|
|
memset(&chars[0], 0, chars.Count()*sizeof(wchar_t));
|
|
const wchar_t* reading=value.Buffer()+1;
|
|
wchar_t* writing=&chars[0];
|
|
while(*reading)
|
|
{
|
|
if(*reading!=L'"')
|
|
{
|
|
*writing++=*reading++;
|
|
}
|
|
else if(reading[1]!=L'"')
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
*writing++=L'"';
|
|
reading+=2;
|
|
}
|
|
}
|
|
return &chars[0];
|
|
}
|
|
return L"";
|
|
}
|
|
|
|
WString DeserializeString(Ptr<ParsingTreeToken> token)
|
|
{
|
|
const WString& value=token->GetValue();
|
|
return DeserializeString(value);
|
|
}
|
|
|
|
void SetName(WString& target, Ptr<ParsingTreeNode> node)
|
|
{
|
|
Ptr<ParsingTreeToken> token=node.Cast<ParsingTreeToken>();
|
|
if(token)
|
|
{
|
|
target=token->GetValue();
|
|
}
|
|
}
|
|
|
|
void SetText(WString& target, Ptr<ParsingTreeNode> node)
|
|
{
|
|
Ptr<ParsingTreeToken> token=node.Cast<ParsingTreeToken>();
|
|
if(token)
|
|
{
|
|
target=DeserializeString(token);
|
|
}
|
|
}
|
|
|
|
extern Ptr<ParsingTreeCustomBase> Deserialize(Ptr<ParsingTreeObject> node);
|
|
|
|
template<typename T>
|
|
void SetArray(List<Ptr<T>>& target, Ptr<ParsingTreeNode> node)
|
|
{
|
|
Ptr<ParsingTreeArray> source=node.Cast<ParsingTreeArray>();
|
|
if(source)
|
|
{
|
|
for(vint i=0;i<source->Count();i++)
|
|
{
|
|
target.Add(Deserialize(source->GetItem(i).Cast<ParsingTreeObject>()).Cast<T>());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SetArray(List<WString>& target, Ptr<ParsingTreeNode> node)
|
|
{
|
|
Ptr<ParsingTreeArray> source=node.Cast<ParsingTreeArray>();
|
|
if(source)
|
|
{
|
|
for(vint i=0;i<source->Count();i++)
|
|
{
|
|
WString name;
|
|
SetName(name, source->GetItem(i));
|
|
target.Add(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void SetMember(Ptr<T>& target, Ptr<ParsingTreeNode> node)
|
|
{
|
|
Ptr<ParsingTreeObject> source=node.Cast<ParsingTreeObject>();
|
|
if(source)
|
|
{
|
|
target=Deserialize(source).Cast<T>();
|
|
}
|
|
}
|
|
|
|
Ptr<ParsingTreeCustomBase> Deserialize(Ptr<ParsingTreeObject> node)
|
|
{
|
|
if(!node)
|
|
{
|
|
return 0;
|
|
}
|
|
else if(node->GetType()==L"AttributeDef")
|
|
{
|
|
Ptr<ParsingDefinitionAttribute> target=new ParsingDefinitionAttribute;
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
SetArray(target->arguments, node->GetMember(L"arguments"));
|
|
for(vint i=0;i<target->arguments.Count();i++)
|
|
{
|
|
target->arguments[i]=DeserializeString(target->arguments[i]);
|
|
}
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"PrimitiveTypeObj")
|
|
{
|
|
Ptr<ParsingDefinitionPrimitiveType> target=new ParsingDefinitionPrimitiveType;
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"TokenTypeObj")
|
|
{
|
|
Ptr<ParsingDefinitionTokenType> target=new ParsingDefinitionTokenType;
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"SubTypeObj")
|
|
{
|
|
Ptr<ParsingDefinitionSubType> target=new ParsingDefinitionSubType;
|
|
SetMember(target->parentType, node->GetMember(L"parentType"));
|
|
SetName(target->subTypeName, node->GetMember(L"name"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"ArrayTypeObj")
|
|
{
|
|
Ptr<ParsingDefinitionArrayType> target=new ParsingDefinitionArrayType;
|
|
SetMember(target->elementType, node->GetMember(L"elementType"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"ClassMemberDef")
|
|
{
|
|
Ptr<ParsingDefinitionClassMemberDefinition> target=new ParsingDefinitionClassMemberDefinition;
|
|
SetArray(target->attributes, node->GetMember(L"attributes"));
|
|
SetMember(target->type, node->GetMember(L"type"));
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
SetName(target->unescapingFunction, node->GetMember(L"unescapingFunction"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"ClassTypeDef")
|
|
{
|
|
Ptr<ParsingDefinitionClassDefinition> target=new ParsingDefinitionClassDefinition;
|
|
SetArray(target->attributes, node->GetMember(L"attributes"));
|
|
SetMember(target->ambiguousType, node->GetMember(L"ambiguousType"));
|
|
SetMember(target->parentType, node->GetMember(L"parentType"));
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
SetArray(target->members, node->GetMember(L"members"));
|
|
SetArray(target->subTypes, node->GetMember(L"subTypes"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"EnumMemberDef")
|
|
{
|
|
Ptr<ParsingDefinitionEnumMemberDefinition> target=new ParsingDefinitionEnumMemberDefinition;
|
|
SetArray(target->attributes, node->GetMember(L"attributes"));
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"EnumTypeDef")
|
|
{
|
|
Ptr<ParsingDefinitionEnumDefinition> target=new ParsingDefinitionEnumDefinition;
|
|
SetArray(target->attributes, node->GetMember(L"attributes"));
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
SetArray(target->members, node->GetMember(L"members"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"PrimitiveGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionPrimitiveGrammar> target=new ParsingDefinitionPrimitiveGrammar;
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"TextGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionTextGrammar> target=new ParsingDefinitionTextGrammar;
|
|
SetText(target->text, node->GetMember(L"text"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"SequenceGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionSequenceGrammar> target=new ParsingDefinitionSequenceGrammar;
|
|
SetMember(target->first, node->GetMember(L"first"));
|
|
SetMember(target->second, node->GetMember(L"second"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"AlternativeGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionAlternativeGrammar> target=new ParsingDefinitionAlternativeGrammar;
|
|
SetMember(target->first, node->GetMember(L"first"));
|
|
SetMember(target->second, node->GetMember(L"second"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"LoopGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionLoopGrammar> target=new ParsingDefinitionLoopGrammar;
|
|
SetMember(target->grammar, node->GetMember(L"grammar"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"OptionalGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionOptionalGrammar> target=new ParsingDefinitionOptionalGrammar;
|
|
SetMember(target->grammar, node->GetMember(L"grammar"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"CreateGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionCreateGrammar> target=new ParsingDefinitionCreateGrammar;
|
|
SetMember(target->grammar, node->GetMember(L"grammar"));
|
|
SetMember(target->type, node->GetMember(L"type"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"AssignGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionAssignGrammar> target=new ParsingDefinitionAssignGrammar;
|
|
SetMember(target->grammar, node->GetMember(L"grammar"));
|
|
SetName(target->memberName, node->GetMember(L"memberName"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"UseGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionUseGrammar> target=new ParsingDefinitionUseGrammar;
|
|
SetMember(target->grammar, node->GetMember(L"grammar"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"SetterGrammarDef")
|
|
{
|
|
Ptr<ParsingDefinitionSetterGrammar> target=new ParsingDefinitionSetterGrammar;
|
|
SetMember(target->grammar, node->GetMember(L"grammar"));
|
|
SetName(target->memberName, node->GetMember(L"memberName"));
|
|
SetText(target->value, node->GetMember(L"value"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"TokenDef")
|
|
{
|
|
Ptr<ParsingDefinitionTokenDefinition> target=new ParsingDefinitionTokenDefinition;
|
|
SetArray(target->attributes, node->GetMember(L"attributes"));
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
SetText(target->regex, node->GetMember(L"regex"));
|
|
|
|
Ptr<ParsingTreeToken> token=node->GetMember(L"discard").Cast<ParsingTreeToken>();
|
|
target->discard=(token && token->GetValue()==L"DiscardToken");
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"RuleDef")
|
|
{
|
|
Ptr<ParsingDefinitionRuleDefinition> target=new ParsingDefinitionRuleDefinition;
|
|
SetArray(target->attributes, node->GetMember(L"attributes"));
|
|
SetName(target->name, node->GetMember(L"name"));
|
|
SetMember(target->type, node->GetMember(L"type"));
|
|
SetArray(target->grammars, node->GetMember(L"grammars"));
|
|
return target;
|
|
}
|
|
else if(node->GetType()==L"ParserDef")
|
|
{
|
|
Ptr<ParsingDefinition> target=new ParsingDefinition;
|
|
Ptr<ParsingTreeArray> defs=node->GetMember(L"definitions").Cast<ParsingTreeArray>();
|
|
if(defs)
|
|
{
|
|
vint count=defs->Count();
|
|
for(vint i=0;i<count;i++)
|
|
{
|
|
Ptr<ParsingTreeObject> def=defs->GetItem(i).Cast<ParsingTreeObject>();
|
|
Ptr<ParsingTreeCustomBase> defObject=Deserialize(def);
|
|
if(Ptr<ParsingDefinitionTypeDefinition> defType=defObject.Cast<ParsingDefinitionTypeDefinition>())
|
|
{
|
|
target->types.Add(defType);
|
|
}
|
|
else if(Ptr<ParsingDefinitionTokenDefinition> defToken=defObject.Cast<ParsingDefinitionTokenDefinition>())
|
|
{
|
|
target->tokens.Add(defToken);
|
|
}
|
|
else if(Ptr<ParsingDefinitionRuleDefinition> defRule=defObject.Cast<ParsingDefinitionRuleDefinition>())
|
|
{
|
|
target->rules.Add(defRule);
|
|
}
|
|
}
|
|
}
|
|
return target;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Ptr<ParsingDefinition> DeserializeDefinition(Ptr<ParsingTreeNode> node)
|
|
{
|
|
return Deserialize(node.Cast<ParsingTreeObject>()).Cast<ParsingDefinition>();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\PARSINGLOGGING.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
using namespace stream;
|
|
using namespace collections;
|
|
|
|
namespace parsing
|
|
{
|
|
namespace definitions
|
|
{
|
|
void LogString(const WString& input, TextWriter& writer)
|
|
{
|
|
writer.WriteChar(L'\"');
|
|
for(int i=0;i<input.Length();i++)
|
|
{
|
|
if(input[i]==L'\"')
|
|
{
|
|
writer.WriteString(L"\"\"");
|
|
}
|
|
else
|
|
{
|
|
writer.WriteChar(input[i]);
|
|
}
|
|
}
|
|
writer.WriteChar(L'\"');
|
|
}
|
|
|
|
WString SerializeString(const WString& value)
|
|
{
|
|
return GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
LogString(value, writer);
|
|
});
|
|
}
|
|
|
|
void LogAttributeList(ParsingDefinitionBase* definition, TextWriter& writer)
|
|
{
|
|
for(vint i=0;i<definition->attributes.Count();i++)
|
|
{
|
|
ParsingDefinitionAttribute* att=definition->attributes[i].Obj();
|
|
if(i>0) writer.WriteChar(L',');
|
|
writer.WriteString(L" @");
|
|
writer.WriteString(att->name);
|
|
writer.WriteChar(L'(');
|
|
for(vint j=0;j<att->arguments.Count();j++)
|
|
{
|
|
if(j>0) writer.WriteString(L", ");
|
|
LogString(att->arguments[j], writer);
|
|
}
|
|
writer.WriteChar(L')');
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Logger (ParsingDefinitionType)
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionTypeLogger : public Object, public ParsingDefinitionType::IVisitor
|
|
{
|
|
public:
|
|
TextWriter& writer;
|
|
|
|
ParsingDefinitionTypeLogger(TextWriter& _writer)
|
|
:writer(_writer)
|
|
{
|
|
}
|
|
|
|
static void LogInternal(ParsingDefinitionType* type, TextWriter& writer)
|
|
{
|
|
ParsingDefinitionTypeLogger visitor(writer);
|
|
type->Accept(&visitor);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveType* node)override
|
|
{
|
|
writer.WriteString(node->name);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTokenType* node)override
|
|
{
|
|
writer.WriteString(L"token");
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSubType* node)override
|
|
{
|
|
LogInternal(node->parentType.Obj(), writer);
|
|
writer.WriteString(L".");
|
|
writer.WriteString(node->subTypeName);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionArrayType* node)override
|
|
{
|
|
LogInternal(node->elementType.Obj(), writer);
|
|
writer.WriteString(L"[]");
|
|
}
|
|
};
|
|
|
|
void Log(ParsingDefinitionType* type, TextWriter& writer)
|
|
{
|
|
ParsingDefinitionTypeLogger::LogInternal(type, writer);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Logger (ParsingDefinitionTypeDefinition)
|
|
***********************************************************************/
|
|
|
|
class ParsingDefinitionTypeDefinitionLogger : public Object, public ParsingDefinitionTypeDefinition::IVisitor
|
|
{
|
|
public:
|
|
WString prefix;
|
|
TextWriter& writer;
|
|
|
|
static void LogInternal(ParsingDefinitionTypeDefinition* definition, const WString& prefix, TextWriter& writer)
|
|
{
|
|
ParsingDefinitionTypeDefinitionLogger visitor(prefix, writer);
|
|
definition->Accept(&visitor);
|
|
}
|
|
|
|
ParsingDefinitionTypeDefinitionLogger(const WString& _prefix, TextWriter& _writer)
|
|
:prefix(_prefix)
|
|
,writer(_writer)
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionClassMemberDefinition* node)override
|
|
{
|
|
writer.WriteString(prefix);
|
|
Log(node->type.Obj(), writer);
|
|
writer.WriteString(L" ");
|
|
writer.WriteString(node->name);
|
|
if(node->unescapingFunction!=L"")
|
|
{
|
|
writer.WriteString(L" (");
|
|
writer.WriteString(node->unescapingFunction);
|
|
writer.WriteString(L")");
|
|
}
|
|
LogAttributeList(node, writer);
|
|
writer.WriteLine(L";");
|
|
}
|
|
|
|
void Visit(ParsingDefinitionClassDefinition* node)override
|
|
{
|
|
writer.WriteString(prefix);
|
|
writer.WriteString(L"class ");
|
|
writer.WriteString(node->name);
|
|
if(node->ambiguousType)
|
|
{
|
|
writer.WriteString(L" ambiguous(");
|
|
Log(node->ambiguousType.Obj(), writer);
|
|
writer.WriteString(L")");
|
|
}
|
|
if(node->parentType)
|
|
{
|
|
writer.WriteString(L" : ");
|
|
Log(node->parentType.Obj(), writer);
|
|
}
|
|
LogAttributeList(node, writer);
|
|
writer.WriteLine(L"");
|
|
|
|
writer.WriteString(prefix);
|
|
writer.WriteLine(L"{");
|
|
|
|
for(int i=0;i<node->subTypes.Count();i++)
|
|
{
|
|
LogInternal(node->subTypes[i].Obj(), prefix+L" ", writer);
|
|
writer.WriteLine(L"");
|
|
}
|
|
|
|
for(int i=0;i<node->members.Count();i++)
|
|
{
|
|
LogInternal(node->members[i].Obj(), prefix+L" ", writer);
|
|
}
|
|
|
|
writer.WriteString(prefix);
|
|
writer.WriteLine(L"}");
|
|
}
|
|
|
|
void Visit(ParsingDefinitionEnumMemberDefinition* node)override
|
|
{
|
|
writer.WriteString(prefix);
|
|
writer.WriteString(node->name);
|
|
LogAttributeList(node, writer);
|
|
writer.WriteLine(L",");
|
|
}
|
|
|
|
void Visit(ParsingDefinitionEnumDefinition* node)override
|
|
{
|
|
writer.WriteString(prefix);
|
|
writer.WriteString(L"enum ");
|
|
writer.WriteString(node->name);
|
|
LogAttributeList(node, writer);
|
|
writer.WriteLine(L"");
|
|
|
|
writer.WriteString(prefix);
|
|
writer.WriteLine(L"{");
|
|
|
|
for(int i=0;i<node->members.Count();i++)
|
|
{
|
|
LogInternal(node->members[i].Obj(), prefix+L" ", writer);
|
|
}
|
|
|
|
writer.WriteString(prefix);
|
|
writer.WriteLine(L"}");
|
|
}
|
|
};
|
|
|
|
void Log(ParsingDefinitionTypeDefinition* definition, const WString& prefix, TextWriter& writer)
|
|
{
|
|
ParsingDefinitionTypeDefinitionLogger::LogInternal(definition, prefix, writer);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Logger (ParsingDefinitionGrammar)
|
|
***********************************************************************/
|
|
|
|
#define PRIORITY_NONE 0
|
|
#define PRIORITY_CREATE 1
|
|
#define PRIORITY_SET 1
|
|
#define PRIORITY_ALTERNATIVE 2
|
|
#define PRIORITY_SEQUENCE 3
|
|
#define PRIORITY_USE 4
|
|
#define PRIORITY_ASSIGN 4
|
|
|
|
class ParsingDefinitionGrammarLogger : public Object, public ParsingDefinitionGrammar::IVisitor
|
|
{
|
|
public:
|
|
TextWriter& writer;
|
|
int parentPriority;
|
|
ParsingDefinitionGrammar* stateNode;
|
|
bool beforeNode;
|
|
|
|
ParsingDefinitionGrammarLogger(TextWriter& _writer, int _parentPriority, ParsingDefinitionGrammar* _stateNode, bool _beforeNode)
|
|
:writer(_writer)
|
|
,parentPriority(_parentPriority)
|
|
,stateNode(_stateNode)
|
|
,beforeNode(_beforeNode)
|
|
{
|
|
}
|
|
|
|
static void LogInternal(ParsingDefinitionGrammar* grammar, int parentPriority, ParsingDefinitionGrammar* stateNode, bool beforeNode, TextWriter& writer)
|
|
{
|
|
if(grammar==stateNode && beforeNode)
|
|
{
|
|
writer.WriteString(L"@");
|
|
}
|
|
ParsingDefinitionGrammarLogger visitor(writer, parentPriority, stateNode, beforeNode);
|
|
grammar->Accept(&visitor);
|
|
if(grammar==stateNode && !beforeNode)
|
|
{
|
|
writer.WriteString(L"@");
|
|
}
|
|
}
|
|
|
|
void LogInternal(ParsingDefinitionGrammar* grammar, int parentPriority, TextWriter& writer)
|
|
{
|
|
LogInternal(grammar, parentPriority, stateNode, beforeNode, writer);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveGrammar* node)override
|
|
{
|
|
writer.WriteString(node->name);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTextGrammar* node)override
|
|
{
|
|
LogString(node->text, writer);
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSequenceGrammar* node)override
|
|
{
|
|
int priority=PRIORITY_SEQUENCE;
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L"( ");
|
|
}
|
|
LogInternal(node->first.Obj(), priority, writer);
|
|
writer.WriteString(L" ");
|
|
LogInternal(node->second.Obj(), priority, writer);
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L" )");
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAlternativeGrammar* node)override
|
|
{
|
|
int priority=PRIORITY_ALTERNATIVE;
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L"( ");
|
|
}
|
|
LogInternal(node->first.Obj(), priority, writer);
|
|
writer.WriteString(L" | ");
|
|
LogInternal(node->second.Obj(), priority, writer);
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L" )");
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionLoopGrammar* node)override
|
|
{
|
|
writer.WriteString(L"{ ");
|
|
LogInternal(node->grammar.Obj(), PRIORITY_NONE, writer);
|
|
writer.WriteString(L" }");
|
|
}
|
|
|
|
void Visit(ParsingDefinitionOptionalGrammar* node)override
|
|
{
|
|
writer.WriteString(L"[ ");
|
|
LogInternal(node->grammar.Obj(), PRIORITY_NONE, writer);
|
|
writer.WriteString(L" ]");
|
|
}
|
|
|
|
void Visit(ParsingDefinitionCreateGrammar* node)override
|
|
{
|
|
int priority=PRIORITY_CREATE;
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L"( ");
|
|
}
|
|
LogInternal(node->grammar.Obj(), priority, writer);
|
|
writer.WriteString(L" as ");
|
|
Log(node->type.Obj(), writer);
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L" )");
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAssignGrammar* node)override
|
|
{
|
|
int priority=PRIORITY_ASSIGN;
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L"( ");
|
|
}
|
|
LogInternal(node->grammar.Obj(), priority, writer);
|
|
writer.WriteString(L" : ");
|
|
writer.WriteString(node->memberName);
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L" )");
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionUseGrammar* node)override
|
|
{
|
|
int priority=PRIORITY_USE;
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L"( ");
|
|
}
|
|
writer.WriteString(L"!");
|
|
LogInternal(node->grammar.Obj(), priority, writer);
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L" )");
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSetterGrammar* node)override
|
|
{
|
|
int priority=PRIORITY_SET;
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L"( ");
|
|
}
|
|
LogInternal(node->grammar.Obj(), priority, writer);
|
|
writer.WriteString(L" with { ");
|
|
writer.WriteString(node->memberName);
|
|
writer.WriteString(L" = ");
|
|
LogString(node->value, writer);
|
|
writer.WriteString(L" }");
|
|
if(parentPriority>priority)
|
|
{
|
|
writer.WriteString(L" )");
|
|
}
|
|
}
|
|
};
|
|
|
|
void Log(ParsingDefinitionGrammar* grammar, TextWriter& writer)
|
|
{
|
|
ParsingDefinitionGrammarLogger::LogInternal(grammar, PRIORITY_NONE, 0, true, writer);
|
|
}
|
|
|
|
void Log(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode, TextWriter& writer)
|
|
{
|
|
ParsingDefinitionGrammarLogger::LogInternal(grammar, PRIORITY_NONE, stateNode, beforeNode, writer);
|
|
}
|
|
|
|
#undef PRIORITY_NONE
|
|
#undef PRIORITY_CREATE
|
|
#undef PRIORITY_SET
|
|
#undef PRIORITY_ALTERNATIVE
|
|
#undef PRIORITY_SEQUENCE
|
|
#undef PRIORITY_USE
|
|
#undef PRIORITY_ASSIGN
|
|
|
|
/***********************************************************************
|
|
FindAppropriateGrammarState
|
|
***********************************************************************/
|
|
|
|
class FindAppropriateGrammarStateVisitor : public Object, public ParsingDefinitionGrammar::IVisitor
|
|
{
|
|
public:
|
|
ParsingDefinitionGrammar* stateNode;
|
|
bool beforeNode;
|
|
ParsingDefinitionGrammar* beforeReference;
|
|
ParsingDefinitionGrammar* afterReference;
|
|
ParsingDefinitionGrammar* result;
|
|
|
|
FindAppropriateGrammarStateVisitor(ParsingDefinitionGrammar* _stateNode, bool _beforeNode, ParsingDefinitionGrammar* _beforeReference, ParsingDefinitionGrammar* _afterReference)
|
|
:stateNode(_stateNode)
|
|
,beforeNode(_beforeNode)
|
|
,beforeReference(_beforeReference)
|
|
,afterReference(_afterReference)
|
|
,result(0)
|
|
{
|
|
}
|
|
|
|
static ParsingDefinitionGrammar* Find(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode, ParsingDefinitionGrammar* beforeReference, ParsingDefinitionGrammar* afterReference)
|
|
{
|
|
if(grammar==stateNode)
|
|
{
|
|
return
|
|
beforeNode
|
|
?(beforeReference?beforeReference:stateNode)
|
|
:(afterReference?afterReference:stateNode)
|
|
;
|
|
}
|
|
else
|
|
{
|
|
FindAppropriateGrammarStateVisitor visitor(stateNode, beforeNode, beforeReference, afterReference);
|
|
grammar->Accept(&visitor);
|
|
return visitor.result;
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionPrimitiveGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionTextGrammar* node)override
|
|
{
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSequenceGrammar* node)override
|
|
{
|
|
result=Find(node->first.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), 0);
|
|
if(!result)
|
|
{
|
|
result=Find(node->second.Obj(), stateNode, beforeNode, 0, (afterReference?afterReference:node));
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAlternativeGrammar* node)override
|
|
{
|
|
result=Find(node->first.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node));
|
|
if(!result)
|
|
{
|
|
result=Find(node->second.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node));
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingDefinitionLoopGrammar* node)override
|
|
{
|
|
result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionOptionalGrammar* node)override
|
|
{
|
|
result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionCreateGrammar* node)override
|
|
{
|
|
result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionAssignGrammar* node)override
|
|
{
|
|
result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionUseGrammar* node)override
|
|
{
|
|
result=Find(node->grammar.Obj(), stateNode, beforeNode, (beforeReference?beforeReference:node), (afterReference?afterReference:node));
|
|
}
|
|
|
|
void Visit(ParsingDefinitionSetterGrammar* node)override
|
|
{
|
|
result=Find(node->grammar.Obj(), stateNode, beforeNode, beforeReference, afterReference);
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
Logger (ParsingDefinitionGrammar)
|
|
***********************************************************************/
|
|
|
|
WString TypeToString(ParsingDefinitionType* type)
|
|
{
|
|
return GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
Log(type, writer);
|
|
}, 64);
|
|
}
|
|
|
|
WString GrammarToString(ParsingDefinitionGrammar* grammar)
|
|
{
|
|
return GrammarStateToString(grammar, 0, true);
|
|
}
|
|
|
|
WString GrammarStateToString(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode)
|
|
{
|
|
return GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
Log(grammar, stateNode, beforeNode, writer);
|
|
}, 64);
|
|
}
|
|
|
|
ParsingDefinitionGrammar* FindAppropriateGrammarState(ParsingDefinitionGrammar* grammar, ParsingDefinitionGrammar* stateNode, bool beforeNode)
|
|
{
|
|
return FindAppropriateGrammarStateVisitor::Find(grammar, stateNode, beforeNode, 0, 0);
|
|
}
|
|
|
|
void Log(Ptr<ParsingDefinition> definition, TextWriter& writer)
|
|
{
|
|
FOREACH(Ptr<ParsingDefinitionTypeDefinition>, type, definition->types)
|
|
{
|
|
Log(type.Obj(), L"", writer);
|
|
writer.WriteLine(L"");
|
|
}
|
|
|
|
FOREACH(Ptr<ParsingDefinitionTokenDefinition>, token, definition->tokens)
|
|
{
|
|
if(token->discard)
|
|
{
|
|
writer.WriteString(L"discardtoken ");
|
|
}
|
|
else
|
|
{
|
|
writer.WriteString(L"token ");
|
|
}
|
|
writer.WriteString(token->name);
|
|
writer.WriteString(L" = ");
|
|
LogString(token->regex, writer);
|
|
LogAttributeList(token.Obj(), writer);
|
|
writer.WriteLine(L";");
|
|
}
|
|
writer.WriteLine(L"");
|
|
|
|
FOREACH(Ptr<ParsingDefinitionRuleDefinition>, rule, definition->rules)
|
|
{
|
|
writer.WriteString(L"rule ");
|
|
Log(rule->type.Obj(), writer);
|
|
writer.WriteString(L" ");
|
|
writer.WriteString(rule->name);
|
|
LogAttributeList(rule.Obj(), writer);
|
|
writer.WriteLine(L"");
|
|
|
|
FOREACH(Ptr<ParsingDefinitionGrammar>, grammar, rule->grammars)
|
|
{
|
|
writer.WriteString(L" = ");
|
|
Log(grammar.Obj(), writer);
|
|
writer.WriteLine(L"");
|
|
}
|
|
writer.WriteLine(L" ;");
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace analyzing
|
|
{
|
|
/***********************************************************************
|
|
Logger (Automaton)
|
|
***********************************************************************/
|
|
|
|
void LogTransitionSymbol(ParsingSymbol* symbol, stream::TextWriter& writer)
|
|
{
|
|
if(symbol->GetType()==ParsingSymbol::TokenDef)
|
|
{
|
|
writer.WriteString(L"[");
|
|
writer.WriteString(symbol->GetName());
|
|
|
|
WString regex=symbol->GetDescriptorString();
|
|
if(regex_internal::IsRegexEscapedLiteralString(regex))
|
|
{
|
|
writer.WriteString(L" ");
|
|
definitions::LogString(regex_internal::UnescapeTextForRegex(regex), writer);
|
|
}
|
|
writer.WriteString(L"]");
|
|
}
|
|
else
|
|
{
|
|
writer.WriteString(L"<");
|
|
writer.WriteString(symbol->GetName());
|
|
writer.WriteString(L">");
|
|
}
|
|
}
|
|
|
|
void Log(Ptr<Automaton> automaton, stream::TextWriter& writer)
|
|
{
|
|
FOREACH(Ptr<RuleInfo>, ruleInfo, automaton->ruleInfos)
|
|
{
|
|
writer.WriteString(L"Root Rule Start: ");
|
|
writer.WriteLine(ruleInfo->rootRuleStartState->stateName);
|
|
|
|
writer.WriteString(L"Root Rule End: ");
|
|
writer.WriteLine(ruleInfo->rootRuleEndState->stateName);
|
|
|
|
writer.WriteString(L"Rule Start: ");
|
|
writer.WriteLine(ruleInfo->startState->stateName);
|
|
|
|
FOREACH(State*, endState, ruleInfo->endStates)
|
|
{
|
|
writer.WriteString(L"Rule End: ");
|
|
writer.WriteLine(endState->stateName);
|
|
}
|
|
|
|
writer.WriteLine(L"");
|
|
}
|
|
|
|
List<State*> states;
|
|
FOREACH(Ptr<RuleInfo>, ruleInfo, automaton->ruleInfos)
|
|
{
|
|
vint currentState=states.Count();
|
|
states.Add(ruleInfo->rootRuleStartState);
|
|
|
|
while(currentState<states.Count())
|
|
{
|
|
State* state=states[currentState++];
|
|
writer.WriteLine(state->stateExpression);
|
|
if(state->endState)
|
|
{
|
|
writer.WriteString(L"END STATE ");
|
|
}
|
|
else
|
|
{
|
|
writer.WriteString(L"STATE ");
|
|
}
|
|
writer.WriteLine(state->stateName);
|
|
|
|
FOREACH(Transition*, transition, state->transitions)
|
|
{
|
|
if(!states.Contains(transition->target))
|
|
{
|
|
states.Add(transition->target);
|
|
}
|
|
switch(transition->transitionType)
|
|
{
|
|
case Transition::Epsilon:
|
|
writer.WriteString(L" EPSILON");
|
|
break;
|
|
case Transition::TokenBegin:
|
|
writer.WriteString(L" TOKEN-BEGIN");
|
|
break;
|
|
case Transition::TokenFinish:
|
|
writer.WriteString(L" TOKEN-FINISH");
|
|
break;
|
|
case Transition::NormalReduce:
|
|
writer.WriteString(L" NORMAL-REDUCE");
|
|
break;
|
|
case Transition::LeftRecursiveReduce:
|
|
writer.WriteString(L" LREC-REDUCE");
|
|
break;
|
|
case Transition::Symbol:
|
|
{
|
|
writer.WriteString(L" ");
|
|
if(transition->transitionSymbol)
|
|
{
|
|
LogTransitionSymbol(transition->transitionSymbol, writer);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
switch(transition->stackOperationType)
|
|
{
|
|
case Transition::None:
|
|
writer.WriteString(L" => ");
|
|
break;
|
|
case Transition::ShiftReduceCompacted:
|
|
writer.WriteString(L" [SHIFT-REDUCE-COMPACTED] => ");
|
|
break;
|
|
case Transition::LeftRecursive:
|
|
writer.WriteString(L" [LEFT-RECURSIVE] => ");
|
|
break;
|
|
}
|
|
writer.WriteLine(transition->target->stateName);
|
|
|
|
FOREACH(Ptr<Action>, action, transition->actions)
|
|
{
|
|
switch(action->actionType)
|
|
{
|
|
case Action::Create:
|
|
writer.WriteString(L" CREATE ");
|
|
break;
|
|
case Action::Assign:
|
|
writer.WriteString(L" ASSIGN ");
|
|
break;
|
|
case Action::Using:
|
|
writer.WriteString(L" USING ");
|
|
break;
|
|
case Action::Setter:
|
|
writer.WriteString(L" SET ");
|
|
break;
|
|
case Action::Shift:
|
|
writer.WriteString(L" SHIFT ");
|
|
break;
|
|
case Action::Reduce:
|
|
writer.WriteString(L" REDUCE ");
|
|
break;
|
|
case Action::LeftRecursiveReduce:
|
|
writer.WriteString(L" LR-REDUCE ");
|
|
break;
|
|
}
|
|
|
|
if(action->shiftReduceSource && action->shiftReduceTarget)
|
|
{
|
|
writer.WriteString(L"[");
|
|
writer.WriteString(action->shiftReduceSource->stateName);
|
|
writer.WriteString(L" => ");
|
|
writer.WriteString(action->shiftReduceTarget->stateName);
|
|
writer.WriteString(L"] ");
|
|
}
|
|
|
|
if(action->actionSource)
|
|
{
|
|
writer.WriteString(action->actionSource->GetName());
|
|
}
|
|
if(action->actionTarget)
|
|
{
|
|
writer.WriteString(L" => ");
|
|
writer.WriteString(action->actionTarget->GetName());
|
|
}
|
|
writer.WriteLine(L"");
|
|
}
|
|
}
|
|
writer.WriteLine(L"");
|
|
}
|
|
writer.WriteLine(L"--------------------------------");
|
|
}
|
|
}
|
|
}
|
|
|
|
namespace tabling
|
|
{
|
|
/***********************************************************************
|
|
Logger (ParsingTable)
|
|
***********************************************************************/
|
|
|
|
void LogAttributeList(Ptr<ParsingTable> table, vint attributeIndex, const WString& prefix, stream::TextWriter& writer)
|
|
{
|
|
if(attributeIndex!=-1)
|
|
{
|
|
Ptr<ParsingTable::AttributeInfoList> atts=table->GetAttributeInfo(attributeIndex);
|
|
FOREACH(Ptr<ParsingTable::AttributeInfo>, att, atts->attributes)
|
|
{
|
|
writer.WriteString(prefix);
|
|
writer.WriteString(L"@");
|
|
writer.WriteString(att->name);
|
|
writer.WriteString(L"(");
|
|
for(vint i=0;i<att->arguments.Count();i++)
|
|
{
|
|
if(i>0) writer.WriteString(L", ");
|
|
definitions::LogString(att->arguments[i], writer);
|
|
}
|
|
writer.WriteLine(L")");
|
|
}
|
|
}
|
|
}
|
|
|
|
void Log(Ptr<ParsingTable> table, stream::TextWriter& writer)
|
|
{
|
|
vint rows=table->GetStateCount()+1;
|
|
vint columns=table->GetTokenCount()+1;
|
|
Array<WString> stringTable(rows*columns);
|
|
|
|
stringTable[0]=L"<Parsing Table>";
|
|
|
|
for(vint row=0; row<table->GetStateCount();row++)
|
|
{
|
|
stringTable[(row+1)*columns]=itow(row)+L": "+table->GetStateInfo(row).stateName;
|
|
}
|
|
|
|
for(vint column=0;column<table->GetTokenCount();column++)
|
|
{
|
|
WString content=
|
|
column==ParsingTable::TokenBegin?L"0: $TokenBegin":
|
|
column==ParsingTable::TokenFinish?L"1: $TokenFinish":
|
|
column==ParsingTable::NormalReduce?L"2: $NormalReduce":
|
|
column==ParsingTable::LeftRecursiveReduce?L"3: $LeftRecursiveReduce":
|
|
itow(column)+L": "+table->GetTokenInfo(column).name+L"\r\n "+table->GetTokenInfo(column).regex;
|
|
stringTable[column+1]=content;
|
|
}
|
|
|
|
for(vint row=0; row<table->GetStateCount();row++)
|
|
{
|
|
for(vint column=0;column<table->GetTokenCount();column++)
|
|
{
|
|
Ptr<ParsingTable::TransitionBag> bag=table->GetTransitionBag(row, column);
|
|
if(bag)
|
|
{
|
|
WString content;
|
|
FOREACH(Ptr<ParsingTable::TransitionItem>, item, bag->transitionItems)
|
|
{
|
|
if(content!=L"") content+=L"\r\n";
|
|
content+=itow(item->targetState);
|
|
FOREACH_INDEXER(vint, state, index, item->stackPattern)
|
|
{
|
|
content+=(index==0?L" : ":L", ");
|
|
content+=itow(state);
|
|
}
|
|
content+=L"\r\n";
|
|
|
|
FOREACH(Ptr<ParsingTable::LookAheadInfo>, lookAhead, item->lookAheads)
|
|
{
|
|
content+=L" ";
|
|
FOREACH_INDEXER(vint, token, index, lookAhead->tokens)
|
|
{
|
|
content+=(index==0?L"> ":L", ");
|
|
content+=itow(token);
|
|
}
|
|
content+=L"\r\n";
|
|
}
|
|
|
|
content+=L" ";
|
|
FOREACH(ParsingTable::Instruction, ins, item->instructions)
|
|
{
|
|
switch(ins.instructionType)
|
|
{
|
|
case ParsingTable::Instruction::Create:
|
|
content+=L"C";
|
|
break;
|
|
case ParsingTable::Instruction::Using:
|
|
content+=L"U";
|
|
break;
|
|
case ParsingTable::Instruction::Assign:
|
|
content+=L"A";
|
|
break;
|
|
case ParsingTable::Instruction::Item:
|
|
content+=L"I";
|
|
break;
|
|
case ParsingTable::Instruction::Setter:
|
|
content+=L"S";
|
|
break;
|
|
case ParsingTable::Instruction::Shift:
|
|
content+=L"[+"+itow(ins.stateParameter)+L"]";
|
|
break;
|
|
case ParsingTable::Instruction::Reduce:
|
|
content+=L"[-"+itow(ins.stateParameter)+L"]";
|
|
break;
|
|
case ParsingTable::Instruction::LeftRecursiveReduce:
|
|
content+=L"[!"+itow(ins.stateParameter)+L"]";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
stringTable[(row+1)*columns+(column+1)]=content;
|
|
}
|
|
}
|
|
}
|
|
|
|
writer.WriteLine(L"Target-State : Stack-Pattern ...");
|
|
writer.WriteLine(L"> Look-Ahead ...");
|
|
writer.WriteLine(L"C: Create");
|
|
writer.WriteLine(L"U: Using");
|
|
writer.WriteLine(L"A: Assign");
|
|
writer.WriteLine(L"I: Item");
|
|
writer.WriteLine(L"S: Setter");
|
|
writer.WriteLine(L"[+s]: Shift[push s]");
|
|
writer.WriteLine(L"[-s]: Reduce[pop s]");
|
|
writer.WriteLine(L"[!s]: Left-Recursive-Reduce[fake s]");
|
|
writer.WriteLine(L"");
|
|
|
|
for(vint i=0;i<table->GetRuleCount();i++)
|
|
{
|
|
const ParsingTable::RuleInfo& ruleInfo=table->GetRuleInfo(i);
|
|
writer.WriteString(ruleInfo.name);
|
|
writer.WriteChar(L'<');
|
|
writer.WriteString(ruleInfo.type);
|
|
if(ruleInfo.ambiguousType!=L"")
|
|
{
|
|
writer.WriteString(L", ");
|
|
writer.WriteString(ruleInfo.ambiguousType);
|
|
}
|
|
writer.WriteString(L">: ");
|
|
writer.WriteString(itow(ruleInfo.rootStartState));
|
|
writer.WriteChar(L'[');
|
|
writer.WriteString(table->GetStateInfo(ruleInfo.rootStartState).stateName);
|
|
writer.WriteChar(L']');
|
|
writer.WriteLine(L"");
|
|
}
|
|
|
|
writer.WriteMonospacedEnglishTable(stringTable, rows, columns);
|
|
writer.WriteLine(L"");
|
|
|
|
writer.WriteLine(L"Metadata(Tokens):");
|
|
for(vint i=0;i<table->GetTokenCount();i++)
|
|
{
|
|
const ParsingTable::TokenInfo& info=table->GetTokenInfo(i);
|
|
writer.WriteString(L" ");
|
|
writer.WriteString(info.name);
|
|
writer.WriteString(L"=");
|
|
writer.WriteLine(info.regex);
|
|
LogAttributeList(table, info.attributeIndex, L" ", writer);
|
|
}
|
|
writer.WriteLine(L"");
|
|
|
|
writer.WriteLine(L"Metadata(Rules):");
|
|
for(vint i=0;i<table->GetRuleCount();i++)
|
|
{
|
|
const ParsingTable::RuleInfo& info=table->GetRuleInfo(i);
|
|
writer.WriteString(L" ");
|
|
writer.WriteLine(info.name);
|
|
LogAttributeList(table, info.attributeIndex, L" ", writer);
|
|
}
|
|
writer.WriteLine(L"");
|
|
|
|
writer.WriteLine(L"Metadata(Classes):");
|
|
for(vint i=0;i<table->GetTreeTypeInfoCount();i++)
|
|
{
|
|
const ParsingTable::TreeTypeInfo& info=table->GetTreeTypeInfo(i);
|
|
writer.WriteString(L" ");
|
|
writer.WriteLine(info.type);
|
|
LogAttributeList(table, info.attributeIndex, L" ", writer);
|
|
}
|
|
writer.WriteLine(L"");
|
|
|
|
writer.WriteLine(L"Metadata(Class Members):");
|
|
for(vint i=0;i<table->GetTreeFieldInfoCount();i++)
|
|
{
|
|
const ParsingTable::TreeFieldInfo& info=table->GetTreeFieldInfo(i);
|
|
writer.WriteString(L" ");
|
|
writer.WriteString(info.type);
|
|
writer.WriteString(L".");
|
|
writer.WriteLine(info.field);
|
|
LogAttributeList(table, info.attributeIndex, L" ", writer);
|
|
}
|
|
writer.WriteLine(L"");
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
Logger (ParsingTreeNode)
|
|
***********************************************************************/
|
|
|
|
class LogParsingTreeNodeVisitor : public Object, public ParsingTreeNode::IVisitor
|
|
{
|
|
protected:
|
|
TextWriter& writer;
|
|
WString prefix;
|
|
WString originalInput;
|
|
public:
|
|
LogParsingTreeNodeVisitor(TextWriter& _writer, const WString& _originalInput, const WString& _prefix)
|
|
:writer(_writer)
|
|
,prefix(_prefix)
|
|
,originalInput(_originalInput)
|
|
{
|
|
}
|
|
|
|
void Write(ParsingTreeNode* node)
|
|
{
|
|
if(node)
|
|
{
|
|
node->Accept(this);
|
|
}
|
|
else
|
|
{
|
|
writer.WriteString(L"null");
|
|
}
|
|
}
|
|
|
|
void WriteInput(ParsingTreeNode* node)
|
|
{
|
|
if(originalInput!=L"")
|
|
{
|
|
ParsingTextRange range=node->GetCodeRange();
|
|
if(range.start.index!=ParsingTextPos::UnknownValue && range.end.index!=ParsingTextPos::UnknownValue)
|
|
{
|
|
vint start=range.start.index;
|
|
vint length=range.end.index-start+1;
|
|
if(length>0)
|
|
{
|
|
writer.WriteString(L" // [");
|
|
writer.WriteString(originalInput.Sub(start, length));
|
|
writer.WriteString(L"]");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Visit(ParsingTreeToken* node)
|
|
{
|
|
writer.WriteChar(L'[');
|
|
writer.WriteString(node->GetValue());
|
|
writer.WriteChar(L']');
|
|
WriteInput(node);
|
|
}
|
|
|
|
void Visit(ParsingTreeObject* node)
|
|
{
|
|
WString oldPrefix=prefix;
|
|
writer.WriteString(node->GetType());
|
|
writer.WriteString(L" <");
|
|
for(vint i=0;i<node->GetCreatorRules().Count();i++)
|
|
{
|
|
if(i!=0) writer.WriteString(L", ");
|
|
writer.WriteString(node->GetCreatorRules()[i]);
|
|
}
|
|
writer.WriteString(L"> {");
|
|
WriteInput(node);
|
|
writer.WriteLine(L"");
|
|
prefix+=L" ";
|
|
for(vint i=0;i<node->GetMembers().Count();i++)
|
|
{
|
|
writer.WriteString(prefix);
|
|
writer.WriteString(node->GetMembers().Keys().Get(i));
|
|
writer.WriteString(L" = ");
|
|
Write(node->GetMembers().Values().Get(i).Obj());
|
|
writer.WriteLine(L"");
|
|
}
|
|
prefix=oldPrefix;
|
|
writer.WriteString(prefix);
|
|
writer.WriteString(L"}");
|
|
}
|
|
|
|
void Visit(ParsingTreeArray* node)
|
|
{
|
|
WString oldPrefix=prefix;
|
|
writer.WriteString(node->GetElementType());
|
|
writer.WriteString(L"[] {");
|
|
WriteInput(node);
|
|
writer.WriteLine(L"");
|
|
prefix+=L" ";
|
|
for(vint i=0;i<node->Count();i++)
|
|
{
|
|
writer.WriteString(prefix);
|
|
Write(node->GetItem(i).Obj());
|
|
writer.WriteLine(L",");
|
|
}
|
|
prefix=oldPrefix;
|
|
writer.WriteString(prefix);
|
|
writer.WriteString(L"}");
|
|
}
|
|
};
|
|
|
|
void Log(ParsingTreeNode* node, const WString& originalInput, stream::TextWriter& writer, const WString& prefix)
|
|
{
|
|
writer.WriteString(prefix);
|
|
LogParsingTreeNodeVisitor visitor(writer, originalInput, prefix);
|
|
node->Accept(&visitor);
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\PARSINGSTATE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
#if defined(VCZH_GCC) && defined(__clang__)
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wnull-dereference"
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace tabling
|
|
{
|
|
using namespace collections;
|
|
using namespace regex;
|
|
|
|
/***********************************************************************
|
|
ParsingTokenWalker::LookAheadEnumerator
|
|
***********************************************************************/
|
|
|
|
ParsingTokenWalker::LookAheadEnumerator::LookAheadEnumerator(const ParsingTokenWalker* _walker, vint _currentToken)
|
|
:walker(_walker)
|
|
,firstToken(_currentToken)
|
|
,currentToken(_currentToken)
|
|
,currentValue(-1)
|
|
,index(-1)
|
|
{
|
|
}
|
|
|
|
ParsingTokenWalker::LookAheadEnumerator::LookAheadEnumerator(const LookAheadEnumerator& _enumerator)
|
|
:walker(_enumerator.walker)
|
|
,firstToken(_enumerator.firstToken)
|
|
,currentToken(_enumerator.currentToken)
|
|
,currentValue(_enumerator.currentValue)
|
|
,index(_enumerator.index)
|
|
{
|
|
}
|
|
|
|
IEnumerator<vint>* ParsingTokenWalker::LookAheadEnumerator::Clone()const
|
|
{
|
|
return new LookAheadEnumerator(*this);
|
|
}
|
|
|
|
const vint& ParsingTokenWalker::LookAheadEnumerator::Current()const
|
|
{
|
|
return currentValue;
|
|
}
|
|
|
|
vint ParsingTokenWalker::LookAheadEnumerator::Index()const
|
|
{
|
|
return index;
|
|
}
|
|
|
|
bool ParsingTokenWalker::LookAheadEnumerator::Next()
|
|
{
|
|
vint newToken=walker->GetNextIndex(currentToken);
|
|
if(newToken==-3) return false;
|
|
currentToken=newToken;
|
|
index++;
|
|
currentValue=walker->GetTableTokenIndex(currentToken);
|
|
return true;
|
|
}
|
|
|
|
void ParsingTokenWalker::LookAheadEnumerator::Reset()
|
|
{
|
|
currentToken=firstToken;
|
|
currentValue=-1;
|
|
index=-1;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTokenWalker::TokenLookAhead
|
|
***********************************************************************/
|
|
|
|
ParsingTokenWalker::TokenLookAhead::TokenLookAhead(const ParsingTokenWalker* _walker)
|
|
:walker(_walker)
|
|
{
|
|
}
|
|
|
|
collections::IEnumerator<vint>* ParsingTokenWalker::TokenLookAhead::CreateEnumerator()const
|
|
{
|
|
return new LookAheadEnumerator(walker, walker->currentToken);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTokenWalker::ReduceLookAhead
|
|
***********************************************************************/
|
|
|
|
ParsingTokenWalker::ReduceLookAhead::ReduceLookAhead(const ParsingTokenWalker* _walker)
|
|
:walker(_walker)
|
|
{
|
|
}
|
|
|
|
collections::IEnumerator<vint>* ParsingTokenWalker::ReduceLookAhead::CreateEnumerator()const
|
|
{
|
|
return new LookAheadEnumerator(walker, walker->currentToken - 1);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTokenWalker
|
|
***********************************************************************/
|
|
|
|
vint ParsingTokenWalker::GetNextIndex(vint index)const
|
|
{
|
|
if(index==-2)
|
|
{
|
|
return -1;
|
|
}
|
|
else if(-1<=index && index<tokens.Count())
|
|
{
|
|
index++;
|
|
while(0<=index && index<tokens.Count())
|
|
{
|
|
if(table->IsInputToken(tokens[index].token))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
index++;
|
|
}
|
|
}
|
|
return index;
|
|
}
|
|
else
|
|
{
|
|
return -3;
|
|
}
|
|
}
|
|
|
|
vint ParsingTokenWalker::GetTableTokenIndex(vint index)const
|
|
{
|
|
if(index==-1)
|
|
{
|
|
return ParsingTable::TokenBegin;
|
|
}
|
|
else if(index==tokens.Count())
|
|
{
|
|
return ParsingTable::TokenFinish;
|
|
}
|
|
else if(0<=index && index<tokens.Count())
|
|
{
|
|
return table->GetTableTokenIndex(tokens[index].token);
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
ParsingTokenWalker::ParsingTokenWalker(collections::List<regex::RegexToken>& _tokens, Ptr<ParsingTable> _table)
|
|
:tokens(_tokens)
|
|
,table(_table)
|
|
,currentToken(-2)
|
|
, tokenLookAhead(this)
|
|
, reduceLookAhead(this)
|
|
{
|
|
}
|
|
|
|
ParsingTokenWalker::~ParsingTokenWalker()
|
|
{
|
|
}
|
|
|
|
const collections::IEnumerable<vint>& ParsingTokenWalker::GetTokenLookahead()const
|
|
{
|
|
return tokenLookAhead;
|
|
}
|
|
|
|
const collections::IEnumerable<vint>& ParsingTokenWalker::GetReduceLookahead()const
|
|
{
|
|
return reduceLookAhead;
|
|
}
|
|
|
|
void ParsingTokenWalker::Reset()
|
|
{
|
|
currentToken=-2;
|
|
}
|
|
|
|
bool ParsingTokenWalker::Move()
|
|
{
|
|
currentToken=GetNextIndex(currentToken);
|
|
return currentToken!=-3;
|
|
}
|
|
|
|
vint ParsingTokenWalker::GetTableTokenIndex()const
|
|
{
|
|
return GetTableTokenIndex(currentToken);
|
|
}
|
|
|
|
regex::RegexToken* ParsingTokenWalker::GetRegexToken()const
|
|
{
|
|
vint index=GetTokenIndexInStream();
|
|
return index==-1?0:&tokens[index];
|
|
}
|
|
|
|
vint ParsingTokenWalker::GetTokenIndexInStream()const
|
|
{
|
|
if(0<=currentToken && currentToken<tokens.Count())
|
|
{
|
|
return currentToken;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingState::StateGroup
|
|
***********************************************************************/
|
|
|
|
ParsingState::StateGroup::StateGroup()
|
|
:currentState(-1)
|
|
,tokenSequenceIndex(0)
|
|
,shiftToken(0)
|
|
,reduceToken(0)
|
|
{
|
|
}
|
|
|
|
ParsingState::StateGroup::StateGroup(const ParsingTable::RuleInfo& info)
|
|
:currentState(info.rootStartState)
|
|
,tokenSequenceIndex(0)
|
|
,shiftToken(0)
|
|
,reduceToken(0)
|
|
{
|
|
}
|
|
|
|
ParsingState::StateGroup::StateGroup(const StateGroup& group)
|
|
:currentState(group.currentState)
|
|
,tokenSequenceIndex(group.tokenSequenceIndex)
|
|
,shiftToken(group.shiftToken)
|
|
,reduceToken(group.reduceToken)
|
|
{
|
|
CopyFrom(stateStack, group.stateStack);
|
|
CopyFrom(shiftTokenStack, group.shiftTokenStack);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingState
|
|
***********************************************************************/
|
|
|
|
ParsingState::ParsingState(const WString& _input, Ptr<ParsingTable> _table, vint codeIndex)
|
|
:input(_input.Buffer())
|
|
,table(_table)
|
|
,parsingRuleStartState(-1)
|
|
{
|
|
CopyFrom(tokens, table->GetLexer().Parse(input, codeIndex));
|
|
walker=new ParsingTokenWalker(tokens, table);
|
|
}
|
|
|
|
ParsingState::~ParsingState()
|
|
{
|
|
}
|
|
|
|
const WString& ParsingState::GetInput()
|
|
{
|
|
return input;
|
|
}
|
|
|
|
Ptr<ParsingTable> ParsingState::GetTable()
|
|
{
|
|
return table;
|
|
}
|
|
|
|
const collections::List<regex::RegexToken>& ParsingState::GetTokens()
|
|
{
|
|
return tokens;
|
|
}
|
|
|
|
regex::RegexToken* ParsingState::GetToken(vint index)
|
|
{
|
|
if(index<=0)
|
|
{
|
|
index=0;
|
|
}
|
|
else if(index>tokens.Count())
|
|
{
|
|
index=tokens.Count();
|
|
}
|
|
|
|
return index==tokens.Count()?0:&tokens[index];
|
|
}
|
|
|
|
vint ParsingState::Reset(const WString& rule)
|
|
{
|
|
const ParsingTable::RuleInfo& info=table->GetRuleInfo(rule);
|
|
auto infoExists = &info;
|
|
if(infoExists)
|
|
{
|
|
walker->Reset();
|
|
walker->Move();
|
|
stateGroup=new StateGroup(info);
|
|
parsingRule=rule;
|
|
parsingRuleStartState=info.rootStartState;
|
|
return stateGroup->currentState;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
WString ParsingState::GetParsingRule()
|
|
{
|
|
return parsingRule;
|
|
}
|
|
|
|
vint ParsingState::GetParsingRuleStartState()
|
|
{
|
|
return parsingRuleStartState;
|
|
}
|
|
|
|
vint ParsingState::GetCurrentToken()
|
|
{
|
|
return walker->GetTableTokenIndex()==ParsingTable::TokenFinish
|
|
?tokens.Count()
|
|
:walker->GetTokenIndexInStream();
|
|
}
|
|
|
|
vint ParsingState::GetCurrentTableTokenIndex()
|
|
{
|
|
return walker->GetTableTokenIndex();
|
|
}
|
|
|
|
const collections::List<vint>& ParsingState::GetStateStack()
|
|
{
|
|
return stateGroup->stateStack;
|
|
}
|
|
|
|
vint ParsingState::GetCurrentState()
|
|
{
|
|
return stateGroup->currentState;
|
|
}
|
|
|
|
void ParsingState::SkipCurrentToken()
|
|
{
|
|
walker->Move();
|
|
}
|
|
|
|
bool ParsingState::TestTransitionItemInFuture(vint tableTokenIndex, Future* future, ParsingTable::TransitionItem* item, const collections::IEnumerable<vint>* lookAheadTokens)
|
|
{
|
|
bool passLookAheadTest=true;
|
|
if(item->lookAheads.Count()>0 && lookAheadTokens)
|
|
{
|
|
passLookAheadTest=false;
|
|
FOREACH(Ptr<ParsingTable::LookAheadInfo>, info, item->lookAheads)
|
|
{
|
|
vint index=0;
|
|
FOREACH(vint, token, *lookAheadTokens)
|
|
{
|
|
if(info->tokens[index]!=token)
|
|
{
|
|
break;
|
|
}
|
|
index++;
|
|
if(index>=info->tokens.Count())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
if(index==info->tokens.Count())
|
|
{
|
|
passLookAheadTest=true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if(!passLookAheadTest)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
vint availableStackDepth=stateGroup->stateStack.Count()-future->reduceStateCount;
|
|
vint totalStackDepth=stateGroup->stateStack.Count()-future->reduceStateCount+future->shiftStates.Count();
|
|
if(item->stackPattern.Count()<=totalStackDepth)
|
|
{
|
|
if(tableTokenIndex!=ParsingTable::TokenFinish || item->stackPattern.Count()==totalStackDepth)
|
|
{
|
|
bool match=true;
|
|
for(vint j=0;j<item->stackPattern.Count();j++)
|
|
{
|
|
vint state=
|
|
j<future->shiftStates.Count()
|
|
?future->shiftStates[future->shiftStates.Count()-1-j]
|
|
:stateGroup->stateStack[availableStackDepth-1-(j-future->shiftStates.Count())]
|
|
;
|
|
if(item->stackPattern[j]!=state)
|
|
{
|
|
match=false;
|
|
}
|
|
}
|
|
if(match)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ParsingTable::TransitionItem* ParsingState::MatchTokenInFuture(vint tableTokenIndex, Future* future, const collections::IEnumerable<vint>* lookAheadTokens)
|
|
{
|
|
ParsingTable::TransitionBag* bag=table->GetTransitionBag(future->currentState, tableTokenIndex).Obj();
|
|
if(bag)
|
|
{
|
|
for(vint i=0;i<bag->transitionItems.Count();i++)
|
|
{
|
|
ParsingTable::TransitionItem* item=bag->transitionItems[i].Obj();
|
|
if(TestTransitionItemInFuture(tableTokenIndex, future, item, lookAheadTokens))
|
|
{
|
|
return item;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
ParsingTable::TransitionItem* ParsingState::MatchToken(vint tableTokenIndex, const collections::IEnumerable<vint>* lookAheadTokens)
|
|
{
|
|
Future future;
|
|
future.currentState=stateGroup->currentState;
|
|
return MatchTokenInFuture(tableTokenIndex, &future, lookAheadTokens);
|
|
}
|
|
|
|
void ParsingState::RunTransitionInFuture(ParsingTable::TransitionItem* transition, Future* previous, Future* now)
|
|
{
|
|
if(previous)
|
|
{
|
|
now->reduceStateCount=previous->reduceStateCount;
|
|
CopyFrom(now->shiftStates, previous->shiftStates);
|
|
}
|
|
else
|
|
{
|
|
now->reduceStateCount=0;
|
|
now->shiftStates.Clear();
|
|
}
|
|
now->currentState=transition->targetState;
|
|
now->selectedToken=transition->token;
|
|
now->selectedItem=transition;
|
|
now->previous=previous;
|
|
now->next=0;
|
|
|
|
for(vint j=0;j<transition->instructions.Count();j++)
|
|
{
|
|
ParsingTable::Instruction& ins=transition->instructions[j];
|
|
switch(ins.instructionType)
|
|
{
|
|
case ParsingTable::Instruction::Shift:
|
|
{
|
|
now->shiftStates.Add(ins.stateParameter);
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Reduce:
|
|
{
|
|
if(now->shiftStates.Count()==0)
|
|
{
|
|
now->reduceStateCount++;
|
|
}
|
|
else
|
|
{
|
|
now->shiftStates.RemoveAt(now->shiftStates.Count()-1);
|
|
}
|
|
}
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingState::RunTransition(ParsingTable::TransitionItem* transition, regex::RegexToken* regexToken, vint instructionBegin, vint instructionCount, bool lastPart)
|
|
{
|
|
if(regexToken)
|
|
{
|
|
if(!stateGroup->shiftToken)
|
|
{
|
|
stateGroup->shiftToken=regexToken;
|
|
stateGroup->reduceToken=regexToken;
|
|
}
|
|
}
|
|
if(transition->token>=ParsingTable::UserTokenStart)
|
|
{
|
|
if(stateGroup->tokenSequenceIndex==0)
|
|
{
|
|
stateGroup->shiftTokenStack.Add(stateGroup->shiftToken);
|
|
}
|
|
stateGroup->tokenSequenceIndex++;
|
|
}
|
|
|
|
TransitionResult result;
|
|
result.tableTokenIndex=transition->token;
|
|
result.token=regexToken;
|
|
result.tokenIndexInStream=regexToken?walker->GetTokenIndexInStream():-1;
|
|
result.tableStateSource=stateGroup->currentState;
|
|
result.tableStateTarget=transition->targetState;
|
|
result.transition=transition;
|
|
result.instructionBegin=instructionBegin;
|
|
result.instructionCount=instructionCount;
|
|
|
|
for(vint j=instructionBegin;j<instructionBegin+instructionCount;j++)
|
|
{
|
|
ParsingTable::Instruction& ins=transition->instructions[j];
|
|
switch(ins.instructionType)
|
|
{
|
|
case ParsingTable::Instruction::Shift:
|
|
{
|
|
stateGroup->stateStack.Add(ins.stateParameter);
|
|
|
|
stateGroup->shiftTokenStack.Add(stateGroup->shiftToken);
|
|
stateGroup->shiftToken=regexToken;
|
|
stateGroup->reduceToken=regexToken;
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Reduce:
|
|
{
|
|
stateGroup->stateStack.RemoveAt(stateGroup->stateStack.Count()-1);
|
|
|
|
result.AddShiftReduceRange(stateGroup->shiftToken, stateGroup->reduceToken);
|
|
stateGroup->shiftToken=stateGroup->shiftTokenStack[stateGroup->shiftTokenStack.Count()-1];
|
|
stateGroup->shiftTokenStack.RemoveAt(stateGroup->shiftTokenStack.Count()-1);
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::LeftRecursiveReduce:
|
|
{
|
|
result.AddShiftReduceRange(stateGroup->shiftToken, stateGroup->reduceToken);
|
|
if(regexToken)
|
|
{
|
|
stateGroup->reduceToken=regexToken;
|
|
}
|
|
}
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
|
|
if(regexToken)
|
|
{
|
|
stateGroup->reduceToken=regexToken;
|
|
}
|
|
|
|
if(transition->token==ParsingTable::TokenFinish && lastPart)
|
|
{
|
|
stateGroup->shiftToken=stateGroup->shiftTokenStack[stateGroup->shiftTokenStack.Count()-1];
|
|
stateGroup->shiftTokenStack.RemoveAt(stateGroup->shiftTokenStack.Count()-1);
|
|
result.AddShiftReduceRange(stateGroup->shiftToken, stateGroup->reduceToken);
|
|
}
|
|
|
|
stateGroup->currentState=transition->targetState;
|
|
return result;
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingState::RunTransition(ParsingTable::TransitionItem* transition, regex::RegexToken* regexToken)
|
|
{
|
|
return RunTransition(transition, regexToken, 0, transition->instructions.Count(), true);
|
|
}
|
|
|
|
bool ParsingState::ReadTokenInFuture(vint tableTokenIndex, Future* previous, Future* now, const collections::IEnumerable<vint>* lookAheadTokens)
|
|
{
|
|
ParsingTable::TransitionItem* selectedItem=0;
|
|
if(previous)
|
|
{
|
|
selectedItem=MatchTokenInFuture(tableTokenIndex, previous, lookAheadTokens);
|
|
}
|
|
else
|
|
{
|
|
selectedItem=MatchToken(tableTokenIndex, lookAheadTokens);
|
|
}
|
|
|
|
if(!selectedItem)
|
|
{
|
|
return false;
|
|
}
|
|
RunTransitionInFuture(selectedItem, previous, now);
|
|
return true;
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingState::ReadToken(vint tableTokenIndex, regex::RegexToken* regexToken, const collections::IEnumerable<vint>* lookAheadTokens)
|
|
{
|
|
ParsingTable::TransitionItem* item=MatchToken(tableTokenIndex, lookAheadTokens);
|
|
if(item)
|
|
{
|
|
return RunTransition(item, regexToken);
|
|
}
|
|
return TransitionResult();
|
|
}
|
|
|
|
ParsingState::TransitionResult ParsingState::ReadToken()
|
|
{
|
|
if(walker->GetTableTokenIndex()==-1)
|
|
{
|
|
return TransitionResult();
|
|
}
|
|
vint token=walker->GetTableTokenIndex();
|
|
RegexToken* regexToken=walker->GetRegexToken();
|
|
|
|
bool tryReduce=false;
|
|
TransitionResult result=ReadToken(token, regexToken, &walker->GetTokenLookahead());
|
|
if(!result)
|
|
{
|
|
result=ReadToken(ParsingTable::LeftRecursiveReduce, 0, &walker->GetReduceLookahead());
|
|
tryReduce=true;
|
|
}
|
|
if(!result)
|
|
{
|
|
result=ReadToken(ParsingTable::NormalReduce, 0, &walker->GetReduceLookahead());
|
|
tryReduce=true;
|
|
}
|
|
|
|
if(result && !tryReduce)
|
|
{
|
|
walker->Move();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
bool ParsingState::TestExplore(vint tableTokenIndex, Future* previous)
|
|
{
|
|
Future fakePrevious;
|
|
fakePrevious.currentState=stateGroup->currentState;
|
|
Future* realPrevious=previous?previous:&fakePrevious;
|
|
|
|
ParsingTable::TransitionBag* bag=table->GetTransitionBag(realPrevious->currentState, tableTokenIndex).Obj();
|
|
if(bag)
|
|
{
|
|
for(vint i=0;i<bag->transitionItems.Count();i++)
|
|
{
|
|
ParsingTable::TransitionItem* item=bag->transitionItems[i].Obj();
|
|
if(TestTransitionItemInFuture(tableTokenIndex, realPrevious, item, 0))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ParsingState::Explore(vint tableTokenIndex, Future* previous, collections::List<Future*>& possibilities)
|
|
{
|
|
Future fakePrevious;
|
|
fakePrevious.currentState=stateGroup->currentState;
|
|
Future* realPrevious=previous?previous:&fakePrevious;
|
|
|
|
ParsingTable::TransitionBag* bag=table->GetTransitionBag(realPrevious->currentState, tableTokenIndex).Obj();
|
|
bool successful = false;
|
|
if(bag)
|
|
{
|
|
for(vint i=0;i<bag->transitionItems.Count();i++)
|
|
{
|
|
ParsingTable::TransitionItem* item=bag->transitionItems[i].Obj();
|
|
if(TestTransitionItemInFuture(tableTokenIndex, realPrevious, item, 0))
|
|
{
|
|
Future* now=new Future;
|
|
RunTransitionInFuture(item, previous, now);
|
|
possibilities.Add(now);
|
|
successful = true;
|
|
}
|
|
}
|
|
}
|
|
return successful;
|
|
}
|
|
|
|
bool ParsingState::ExploreStep(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities)
|
|
{
|
|
if(walker->GetTableTokenIndex()==-1)
|
|
{
|
|
return false;
|
|
}
|
|
vint token = walker->GetTableTokenIndex();
|
|
RegexToken* regexToken = walker->GetRegexToken();
|
|
vint oldPossibilitiesCount = possibilities.Count();
|
|
for (vint i = 0; i<count; i++)
|
|
{
|
|
Future* previous = previousFutures[start + i];
|
|
Explore(token, previous, possibilities);
|
|
}
|
|
if (possibilities.Count() == oldPossibilitiesCount)
|
|
{
|
|
return false;
|
|
}
|
|
for (vint i = oldPossibilitiesCount; i < possibilities.Count(); i++)
|
|
{
|
|
possibilities[i]->selectedRegexToken = regexToken;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool ParsingState::ExploreNormalReduce(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities)
|
|
{
|
|
if(walker->GetTableTokenIndex()==-1)
|
|
{
|
|
return false;
|
|
}
|
|
vint oldPossibilitiesCount = possibilities.Count();
|
|
for(vint i=0;i<count;i++)
|
|
{
|
|
Future* previous=previousFutures[start+i];
|
|
Explore(ParsingTable::NormalReduce, previous, possibilities);
|
|
}
|
|
return possibilities.Count() > oldPossibilitiesCount;
|
|
}
|
|
|
|
bool ParsingState::ExploreLeftRecursiveReduce(collections::List<Future*>& previousFutures, vint start, vint count, collections::List<Future*>& possibilities)
|
|
{
|
|
if(walker->GetTableTokenIndex()==-1)
|
|
{
|
|
return false;
|
|
}
|
|
vint oldPossibilitiesCount = possibilities.Count();
|
|
for(vint i=0;i<count;i++)
|
|
{
|
|
Future* previous=previousFutures[start+i];
|
|
Explore(ParsingTable::LeftRecursiveReduce, previous, possibilities);
|
|
}
|
|
return possibilities.Count() > oldPossibilitiesCount;
|
|
}
|
|
|
|
ParsingState::Future* ParsingState::ExploreCreateRootFuture()
|
|
{
|
|
Future* future=new Future;
|
|
future->currentState=stateGroup->currentState;
|
|
return future;
|
|
}
|
|
|
|
Ptr<ParsingState::StateGroup> ParsingState::TakeSnapshot()
|
|
{
|
|
return new StateGroup(*stateGroup.Obj());
|
|
}
|
|
|
|
void ParsingState::RestoreSnapshot(Ptr<StateGroup> group)
|
|
{
|
|
stateGroup=new StateGroup(*group.Obj());
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTreeBuilder
|
|
***********************************************************************/
|
|
|
|
ParsingTreeBuilder::ParsingTreeBuilder()
|
|
:processingAmbiguityBranch(false)
|
|
,ambiguityBranchSharedNodeCount(0)
|
|
{
|
|
}
|
|
|
|
ParsingTreeBuilder::~ParsingTreeBuilder()
|
|
{
|
|
}
|
|
|
|
void ParsingTreeBuilder::Reset()
|
|
{
|
|
createdObject=0;
|
|
operationTarget=new ParsingTreeObject();
|
|
nodeStack.Clear();
|
|
|
|
processingAmbiguityBranch=false;
|
|
ambiguityBranchCreatedObject=0;
|
|
ambiguityBranchOperationTarget=0;
|
|
ambiguityBranchSharedNodeCount=0;
|
|
ambiguityBranchNodeStack.Clear();
|
|
ambiguityNodes.Clear();
|
|
}
|
|
|
|
bool ParsingTreeBuilder::Run(const ParsingState::TransitionResult& result)
|
|
{
|
|
if(!operationTarget)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
switch(result.transitionType)
|
|
{
|
|
case ParsingState::TransitionResult::AmbiguityBegin:
|
|
{
|
|
if(processingAmbiguityBranch) return false;
|
|
processingAmbiguityBranch=true;
|
|
if(createdObject)
|
|
{
|
|
ambiguityBranchCreatedObject=createdObject->Clone();
|
|
}
|
|
else
|
|
{
|
|
ambiguityBranchCreatedObject=0;
|
|
}
|
|
ambiguityBranchOperationTarget=operationTarget->Clone().Cast<ParsingTreeObject>();
|
|
ambiguityBranchNodeStack.Clear();
|
|
ambiguityBranchSharedNodeCount=nodeStack.Count()-result.ambiguityAffectedStackNodeCount+1;
|
|
for(vint i=ambiguityBranchSharedNodeCount;i<nodeStack.Count();i++)
|
|
{
|
|
ambiguityBranchNodeStack.Add(nodeStack[i]->Clone().Cast<ParsingTreeObject>());
|
|
}
|
|
ambiguityNodes.Clear();
|
|
}
|
|
break;
|
|
case ParsingState::TransitionResult::AmbiguityBranch:
|
|
{
|
|
if(!processingAmbiguityBranch) return false;
|
|
if(nodeStack.Count()!=ambiguityBranchSharedNodeCount) return false;
|
|
ambiguityNodes.Add(operationTarget);
|
|
if(ambiguityBranchCreatedObject)
|
|
{
|
|
createdObject=ambiguityBranchCreatedObject->Clone();
|
|
}
|
|
else
|
|
{
|
|
createdObject=0;
|
|
}
|
|
operationTarget=ambiguityBranchOperationTarget->Clone().Cast<ParsingTreeObject>();
|
|
for(vint i=0;i<ambiguityBranchNodeStack.Count();i++)
|
|
{
|
|
nodeStack.Add(ambiguityBranchNodeStack[i]->Clone().Cast<ParsingTreeObject>());
|
|
}
|
|
}
|
|
break;
|
|
case ParsingState::TransitionResult::AmbiguityEnd:
|
|
{
|
|
if(!processingAmbiguityBranch) return false;
|
|
if(nodeStack.Count()!=ambiguityBranchSharedNodeCount) return false;
|
|
ambiguityNodes.Add(operationTarget);
|
|
|
|
processingAmbiguityBranch=false;
|
|
createdObject=0;
|
|
ambiguityBranchCreatedObject=0;
|
|
ambiguityBranchOperationTarget=0;
|
|
ambiguityBranchSharedNodeCount=0;
|
|
ambiguityBranchNodeStack.Clear();
|
|
|
|
{
|
|
Ptr<ParsingTreeObject> ambiguousNode=new ParsingTreeObject(result.ambiguityNodeType, operationTarget->GetCodeRange());
|
|
Ptr<ParsingTreeArray> items=new ParsingTreeArray(L"", operationTarget->GetCodeRange());
|
|
FOREACH(Ptr<ParsingTreeObject>, node, ambiguityNodes)
|
|
{
|
|
items->AddItem(node);
|
|
}
|
|
ambiguousNode->SetMember(L"items", items);
|
|
operationTarget=ambiguousNode;
|
|
}
|
|
ambiguityNodes.Clear();
|
|
}
|
|
break;
|
|
case ParsingState::TransitionResult::ExecuteInstructions:
|
|
{
|
|
vint shiftReduceRangeIndex=0;
|
|
for(vint j=result.instructionBegin;j<result.instructionBegin+result.instructionCount;j++)
|
|
{
|
|
ParsingTable::Instruction& ins=result.transition->instructions[j];
|
|
switch(ins.instructionType)
|
|
{
|
|
case ParsingTable::Instruction::Create:
|
|
{
|
|
if(operationTarget->GetType()!=L"")
|
|
{
|
|
return false;
|
|
}
|
|
operationTarget->SetType(ins.nameParameter);
|
|
operationTarget->GetCreatorRules().Add(ins.creatorRule);
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Using:
|
|
{
|
|
if(operationTarget->GetType()!=L"" || !createdObject)
|
|
{
|
|
return false;
|
|
}
|
|
Ptr<ParsingTreeObject> obj=createdObject.Cast<ParsingTreeObject>();
|
|
if(!obj)
|
|
{
|
|
return false;
|
|
}
|
|
for(vint i=0;i<operationTarget->GetMembers().Count();i++)
|
|
{
|
|
WString name=operationTarget->GetMembers().Keys().Get(i);
|
|
Ptr<ParsingTreeNode> value=operationTarget->GetMembers().Values().Get(i);
|
|
obj->SetMember(name, value);
|
|
}
|
|
operationTarget=obj;
|
|
operationTarget->GetCreatorRules().Add(ins.creatorRule);
|
|
createdObject=0;
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Assign:
|
|
{
|
|
if(!createdObject)
|
|
{
|
|
Ptr<ParsingTreeToken> value;
|
|
if(result.token==0)
|
|
{
|
|
value=new ParsingTreeToken(L"", result.tokenIndexInStream);
|
|
}
|
|
else
|
|
{
|
|
value=new ParsingTreeToken(WString(result.token->reading, result.token->length), result.tokenIndexInStream);
|
|
value->SetCodeRange(ParsingTextRange(result.token, result.token));
|
|
}
|
|
operationTarget->SetMember(ins.nameParameter, value);
|
|
}
|
|
else
|
|
{
|
|
operationTarget->SetMember(ins.nameParameter, createdObject);
|
|
createdObject=0;
|
|
}
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Item:
|
|
{
|
|
Ptr<ParsingTreeArray> arr=operationTarget->GetMember(ins.nameParameter).Cast<ParsingTreeArray>();;
|
|
if(!arr)
|
|
{
|
|
arr=new ParsingTreeArray();
|
|
operationTarget->SetMember(ins.nameParameter, arr);
|
|
}
|
|
ParsingTextRange arrRange=arr->GetCodeRange();
|
|
ParsingTextRange itemRange;
|
|
if(!createdObject)
|
|
{
|
|
Ptr<ParsingTreeToken> value;
|
|
if(result.token==0)
|
|
{
|
|
value=new ParsingTreeToken(L"", result.tokenIndexInStream);
|
|
}
|
|
else
|
|
{
|
|
value=new ParsingTreeToken(WString(result.token->reading, result.token->length), result.tokenIndexInStream);
|
|
value->SetCodeRange(ParsingTextRange(result.token, result.token));
|
|
itemRange=value->GetCodeRange();
|
|
}
|
|
arr->AddItem(value);
|
|
}
|
|
else
|
|
{
|
|
arr->AddItem(createdObject);
|
|
itemRange=createdObject->GetCodeRange();
|
|
createdObject=0;
|
|
}
|
|
|
|
if(arrRange.start.index==ParsingTextPos::UnknownValue || itemRange.start<arrRange.start)
|
|
{
|
|
arrRange.start=itemRange.start;
|
|
}
|
|
if(arrRange.end.index==ParsingTextPos::UnknownValue || itemRange.end>arrRange.end)
|
|
{
|
|
arrRange.end=itemRange.end;
|
|
}
|
|
arr->SetCodeRange(arrRange);
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Setter:
|
|
{
|
|
Ptr<ParsingTreeToken> value=new ParsingTreeToken(ins.value, -1);
|
|
operationTarget->SetMember(ins.nameParameter, value);
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Shift:
|
|
{
|
|
nodeStack.Add(operationTarget);
|
|
operationTarget=new ParsingTreeObject();
|
|
createdObject=0;
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::Reduce:
|
|
{
|
|
if(nodeStack.Count()==0)
|
|
{
|
|
return false;
|
|
}
|
|
createdObject=operationTarget;
|
|
operationTarget=nodeStack[nodeStack.Count()-1];
|
|
nodeStack.RemoveAt(nodeStack.Count()-1);
|
|
|
|
if(result.shiftReduceRanges)
|
|
{
|
|
ParsingState::ShiftReduceRange tokenRange=result.shiftReduceRanges->Get(shiftReduceRangeIndex++);
|
|
if(tokenRange.shiftToken && tokenRange.reduceToken)
|
|
{
|
|
ParsingTextRange codeRange(tokenRange.shiftToken, tokenRange.reduceToken);
|
|
createdObject->SetCodeRange(codeRange);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case ParsingTable::Instruction::LeftRecursiveReduce:
|
|
{
|
|
createdObject=operationTarget;
|
|
operationTarget=new ParsingTreeObject();
|
|
|
|
if(result.shiftReduceRanges)
|
|
{
|
|
ParsingState::ShiftReduceRange tokenRange=result.shiftReduceRanges->Get(shiftReduceRangeIndex++);
|
|
if(tokenRange.shiftToken && tokenRange.reduceToken)
|
|
{
|
|
ParsingTextRange codeRange(tokenRange.shiftToken, tokenRange.reduceToken);
|
|
createdObject->SetCodeRange(codeRange);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if(result.tableTokenIndex==ParsingTable::TokenFinish && !processingAmbiguityBranch)
|
|
{
|
|
if(result.shiftReduceRanges)
|
|
{
|
|
ParsingState::ShiftReduceRange tokenRange=result.shiftReduceRanges->Get(shiftReduceRangeIndex++);
|
|
if(tokenRange.shiftToken && tokenRange.reduceToken)
|
|
{
|
|
ParsingTextRange codeRange(tokenRange.shiftToken, tokenRange.reduceToken);
|
|
operationTarget->SetCodeRange(codeRange);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ParsingTreeBuilder::GetProcessingAmbiguityBranch()
|
|
{
|
|
return processingAmbiguityBranch;
|
|
}
|
|
|
|
Ptr<ParsingTreeObject> ParsingTreeBuilder::GetNode()const
|
|
{
|
|
if(nodeStack.Count()==0)
|
|
{
|
|
return operationTarget;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTransitionCollector
|
|
***********************************************************************/
|
|
|
|
ParsingTransitionCollector::ParsingTransitionCollector()
|
|
:ambiguityBegin(-1)
|
|
{
|
|
}
|
|
|
|
ParsingTransitionCollector::~ParsingTransitionCollector()
|
|
{
|
|
}
|
|
|
|
void ParsingTransitionCollector::Reset()
|
|
{
|
|
ambiguityBegin=-1;
|
|
transitions.Clear();
|
|
ambiguityBeginToEnds.Clear();
|
|
ambiguityBeginToBranches.Clear();
|
|
ambiguityBranchToBegins.Clear();
|
|
}
|
|
|
|
bool ParsingTransitionCollector::Run(const ParsingState::TransitionResult& result)
|
|
{
|
|
vint index=transitions.Count();
|
|
switch(result.transitionType)
|
|
{
|
|
case ParsingState::TransitionResult::AmbiguityBegin:
|
|
if(ambiguityBegin!=-1) return false;
|
|
ambiguityBegin=index;
|
|
break;
|
|
case ParsingState::TransitionResult::AmbiguityBranch:
|
|
{
|
|
if(ambiguityBegin==-1) return false;
|
|
ambiguityBeginToBranches.Add(ambiguityBegin, index);
|
|
ambiguityBranchToBegins.Add(index, ambiguityBegin);
|
|
}
|
|
break;
|
|
case ParsingState::TransitionResult::AmbiguityEnd:
|
|
{
|
|
if(ambiguityBegin==-1) return false;
|
|
ambiguityBeginToEnds.Add(ambiguityBegin, index);
|
|
ambiguityBegin=-1;
|
|
}
|
|
break;
|
|
case ParsingState::TransitionResult::ExecuteInstructions:
|
|
break;
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
transitions.Add(result);
|
|
return true;
|
|
}
|
|
|
|
bool ParsingTransitionCollector::GetProcessingAmbiguityBranch()
|
|
{
|
|
return ambiguityBegin!=-1;
|
|
}
|
|
|
|
const ParsingTransitionCollector::TransitionResultList& ParsingTransitionCollector::GetTransitions()const
|
|
{
|
|
return transitions;
|
|
}
|
|
|
|
vint ParsingTransitionCollector::GetAmbiguityEndFromBegin(vint transitionIndex)const
|
|
{
|
|
vint index=ambiguityBeginToEnds.Keys().IndexOf(transitionIndex);
|
|
return index==-1?-1:ambiguityBeginToEnds.Values()[index];
|
|
}
|
|
|
|
const collections::List<vint>& ParsingTransitionCollector::GetAmbiguityBranchesFromBegin(vint transitionIndex)const
|
|
{
|
|
vint index=ambiguityBeginToBranches.Keys().IndexOf(transitionIndex);
|
|
return index==-1?*(collections::List<vint>*)0:ambiguityBeginToBranches.GetByIndex(index);
|
|
}
|
|
|
|
vint ParsingTransitionCollector::GetAmbiguityBeginFromBranch(vint transitionIndex)const
|
|
{
|
|
vint index=ambiguityBranchToBegins.Keys().IndexOf(transitionIndex);
|
|
return index==-1?-1:ambiguityBranchToBegins.Values()[index];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(VCZH_GCC) && defined(__clang__)
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\PARSINGTABLE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace stream
|
|
{
|
|
namespace internal
|
|
{
|
|
using namespace vl::parsing::tabling;
|
|
|
|
/***********************************************************************
|
|
ParsingTable (Serialization)
|
|
***********************************************************************/
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::AttributeInfo)
|
|
SERIALIZE(name)
|
|
SERIALIZE(arguments)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::AttributeInfoList)
|
|
SERIALIZE(attributes)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::TreeTypeInfo)
|
|
SERIALIZE(type)
|
|
SERIALIZE(attributeIndex)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::TreeFieldInfo)
|
|
SERIALIZE(type)
|
|
SERIALIZE(field)
|
|
SERIALIZE(attributeIndex)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::TokenInfo)
|
|
SERIALIZE(name)
|
|
SERIALIZE(regex)
|
|
SERIALIZE(regexTokenIndex)
|
|
SERIALIZE(attributeIndex)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::StateInfo)
|
|
SERIALIZE(ruleName)
|
|
SERIALIZE(stateName)
|
|
SERIALIZE(stateExpression)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::RuleInfo)
|
|
SERIALIZE(name)
|
|
SERIALIZE(type)
|
|
SERIALIZE(ambiguousType)
|
|
SERIALIZE(rootStartState)
|
|
SERIALIZE(attributeIndex)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::Instruction)
|
|
SERIALIZE(instructionType)
|
|
SERIALIZE(stateParameter)
|
|
SERIALIZE(nameParameter)
|
|
SERIALIZE(value)
|
|
SERIALIZE(creatorRule)
|
|
END_SERIALIZATION
|
|
|
|
SERIALIZE_ENUM(ParsingTable::Instruction::InstructionType)
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::LookAheadInfo)
|
|
SERIALIZE(tokens)
|
|
SERIALIZE(state)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::TransitionItem)
|
|
SERIALIZE(token)
|
|
SERIALIZE(targetState)
|
|
SERIALIZE(lookAheads)
|
|
SERIALIZE(stackPattern)
|
|
SERIALIZE(instructions)
|
|
END_SERIALIZATION
|
|
|
|
BEGIN_SERIALIZATION(ParsingTable::TransitionBag)
|
|
SERIALIZE(transitionItems)
|
|
END_SERIALIZATION
|
|
}
|
|
}
|
|
|
|
namespace parsing
|
|
{
|
|
namespace tabling
|
|
{
|
|
using namespace collections;
|
|
using namespace regex;
|
|
|
|
#ifdef VCZH_GCC
|
|
const vint ParsingTable::TokenBegin;
|
|
const vint ParsingTable::TokenFinish;
|
|
const vint ParsingTable::NormalReduce;
|
|
const vint ParsingTable::LeftRecursiveReduce;
|
|
const vint ParsingTable::UserTokenStart;
|
|
#endif
|
|
|
|
/***********************************************************************
|
|
ParsingTable::AttributeInfoList
|
|
***********************************************************************/
|
|
|
|
Ptr<ParsingTable::AttributeInfo> ParsingTable::AttributeInfoList::FindFirst(const WString& name)
|
|
{
|
|
for(vint i=0;i<attributes.Count();i++)
|
|
{
|
|
if(attributes[i]->name==name)
|
|
{
|
|
return attributes[i];
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTable::LookAheadInfo
|
|
***********************************************************************/
|
|
|
|
ParsingTable::LookAheadInfo::PrefixResult ParsingTable::LookAheadInfo::TestPrefix(Ptr<LookAheadInfo> a, Ptr<LookAheadInfo> b)
|
|
{
|
|
if(a->tokens.Count()>b->tokens.Count())
|
|
{
|
|
return ParsingTable::LookAheadInfo::NotPrefix;
|
|
}
|
|
for(vint i=0;i<a->tokens.Count();i++)
|
|
{
|
|
if(a->tokens[i]!=b->tokens[i])
|
|
{
|
|
return ParsingTable::LookAheadInfo::NotPrefix;
|
|
}
|
|
}
|
|
return a->tokens.Count()<b->tokens.Count()?ParsingTable::LookAheadInfo::Prefix:ParsingTable::LookAheadInfo::Equal;
|
|
}
|
|
|
|
void ParsingTable::LookAheadInfo::WalkInternal(Ptr<ParsingTable> table, Ptr<LookAheadInfo> previous, vint state, collections::SortedList<vint>& walkedStates, collections::List<Ptr<LookAheadInfo>>& newInfos)
|
|
{
|
|
if (walkedStates.Contains(state)) return;
|
|
walkedStates.Add(state);
|
|
|
|
for (vint i = 0; i < table->GetTokenCount(); i++)
|
|
{
|
|
if(Ptr<TransitionBag> bag=table->GetTransitionBag(state, i))
|
|
{
|
|
FOREACH(Ptr<TransitionItem>, item, bag->transitionItems)
|
|
{
|
|
if (i == ParsingTable::NormalReduce || i == ParsingTable::LeftRecursiveReduce)
|
|
{
|
|
WalkInternal(table, previous, item->targetState, walkedStates, newInfos);
|
|
}
|
|
else
|
|
{
|
|
Ptr<LookAheadInfo> info=new LookAheadInfo;
|
|
info->state=item->targetState;
|
|
if(previous)
|
|
{
|
|
CopyFrom(info->tokens, previous->tokens);
|
|
}
|
|
info->tokens.Add(i);
|
|
newInfos.Add(info);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
walkedStates.Remove(state);
|
|
}
|
|
|
|
void ParsingTable::LookAheadInfo::Walk(Ptr<ParsingTable> table, Ptr<LookAheadInfo> previous, vint state, collections::List<Ptr<LookAheadInfo>>& newInfos)
|
|
{
|
|
SortedList<vint> walkedStates;
|
|
WalkInternal(table, previous, state, walkedStates, newInfos);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTable::TransitionItem
|
|
***********************************************************************/
|
|
|
|
enum TransitionLevel
|
|
{
|
|
ReduceTransition,
|
|
LeftRecursiveReduceTransition,
|
|
NormalTransition,
|
|
};
|
|
|
|
TransitionLevel GetTransitionLevel(Ptr<ParsingTable::TransitionItem> t)
|
|
{
|
|
bool hasReduce=false;
|
|
bool hasLrReduce=false;
|
|
FOREACH(ParsingTable::Instruction, ins, t->instructions)
|
|
{
|
|
switch(ins.instructionType)
|
|
{
|
|
case ParsingTable::Instruction::Reduce:
|
|
hasReduce=true;
|
|
break;
|
|
case ParsingTable::Instruction::LeftRecursiveReduce:
|
|
hasLrReduce=true;
|
|
break;
|
|
default:;
|
|
}
|
|
}
|
|
|
|
return
|
|
hasLrReduce?LeftRecursiveReduceTransition:
|
|
hasReduce?ReduceTransition:
|
|
NormalTransition;
|
|
}
|
|
|
|
ParsingTable::TransitionItem::OrderResult ParsingTable::TransitionItem::CheckOrder(Ptr<TransitionItem> t1, Ptr<TransitionItem> t2, OrderResult defaultResult)
|
|
{
|
|
if(t1->token!=t2->token) return UnknownOrder;
|
|
if (defaultResult != UnknownOrder)
|
|
{
|
|
TransitionLevel level1 = GetTransitionLevel(t1);
|
|
TransitionLevel level2 = GetTransitionLevel(t2);
|
|
if (level1 > level2) return CorrectOrder;
|
|
if (level1 < level2) return WrongOrder;
|
|
}
|
|
|
|
vint ic1=t1->stackPattern.Count();
|
|
vint ic2=t2->stackPattern.Count();
|
|
vint ic=ic1<ic2?ic1:ic2;
|
|
|
|
for(vint i=0;i<ic;i++)
|
|
{
|
|
vint s1=t1->stackPattern[i];
|
|
vint s2=t2->stackPattern[i];
|
|
|
|
if(s1>s2)
|
|
{
|
|
return CorrectOrder;
|
|
}
|
|
else if(s1<s2)
|
|
{
|
|
return WrongOrder;
|
|
}
|
|
}
|
|
|
|
if(t1->token==TokenFinish)
|
|
{
|
|
if(ic1>ic2)
|
|
{
|
|
return CorrectOrder;
|
|
}
|
|
else if(ic1<ic2)
|
|
{
|
|
return WrongOrder;
|
|
}
|
|
}
|
|
return defaultResult;
|
|
}
|
|
|
|
vint ParsingTable::TransitionItem::Compare(Ptr<TransitionItem> t1, Ptr<TransitionItem> t2, OrderResult defaultResult)
|
|
{
|
|
OrderResult order=CheckOrder(t1, t2, defaultResult);
|
|
switch(order)
|
|
{
|
|
case CorrectOrder: return -1;
|
|
case WrongOrder: return 1;
|
|
default: return 0;
|
|
}
|
|
}
|
|
|
|
template<typename TIO>
|
|
void ParsingTable::IO(TIO& io)
|
|
{
|
|
io
|
|
<< ambiguity
|
|
<< attributeInfos
|
|
<< treeTypeInfos
|
|
<< treeFieldInfos
|
|
<< tokenCount
|
|
<< stateCount
|
|
<< tokenInfos
|
|
<< discardTokenInfos
|
|
<< stateInfos
|
|
<< ruleInfos
|
|
<< transitionBags
|
|
;
|
|
}
|
|
|
|
ParsingTable::ParsingTable(stream::IStream& input)
|
|
{
|
|
stream::internal::ContextFreeReader reader(input);
|
|
IO(reader);
|
|
}
|
|
|
|
void ParsingTable::Serialize(stream::IStream& output)
|
|
{
|
|
stream::internal::ContextFreeWriter writer(output);
|
|
IO(writer);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTable
|
|
***********************************************************************/
|
|
|
|
#if defined(VCZH_GCC) && defined(__clang__)
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wnull-dereference"
|
|
#endif
|
|
|
|
ParsingTable::ParsingTable(vint _attributeInfoCount, vint _treeTypeInfoCount, vint _treeFieldInfoCount, vint _tokenCount, vint discardTokenCount, vint _stateCount, vint _ruleCount)
|
|
:ambiguity(false)
|
|
,tokenCount(_tokenCount+UserTokenStart)
|
|
,stateCount(_stateCount)
|
|
,attributeInfos(_attributeInfoCount)
|
|
,treeTypeInfos(_treeTypeInfoCount)
|
|
,treeFieldInfos(_treeFieldInfoCount)
|
|
,tokenInfos(_tokenCount+UserTokenStart)
|
|
,discardTokenInfos(discardTokenCount)
|
|
,stateInfos(_stateCount)
|
|
,ruleInfos(_ruleCount)
|
|
,transitionBags((_tokenCount+UserTokenStart)*_stateCount)
|
|
{
|
|
}
|
|
|
|
ParsingTable::~ParsingTable()
|
|
{
|
|
}
|
|
|
|
bool ParsingTable::GetAmbiguity()
|
|
{
|
|
return ambiguity;
|
|
}
|
|
|
|
void ParsingTable::SetAmbiguity(bool value)
|
|
{
|
|
ambiguity=value;
|
|
}
|
|
|
|
vint ParsingTable::GetAttributeInfoCount()
|
|
{
|
|
return attributeInfos.Count();
|
|
}
|
|
|
|
Ptr<ParsingTable::AttributeInfoList> ParsingTable::GetAttributeInfo(vint index)
|
|
{
|
|
return attributeInfos[index];
|
|
}
|
|
|
|
void ParsingTable::SetAttributeInfo(vint index, Ptr<AttributeInfoList> info)
|
|
{
|
|
attributeInfos[index]=info;
|
|
}
|
|
|
|
vint ParsingTable::GetTreeTypeInfoCount()
|
|
{
|
|
return treeTypeInfos.Count();
|
|
}
|
|
|
|
const ParsingTable::TreeTypeInfo& ParsingTable::GetTreeTypeInfo(vint index)
|
|
{
|
|
return treeTypeInfos[index];
|
|
}
|
|
|
|
const ParsingTable::TreeTypeInfo& ParsingTable::GetTreeTypeInfo(const WString& type)
|
|
{
|
|
vint index=treeTypeInfoMap.Keys().IndexOf(type);
|
|
if(index==-1) return *(const TreeTypeInfo*)0;
|
|
return treeTypeInfos[treeTypeInfoMap.Values().Get(index)];
|
|
}
|
|
|
|
void ParsingTable::SetTreeTypeInfo(vint index, const TreeTypeInfo& info)
|
|
{
|
|
treeTypeInfos[index]=info;
|
|
}
|
|
|
|
vint ParsingTable::GetTreeFieldInfoCount()
|
|
{
|
|
return treeFieldInfos.Count();
|
|
}
|
|
|
|
const ParsingTable::TreeFieldInfo& ParsingTable::GetTreeFieldInfo(vint index)
|
|
{
|
|
return treeFieldInfos[index];
|
|
}
|
|
|
|
const ParsingTable::TreeFieldInfo& ParsingTable::GetTreeFieldInfo(const WString& type, const WString& field)
|
|
{
|
|
Pair<WString, WString> key(type, field);
|
|
vint index=treeFieldInfoMap.Keys().IndexOf(key);
|
|
if(index==-1) return *(const TreeFieldInfo*)0;
|
|
return treeFieldInfos[treeFieldInfoMap.Values().Get(index)];
|
|
}
|
|
|
|
void ParsingTable::SetTreeFieldInfo(vint index, const TreeFieldInfo& info)
|
|
{
|
|
treeFieldInfos[index]=info;
|
|
}
|
|
|
|
vint ParsingTable::GetTokenCount()
|
|
{
|
|
return tokenCount;
|
|
}
|
|
|
|
const ParsingTable::TokenInfo& ParsingTable::GetTokenInfo(vint token)
|
|
{
|
|
return tokenInfos[token];
|
|
}
|
|
|
|
void ParsingTable::SetTokenInfo(vint token, const TokenInfo& info)
|
|
{
|
|
tokenInfos[token]=info;
|
|
}
|
|
|
|
vint ParsingTable::GetDiscardTokenCount()
|
|
{
|
|
return discardTokenInfos.Count();
|
|
}
|
|
|
|
const ParsingTable::TokenInfo& ParsingTable::GetDiscardTokenInfo(vint token)
|
|
{
|
|
return discardTokenInfos[token];
|
|
}
|
|
|
|
void ParsingTable::SetDiscardTokenInfo(vint token, const TokenInfo& info)
|
|
{
|
|
discardTokenInfos[token]=info;
|
|
}
|
|
|
|
vint ParsingTable::GetStateCount()
|
|
{
|
|
return stateCount;
|
|
}
|
|
|
|
const ParsingTable::StateInfo& ParsingTable::GetStateInfo(vint state)
|
|
{
|
|
return stateInfos[state];
|
|
}
|
|
|
|
void ParsingTable::SetStateInfo(vint state, const StateInfo& info)
|
|
{
|
|
stateInfos[state]=info;
|
|
}
|
|
|
|
vint ParsingTable::GetRuleCount()
|
|
{
|
|
return ruleInfos.Count();
|
|
}
|
|
|
|
const ParsingTable::RuleInfo& ParsingTable::GetRuleInfo(const WString& ruleName)
|
|
{
|
|
vint index=ruleMap.Keys().IndexOf(ruleName);
|
|
if(index==-1) return *(const RuleInfo*)0;
|
|
return ruleInfos[ruleMap.Values().Get(index)];
|
|
}
|
|
|
|
const ParsingTable::RuleInfo& ParsingTable::GetRuleInfo(vint rule)
|
|
{
|
|
return ruleInfos[rule];
|
|
}
|
|
|
|
void ParsingTable::SetRuleInfo(vint rule, const RuleInfo& info)
|
|
{
|
|
ruleInfos[rule]=info;
|
|
}
|
|
|
|
const regex::RegexLexer& ParsingTable::GetLexer()
|
|
{
|
|
return *lexer.Obj();
|
|
}
|
|
|
|
Ptr<ParsingTable::TransitionBag> ParsingTable::GetTransitionBag(vint state, vint token)
|
|
{
|
|
return transitionBags[state*tokenCount+token];
|
|
}
|
|
|
|
void ParsingTable::SetTransitionBag(vint state, vint token, Ptr<TransitionBag> bag)
|
|
{
|
|
transitionBags[state*tokenCount+token]=bag;
|
|
}
|
|
|
|
void ParsingTable::Initialize()
|
|
{
|
|
List<WString> tokens;
|
|
FOREACH(TokenInfo, info, From(tokenInfos).Skip(UserTokenStart))
|
|
{
|
|
tokens.Add(info.regex);
|
|
}
|
|
FOREACH(TokenInfo, info, discardTokenInfos)
|
|
{
|
|
tokens.Add(info.regex);
|
|
}
|
|
|
|
vint regexTokenIndex = 0;
|
|
for (vint i = UserTokenStart; i < tokenInfos.Count(); i++)
|
|
{
|
|
tokenInfos[i].regexTokenIndex = regexTokenIndex++;
|
|
}
|
|
for (vint i = 0; i < discardTokenInfos.Count(); i++)
|
|
{
|
|
discardTokenInfos[i].regexTokenIndex = regexTokenIndex++;
|
|
}
|
|
lexer = new RegexLexer(tokens, {});
|
|
|
|
ruleMap.Clear();
|
|
FOREACH_INDEXER(RuleInfo, rule, index, ruleInfos)
|
|
{
|
|
ruleMap.Add(rule.name, index);
|
|
}
|
|
for (vint i = 0; i < stateInfos.Count(); i++)
|
|
{
|
|
StateInfo& info = stateInfos[i];
|
|
info.ruleAmbiguousType = ruleInfos[ruleMap[info.ruleName]].ambiguousType;
|
|
}
|
|
|
|
treeTypeInfoMap.Clear();
|
|
FOREACH_INDEXER(TreeTypeInfo, info, index, treeTypeInfos)
|
|
{
|
|
treeTypeInfoMap.Add(info.type, index);
|
|
}
|
|
|
|
treeFieldInfoMap.Clear();
|
|
FOREACH_INDEXER(TreeFieldInfo, info, index, treeFieldInfos)
|
|
{
|
|
Pair<WString, WString> key(info.type, info.field);
|
|
treeFieldInfoMap.Add(key, index);
|
|
}
|
|
}
|
|
|
|
bool ParsingTable::IsInputToken(vint regexTokenIndex)
|
|
{
|
|
return regexTokenIndex>=0 && regexTokenIndex<tokenCount-UserTokenStart;
|
|
}
|
|
|
|
vint ParsingTable::GetTableTokenIndex(vint regexTokenIndex)
|
|
{
|
|
return IsInputToken(regexTokenIndex)?regexTokenIndex+UserTokenStart:-1;
|
|
}
|
|
|
|
vint ParsingTable::GetTableDiscardTokenIndex(vint regexTokenIndex)
|
|
{
|
|
return regexTokenIndex>=tokenCount-UserTokenStart?regexTokenIndex-(tokenCount-UserTokenStart):-1;
|
|
}
|
|
|
|
#if defined(VCZH_GCC) && defined(__clang__)
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\PARSINGTREE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
#if defined(VCZH_GCC) && defined(__clang__)
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wnull-dereference"
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
using namespace collections;
|
|
|
|
namespace parsing
|
|
{
|
|
vint CompareTextRange(Ptr<ParsingTreeNode> r1, Ptr<ParsingTreeNode> r2)
|
|
{
|
|
return ParsingTextPos::Compare(r1->GetCodeRange().start, r2->GetCodeRange().start);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTreeNode::TraversalVisitor
|
|
***********************************************************************/
|
|
|
|
ParsingTreeNode::TraversalVisitor::TraversalVisitor(TraverseDirection _direction)
|
|
:direction(_direction)
|
|
{
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::BeforeVisit(ParsingTreeToken* node)
|
|
{
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::AfterVisit(ParsingTreeToken* node)
|
|
{
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::BeforeVisit(ParsingTreeObject* node)
|
|
{
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::AfterVisit(ParsingTreeObject* node)
|
|
{
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::BeforeVisit(ParsingTreeArray* node)
|
|
{
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::AfterVisit(ParsingTreeArray* node)
|
|
{
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::Visit(ParsingTreeToken* node)
|
|
{
|
|
BeforeVisit(node);
|
|
AfterVisit(node);
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::Visit(ParsingTreeObject* node)
|
|
{
|
|
BeforeVisit(node);
|
|
switch(direction)
|
|
{
|
|
case TraverseDirection::ByTextPosition:
|
|
{
|
|
FOREACH(Ptr<ParsingTreeNode>, node, node->GetSubNodes())
|
|
{
|
|
node->Accept(this);
|
|
}
|
|
}
|
|
break;
|
|
case TraverseDirection::ByStorePosition:
|
|
{
|
|
FOREACH(Ptr<ParsingTreeNode>, node, node->GetMembers().Values())
|
|
{
|
|
node->Accept(this);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
AfterVisit(node);
|
|
}
|
|
|
|
void ParsingTreeNode::TraversalVisitor::Visit(ParsingTreeArray* node)
|
|
{
|
|
BeforeVisit(node);
|
|
switch(direction)
|
|
{
|
|
case TraverseDirection::ByTextPosition:
|
|
{
|
|
FOREACH(Ptr<ParsingTreeNode>, node, node->GetSubNodes())
|
|
{
|
|
node->Accept(this);
|
|
}
|
|
}
|
|
break;
|
|
case TraverseDirection::ByStorePosition:
|
|
{
|
|
FOREACH(Ptr<ParsingTreeNode>, node, node->GetItems())
|
|
{
|
|
node->Accept(this);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
AfterVisit(node);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTreeNode
|
|
***********************************************************************/
|
|
|
|
bool ParsingTreeNode::BeforeAddChild(Ptr<ParsingTreeNode> node)
|
|
{
|
|
return node->parent==0;
|
|
}
|
|
|
|
void ParsingTreeNode::AfterAddChild(Ptr<ParsingTreeNode> node)
|
|
{
|
|
node->parent=this;
|
|
ClearQueryCache();
|
|
}
|
|
|
|
bool ParsingTreeNode::BeforeRemoveChild(Ptr<ParsingTreeNode> node)
|
|
{
|
|
return node->parent!=0;
|
|
}
|
|
|
|
void ParsingTreeNode::AfterRemoveChild(Ptr<ParsingTreeNode> node)
|
|
{
|
|
node->parent=0;
|
|
ClearQueryCache();
|
|
}
|
|
|
|
ParsingTreeNode::ParsingTreeNode(const ParsingTextRange& _codeRange)
|
|
:codeRange(_codeRange)
|
|
,parent(0)
|
|
{
|
|
}
|
|
|
|
ParsingTreeNode::~ParsingTreeNode()
|
|
{
|
|
}
|
|
|
|
ParsingTextRange ParsingTreeNode::GetCodeRange()
|
|
{
|
|
return codeRange;
|
|
}
|
|
|
|
void ParsingTreeNode::SetCodeRange(const ParsingTextRange& range)
|
|
{
|
|
codeRange=range;
|
|
}
|
|
|
|
void ParsingTreeNode::InitializeQueryCache()
|
|
{
|
|
const NodeList& subNodes=GetSubNodesInternal();
|
|
ClearQueryCache();
|
|
auto subNodesExists = &subNodes;
|
|
if(subNodesExists)
|
|
{
|
|
FOREACH(Ptr<ParsingTreeNode>, node, subNodes)
|
|
{
|
|
node->InitializeQueryCache();
|
|
}
|
|
|
|
//if (codeRange.start.IsInvalid() || codeRange.start.IsInvalid())
|
|
{
|
|
FOREACH(Ptr<ParsingTreeNode>, subNode, subNodes)
|
|
{
|
|
const auto& subRange = subNode->codeRange;
|
|
const auto& min = !subRange.start.IsInvalid() ? subRange.start : subRange.end;
|
|
const auto& max = !subRange.end.IsInvalid() ? subRange.end : subRange.start;
|
|
|
|
if (codeRange.start.IsInvalid() || (!min.IsInvalid() && codeRange.start > min))
|
|
{
|
|
codeRange.start = min;
|
|
}
|
|
if (codeRange.end.IsInvalid() || (!max.IsInvalid() && codeRange.end < max))
|
|
{
|
|
codeRange.end = max;
|
|
}
|
|
}
|
|
}
|
|
|
|
CopyFrom(
|
|
cachedOrderedSubNodes,
|
|
From(subNodes)
|
|
.Where([=](Ptr<ParsingTreeNode> node)
|
|
{
|
|
const auto& range = node->GetCodeRange();
|
|
return !range.start.IsInvalid() && !range.end.IsInvalid();
|
|
})
|
|
.OrderBy(&CompareTextRange)
|
|
);
|
|
}
|
|
}
|
|
|
|
void ParsingTreeNode::ClearQueryCache()
|
|
{
|
|
cachedOrderedSubNodes.Clear();
|
|
}
|
|
|
|
ParsingTreeNode* ParsingTreeNode::GetParent()
|
|
{
|
|
return parent;
|
|
}
|
|
|
|
const ParsingTreeNode::NodeList& ParsingTreeNode::GetSubNodes()
|
|
{
|
|
return cachedOrderedSubNodes;
|
|
}
|
|
|
|
ParsingTreeNode* ParsingTreeNode::FindSubNode(const ParsingTextPos& position)
|
|
{
|
|
return FindSubNode(ParsingTextRange(position, position));
|
|
}
|
|
|
|
ParsingTreeNode* ParsingTreeNode::FindSubNode(const ParsingTextRange& range)
|
|
{
|
|
if (codeRange.start <= range.start && range.end <= codeRange.end)
|
|
{
|
|
vint start = 0;
|
|
vint end = cachedOrderedSubNodes.Count() - 1;
|
|
while (start <= end)
|
|
{
|
|
vint selected = (start + end) / 2;
|
|
ParsingTreeNode* selectedNode = cachedOrderedSubNodes[selected].Obj();
|
|
const ParsingTextRange& selectedRange = selectedNode->codeRange;
|
|
if (range.end<selectedRange.start)
|
|
{
|
|
end = selected - 1;
|
|
}
|
|
else if (range.start>selectedRange.end)
|
|
{
|
|
start = selected + 1;
|
|
}
|
|
else if (selectedRange.start <= range.start && range.end <= selectedRange.end)
|
|
{
|
|
return selectedNode;
|
|
}
|
|
else
|
|
{
|
|
return this;
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
ParsingTreeNode* ParsingTreeNode::FindDeepestNode(const ParsingTextPos& position)
|
|
{
|
|
return FindDeepestNode(ParsingTextRange(position, position));
|
|
}
|
|
|
|
ParsingTreeNode* ParsingTreeNode::FindDeepestNode(const ParsingTextRange& range)
|
|
{
|
|
ParsingTreeNode* result=0;
|
|
ParsingTreeNode* node=this;
|
|
do
|
|
{
|
|
result=node;
|
|
node=node->FindSubNode(range);
|
|
}while(result!=node);
|
|
return result;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTreeToken
|
|
***********************************************************************/
|
|
|
|
const ParsingTreeToken::NodeList& ParsingTreeToken::GetSubNodesInternal()
|
|
{
|
|
return *(NodeList*)0;
|
|
}
|
|
|
|
ParsingTreeToken::ParsingTreeToken(const WString& _value, vint _tokenIndex, const ParsingTextRange& _codeRange)
|
|
:ParsingTreeNode(_codeRange)
|
|
,value(_value)
|
|
,tokenIndex(_tokenIndex)
|
|
{
|
|
}
|
|
|
|
ParsingTreeToken::~ParsingTreeToken()
|
|
{
|
|
}
|
|
|
|
void ParsingTreeToken::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
Ptr<ParsingTreeNode> ParsingTreeToken::Clone()
|
|
{
|
|
Ptr<ParsingTreeToken> clone=new ParsingTreeToken(value, tokenIndex, codeRange);
|
|
return clone;
|
|
}
|
|
|
|
vint ParsingTreeToken::GetTokenIndex()
|
|
{
|
|
return tokenIndex;
|
|
}
|
|
|
|
void ParsingTreeToken::SetTokenIndex(vint _tokenIndex)
|
|
{
|
|
tokenIndex=_tokenIndex;
|
|
}
|
|
|
|
const WString& ParsingTreeToken::GetValue()
|
|
{
|
|
return value;
|
|
}
|
|
|
|
void ParsingTreeToken::SetValue(const WString& _value)
|
|
{
|
|
value=_value;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTreeObject
|
|
***********************************************************************/
|
|
|
|
const ParsingTreeObject::NodeList& ParsingTreeObject::GetSubNodesInternal()
|
|
{
|
|
return members.Values();
|
|
}
|
|
|
|
ParsingTreeObject::ParsingTreeObject(const WString& _type, const ParsingTextRange& _codeRange)
|
|
:ParsingTreeNode(_codeRange)
|
|
,type(_type)
|
|
{
|
|
}
|
|
|
|
ParsingTreeObject::~ParsingTreeObject()
|
|
{
|
|
}
|
|
|
|
void ParsingTreeObject::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
Ptr<ParsingTreeNode> ParsingTreeObject::Clone()
|
|
{
|
|
Ptr<ParsingTreeObject> clone=new ParsingTreeObject(type, codeRange);
|
|
CopyFrom(clone->rules, rules);
|
|
for(vint i=0;i<members.Count();i++)
|
|
{
|
|
WString name=members.Keys().Get(i);
|
|
Ptr<ParsingTreeNode> node=members.Values().Get(i)->Clone();
|
|
clone->SetMember(name, node);
|
|
}
|
|
return clone;
|
|
}
|
|
|
|
const WString& ParsingTreeObject::GetType()
|
|
{
|
|
return type;
|
|
}
|
|
|
|
void ParsingTreeObject::SetType(const WString& _type)
|
|
{
|
|
type=_type;
|
|
}
|
|
|
|
ParsingTreeObject::NodeMap& ParsingTreeObject::GetMembers()
|
|
{
|
|
return members;
|
|
}
|
|
|
|
Ptr<ParsingTreeNode> ParsingTreeObject::GetMember(const WString& name)
|
|
{
|
|
vint index=members.Keys().IndexOf(name);
|
|
if(index==-1) return 0;
|
|
return members.Values().Get(index);
|
|
}
|
|
|
|
bool ParsingTreeObject::SetMember(const WString& name, Ptr<ParsingTreeNode> node)
|
|
{
|
|
vint index=members.Keys().IndexOf(name);
|
|
if(index!=-1)
|
|
{
|
|
Ptr<ParsingTreeNode> previous=members.Values().Get(index);
|
|
if(previous==node) return true;
|
|
if(!BeforeRemoveChild(previous) || !BeforeAddChild(node)) return false;
|
|
members.Remove(name);
|
|
AfterRemoveChild(previous);
|
|
}
|
|
members.Add(name, node);
|
|
AfterAddChild(node);
|
|
return true;
|
|
}
|
|
|
|
bool ParsingTreeObject::RemoveMember(const WString& name)
|
|
{
|
|
vint index=members.Keys().IndexOf(name);
|
|
if(index!=-1)
|
|
{
|
|
Ptr<ParsingTreeNode> previous=members.Values().Get(index);
|
|
if(BeforeRemoveChild(previous))
|
|
{
|
|
members.Remove(name);
|
|
AfterRemoveChild(previous);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const ParsingTreeObject::NameList& ParsingTreeObject::GetMemberNames()
|
|
{
|
|
return members.Keys();
|
|
}
|
|
|
|
ParsingTreeObject::RuleList& ParsingTreeObject::GetCreatorRules()
|
|
{
|
|
return rules;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingTreeArray
|
|
***********************************************************************/
|
|
|
|
const ParsingTreeArray::NodeList& ParsingTreeArray::GetSubNodesInternal()
|
|
{
|
|
return items;
|
|
}
|
|
|
|
ParsingTreeArray::ParsingTreeArray(const WString& _elementType, const ParsingTextRange& _codeRange)
|
|
:ParsingTreeNode(_codeRange)
|
|
,elementType(_elementType)
|
|
{
|
|
}
|
|
|
|
ParsingTreeArray::~ParsingTreeArray()
|
|
{
|
|
}
|
|
|
|
void ParsingTreeArray::Accept(IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
Ptr<ParsingTreeNode> ParsingTreeArray::Clone()
|
|
{
|
|
Ptr<ParsingTreeArray> clone=new ParsingTreeArray(elementType, codeRange);
|
|
for(vint i=0;i<items.Count();i++)
|
|
{
|
|
Ptr<ParsingTreeNode> node=items.Get(i)->Clone();
|
|
clone->AddItem(node);
|
|
}
|
|
return clone;
|
|
}
|
|
|
|
const WString& ParsingTreeArray::GetElementType()
|
|
{
|
|
return elementType;
|
|
}
|
|
|
|
void ParsingTreeArray::SetElementType(const WString& _elementType)
|
|
{
|
|
elementType=_elementType;
|
|
}
|
|
|
|
ParsingTreeArray::NodeArray& ParsingTreeArray::GetItems()
|
|
{
|
|
return items;
|
|
}
|
|
|
|
Ptr<ParsingTreeNode> ParsingTreeArray::GetItem(vint index)
|
|
{
|
|
if(0<=index && index<items.Count())
|
|
{
|
|
return items[index];
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
bool ParsingTreeArray::SetItem(vint index, Ptr<ParsingTreeNode> node)
|
|
{
|
|
if(0<=index && index<items.Count())
|
|
{
|
|
items[index]=node;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ParsingTreeArray::AddItem(Ptr<ParsingTreeNode> node)
|
|
{
|
|
return InsertItem(items.Count(), node);
|
|
}
|
|
|
|
bool ParsingTreeArray::InsertItem(vint index, Ptr<ParsingTreeNode> node)
|
|
{
|
|
if(0<=index && index<=items.Count())
|
|
{
|
|
if(BeforeAddChild(node))
|
|
{
|
|
items.Insert(index, node);
|
|
AfterAddChild(node);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ParsingTreeArray::RemoveItem(vint index)
|
|
{
|
|
if(0<=index && index<items.Count())
|
|
{
|
|
Ptr<ParsingTreeNode> previous=items[index];
|
|
if(BeforeRemoveChild(previous))
|
|
{
|
|
items.RemoveAt(index);
|
|
AfterRemoveChild(previous);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ParsingTreeArray::RemoveItem(ParsingTreeNode* node)
|
|
{
|
|
return RemoveItem(items.IndexOf(node));
|
|
}
|
|
|
|
vint ParsingTreeArray::IndexOfItem(ParsingTreeNode* node)
|
|
{
|
|
return items.IndexOf(node);
|
|
}
|
|
|
|
bool ParsingTreeArray::ContainsItem(ParsingTreeNode* node)
|
|
{
|
|
return items.Contains(node);
|
|
}
|
|
|
|
vint ParsingTreeArray::Count()
|
|
{
|
|
return items.Count();
|
|
}
|
|
|
|
bool ParsingTreeArray::Clear()
|
|
{
|
|
FOREACH(Ptr<ParsingTreeNode>, node, items)
|
|
{
|
|
if(!BeforeRemoveChild(node)) return false;
|
|
}
|
|
FOREACH(Ptr<ParsingTreeNode>, node, items)
|
|
{
|
|
AfterRemoveChild(node);
|
|
}
|
|
items.Clear();
|
|
return true;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingError
|
|
***********************************************************************/
|
|
|
|
ParsingError::ParsingError()
|
|
:token(0)
|
|
,parsingTree(0)
|
|
{
|
|
}
|
|
|
|
ParsingError::ParsingError(const WString& _errorMessage)
|
|
:token(0)
|
|
,parsingTree(0)
|
|
,errorMessage(_errorMessage)
|
|
{
|
|
}
|
|
|
|
ParsingError::ParsingError(const regex::RegexToken* _token, const WString& _errorMessage)
|
|
:token(_token)
|
|
,parsingTree(0)
|
|
,errorMessage(_errorMessage)
|
|
{
|
|
if(token)
|
|
{
|
|
codeRange.start.row=_token->rowStart;
|
|
codeRange.start.column=_token->columnStart;
|
|
codeRange.start.index=_token->start;
|
|
codeRange.end.row=_token->rowEnd;
|
|
codeRange.end.column=_token->columnEnd;
|
|
codeRange.end.index=_token->start+_token->length-1;
|
|
codeRange.codeIndex = _token->codeIndex;
|
|
}
|
|
}
|
|
|
|
ParsingError::ParsingError(ParsingTreeCustomBase* _parsingTree, const WString& _errorMessage)
|
|
:codeRange(_parsingTree->codeRange)
|
|
,token(0)
|
|
,parsingTree(_parsingTree)
|
|
,errorMessage(_errorMessage)
|
|
{
|
|
}
|
|
|
|
ParsingError::~ParsingError()
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingEmptyPrintNodeRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingEmptyPrintNodeRecorder::ParsingEmptyPrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
ParsingEmptyPrintNodeRecorder::~ParsingEmptyPrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingEmptyPrintNodeRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingMultiplePrintNodeRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingMultiplePrintNodeRecorder::ParsingMultiplePrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
ParsingMultiplePrintNodeRecorder::~ParsingMultiplePrintNodeRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingMultiplePrintNodeRecorder::AddRecorder(Ptr<IParsingPrintNodeRecorder> recorder)
|
|
{
|
|
recorders.Add(recorder);
|
|
}
|
|
|
|
void ParsingMultiplePrintNodeRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)
|
|
{
|
|
FOREACH(Ptr<IParsingPrintNodeRecorder>, recorder, recorders)
|
|
{
|
|
recorder->Record(node, range);
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingOriginalLocationRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingOriginalLocationRecorder::ParsingOriginalLocationRecorder(Ptr<IParsingPrintNodeRecorder> _recorder)
|
|
:recorder(_recorder)
|
|
{
|
|
}
|
|
|
|
ParsingOriginalLocationRecorder::~ParsingOriginalLocationRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingOriginalLocationRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)
|
|
{
|
|
auto codeRange = node->codeRange;
|
|
codeRange.codeIndex = range.codeIndex;
|
|
recorder->Record(node, codeRange);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingGeneratedLocationRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingGeneratedLocationRecorder::ParsingGeneratedLocationRecorder(RangeMap& _rangeMap)
|
|
:rangeMap(_rangeMap)
|
|
{
|
|
}
|
|
|
|
ParsingGeneratedLocationRecorder::~ParsingGeneratedLocationRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingGeneratedLocationRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)
|
|
{
|
|
rangeMap.Add(node, range);
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingUpdateLocationRecorder
|
|
***********************************************************************/
|
|
|
|
ParsingUpdateLocationRecorder::ParsingUpdateLocationRecorder()
|
|
{
|
|
}
|
|
|
|
ParsingUpdateLocationRecorder::~ParsingUpdateLocationRecorder()
|
|
{
|
|
}
|
|
|
|
void ParsingUpdateLocationRecorder::Record(ParsingTreeCustomBase* node, const ParsingTextRange& range)
|
|
{
|
|
node->codeRange = range;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingWriter
|
|
***********************************************************************/
|
|
|
|
void ParsingWriter::HandleChar(wchar_t c)
|
|
{
|
|
lastPos = currentPos;
|
|
switch (c)
|
|
{
|
|
case L'\n':
|
|
currentPos.index++;
|
|
currentPos.row++;
|
|
currentPos.column = 0;
|
|
break;
|
|
default:
|
|
currentPos.index++;
|
|
currentPos.column++;
|
|
}
|
|
}
|
|
|
|
ParsingWriter::ParsingWriter(stream::TextWriter& _writer, Ptr<IParsingPrintNodeRecorder> _recorder, vint _codeIndex)
|
|
:writer(_writer)
|
|
, recorder(_recorder)
|
|
, codeIndex(_codeIndex)
|
|
, lastPos(-1, 0, -1)
|
|
, currentPos(0, 0, 0)
|
|
{
|
|
}
|
|
|
|
ParsingWriter::~ParsingWriter()
|
|
{
|
|
}
|
|
|
|
void ParsingWriter::WriteChar(wchar_t c)
|
|
{
|
|
writer.WriteChar(c);
|
|
if (!recorder) return;
|
|
HandleChar(c);
|
|
}
|
|
|
|
void ParsingWriter::WriteString(const wchar_t* string, vint charCount)
|
|
{
|
|
writer.WriteString(string, charCount);
|
|
if (!recorder) return;
|
|
for (vint i = 0; i < charCount; i++)
|
|
{
|
|
HandleChar(string[i]);
|
|
}
|
|
}
|
|
|
|
void ParsingWriter::BeforePrint(ParsingTreeCustomBase* node)
|
|
{
|
|
if (!recorder) return;
|
|
nodePositions.Add(NodePosPair(node, currentPos));
|
|
}
|
|
|
|
void ParsingWriter::AfterPrint(ParsingTreeCustomBase* node)
|
|
{
|
|
if (!recorder) return;
|
|
|
|
auto pair = nodePositions[nodePositions.Count() - 1];
|
|
nodePositions.RemoveAt(nodePositions.Count() - 1);
|
|
CHECK_ERROR(pair.key == node, L"vl::parsing::ParsingWriter::AfterPrint(ParsingTreeNode*)#BeforePrint and AfterPrint should be call in pairs.");
|
|
|
|
ParsingTextRange range(pair.value, lastPos, codeIndex);
|
|
recorder->Record(node, range);
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(VCZH_GCC) && defined(__clang__)
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\PARSINGJSON.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace json
|
|
{
|
|
using namespace stream;
|
|
using namespace collections;
|
|
|
|
/***********************************************************************
|
|
Unescaping Function Foward Declarations
|
|
***********************************************************************/
|
|
|
|
void JsonUnescapingString(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
value.value = GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
JsonUnescapeString(value.value.Sub(1, value.value.Length() - 2), writer);
|
|
});
|
|
}
|
|
|
|
/***********************************************************************
|
|
JsonPrintVisitor
|
|
***********************************************************************/
|
|
|
|
class JsonPrintVisitor : public Object, public JsonNode::IVisitor
|
|
{
|
|
public:
|
|
TextWriter& writer;
|
|
|
|
JsonPrintVisitor(TextWriter& _writer)
|
|
:writer(_writer)
|
|
{
|
|
}
|
|
|
|
void Visit(JsonLiteral* node)
|
|
{
|
|
switch(node->value)
|
|
{
|
|
case JsonLiteral::JsonValue::True:
|
|
writer.WriteString(L"true");
|
|
break;
|
|
case JsonLiteral::JsonValue::False:
|
|
writer.WriteString(L"false");
|
|
break;
|
|
case JsonLiteral::JsonValue::Null:
|
|
writer.WriteString(L"null");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Visit(JsonString* node)
|
|
{
|
|
writer.WriteChar(L'\"');
|
|
JsonEscapeString(node->content.value, writer);
|
|
writer.WriteChar(L'\"');
|
|
}
|
|
|
|
void Visit(JsonNumber* node)
|
|
{
|
|
writer.WriteString(node->content.value);
|
|
}
|
|
|
|
void Visit(JsonArray* node)
|
|
{
|
|
writer.WriteChar(L'[');
|
|
FOREACH_INDEXER(Ptr<JsonNode>, item, i, node->items)
|
|
{
|
|
if(i>0) writer.WriteChar(L',');
|
|
item->Accept(this);
|
|
}
|
|
writer.WriteChar(L']');
|
|
}
|
|
|
|
void Visit(JsonObjectField* node)
|
|
{
|
|
writer.WriteChar(L'\"');
|
|
JsonEscapeString(node->name.value, writer);
|
|
writer.WriteString(L"\":");
|
|
node->value->Accept(this);
|
|
}
|
|
|
|
void Visit(JsonObject* node)
|
|
{
|
|
writer.WriteChar(L'{');
|
|
FOREACH_INDEXER(Ptr<JsonObjectField>, field, i, node->fields)
|
|
{
|
|
if(i>0) writer.WriteChar(L',');
|
|
field->Accept(this);
|
|
}
|
|
writer.WriteChar(L'}');
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
API
|
|
***********************************************************************/
|
|
|
|
void JsonEscapeString(const WString& text, stream::TextWriter& writer)
|
|
{
|
|
const wchar_t* reading=text.Buffer();
|
|
while(wchar_t c=*reading++)
|
|
{
|
|
switch(c)
|
|
{
|
|
case L'\"': writer.WriteString(L"\\\""); break;
|
|
case L'\\': writer.WriteString(L"\\\\"); break;
|
|
case L'/': writer.WriteString(L"\\/"); break;
|
|
case L'\b': writer.WriteString(L"\\b"); break;
|
|
case L'\f': writer.WriteString(L"\\f"); break;
|
|
case L'\n': writer.WriteString(L"\\n"); break;
|
|
case L'\r': writer.WriteString(L"\\r"); break;
|
|
case L'\t': writer.WriteString(L"\\t"); break;
|
|
default: writer.WriteChar(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
vuint16_t GetHex(wchar_t c)
|
|
{
|
|
if(L'0'<=c && c<=L'9')
|
|
{
|
|
return c-L'0';
|
|
}
|
|
else if(L'A'<=c && c<=L'F')
|
|
{
|
|
return c-L'A';
|
|
}
|
|
else if(L'a'<=c && c<=L'f')
|
|
{
|
|
return c-L'a';
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void JsonUnescapeString(const WString& text, stream::TextWriter& writer)
|
|
{
|
|
const wchar_t* reading=text.Buffer();
|
|
while(wchar_t c=*reading++)
|
|
{
|
|
if(c==L'\\' && *reading)
|
|
{
|
|
switch(c=*reading++)
|
|
{
|
|
case L'b': writer.WriteChar(L'\b'); break;
|
|
case L'f': writer.WriteChar(L'\f'); break;
|
|
case L'n': writer.WriteChar(L'\n'); break;
|
|
case L'r': writer.WriteChar(L'\r'); break;
|
|
case L't': writer.WriteChar(L'\t'); break;
|
|
case L'u':
|
|
{
|
|
wchar_t h1, h2, h3, h4;
|
|
if((h1=reading[0]) && (h2=reading[1]) && (h3=reading[2]) && (h4=reading[3]))
|
|
{
|
|
reading+=4;
|
|
wchar_t h=(wchar_t)(vuint16_t)(
|
|
(GetHex(h1)<<12) +
|
|
(GetHex(h2)<<8) +
|
|
(GetHex(h3)<<4) +
|
|
(GetHex(h4)<<0)
|
|
);
|
|
writer.WriteChar(h);
|
|
}
|
|
}
|
|
break;
|
|
default: writer.WriteChar(c);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
writer.WriteChar(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
void JsonPrint(Ptr<JsonNode> node, stream::TextWriter& writer)
|
|
{
|
|
JsonPrintVisitor visitor(writer);
|
|
node->Accept(&visitor);
|
|
}
|
|
|
|
WString JsonToString(Ptr<JsonNode> node)
|
|
{
|
|
return GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
JsonPrint(node, writer);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\PARSINGJSON_AST.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingJson.parser.txt
|
|
|
|
This file is generated by: Vczh Parser Generator
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace json
|
|
{
|
|
/***********************************************************************
|
|
Visitor Pattern Implementation
|
|
***********************************************************************/
|
|
|
|
void JsonLiteral::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonString::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonNumber::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonArray::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonObjectField::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void JsonObject::Accept(JsonNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
using namespace vl::parsing::json;
|
|
|
|
#define PARSING_TOKEN_FIELD(NAME)\
|
|
CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(get_##NAME, NO_PARAMETER, vl::WString(ClassType::*)(), [](ClassType* node) { return node->NAME.value; }, L"*", L"*")\
|
|
CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(set_##NAME, { L"value" }, void(ClassType::*)(const vl::WString&), [](ClassType* node, const vl::WString& value) { node->NAME.value = value; }, L"*", L"*")\
|
|
CLASS_MEMBER_PROPERTY_REFERENCETEMPLATE(NAME, get_##NAME, set_##NAME, L"$This->$Name.value")\
|
|
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonNode, system::JsonNode)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonLiteral, system::JsonLiteral)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonLiteral::JsonValue, system::JsonLiteral::JsonValue)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonString, system::JsonString)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonNumber, system::JsonNumber)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonArray, system::JsonArray)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonObjectField, system::JsonObjectField)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonObject, system::JsonObject)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::json::JsonNode::IVisitor, system::JsonNode::IVisitor)
|
|
|
|
BEGIN_CLASS_MEMBER(JsonNode)
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Accept, {L"visitor"}, void(JsonNode::*)(JsonNode::IVisitor* visitor))
|
|
END_CLASS_MEMBER(JsonNode)
|
|
|
|
BEGIN_CLASS_MEMBER(JsonLiteral)
|
|
CLASS_MEMBER_BASE(JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<JsonLiteral>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(value)
|
|
END_CLASS_MEMBER(JsonLiteral)
|
|
|
|
BEGIN_ENUM_ITEM(JsonLiteral::JsonValue)
|
|
ENUM_ITEM_NAMESPACE(JsonLiteral::JsonValue)
|
|
ENUM_NAMESPACE_ITEM(True)
|
|
ENUM_NAMESPACE_ITEM(False)
|
|
ENUM_NAMESPACE_ITEM(Null)
|
|
END_ENUM_ITEM(JsonLiteral::JsonValue)
|
|
|
|
BEGIN_CLASS_MEMBER(JsonString)
|
|
CLASS_MEMBER_BASE(JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<JsonString>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(content)
|
|
END_CLASS_MEMBER(JsonString)
|
|
|
|
BEGIN_CLASS_MEMBER(JsonNumber)
|
|
CLASS_MEMBER_BASE(JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<JsonNumber>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(content)
|
|
END_CLASS_MEMBER(JsonNumber)
|
|
|
|
BEGIN_CLASS_MEMBER(JsonArray)
|
|
CLASS_MEMBER_BASE(JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<JsonArray>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(items)
|
|
END_CLASS_MEMBER(JsonArray)
|
|
|
|
BEGIN_CLASS_MEMBER(JsonObjectField)
|
|
CLASS_MEMBER_BASE(JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<JsonObjectField>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(name)
|
|
CLASS_MEMBER_FIELD(value)
|
|
END_CLASS_MEMBER(JsonObjectField)
|
|
|
|
BEGIN_CLASS_MEMBER(JsonObject)
|
|
CLASS_MEMBER_BASE(JsonNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<JsonObject>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(fields)
|
|
END_CLASS_MEMBER(JsonObject)
|
|
|
|
BEGIN_INTERFACE_MEMBER(JsonNode::IVisitor)
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonLiteral* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonString* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonNumber* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonArray* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonObjectField* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(JsonNode::IVisitor::*)(JsonObject* node))
|
|
END_INTERFACE_MEMBER(JsonNode)
|
|
|
|
#undef PARSING_TOKEN_FIELD
|
|
|
|
class JsonTypeLoader : public vl::Object, public ITypeLoader
|
|
{
|
|
public:
|
|
void Load(ITypeManager* manager)
|
|
{
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonNode)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonLiteral)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonLiteral::JsonValue)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonString)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonNumber)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonArray)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonObjectField)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonObject)
|
|
ADD_TYPE_INFO(vl::parsing::json::JsonNode::IVisitor)
|
|
}
|
|
|
|
void Unload(ITypeManager* manager)
|
|
{
|
|
}
|
|
};
|
|
#endif
|
|
|
|
bool JsonLoadTypes()
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
ITypeManager* manager=GetGlobalTypeManager();
|
|
if(manager)
|
|
{
|
|
Ptr<ITypeLoader> loader=new JsonTypeLoader;
|
|
return manager->AddTypeLoader(loader);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\JSON\PARSINGJSON_PARSER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingJson.parser.txt
|
|
|
|
This file is generated by: Vczh Parser Generator
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace json
|
|
{
|
|
/***********************************************************************
|
|
ParserText
|
|
***********************************************************************/
|
|
|
|
const wchar_t* const parserTextBuffer[] = {
|
|
L"" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"// AST" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Literal:Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\tenum Value" L"\r\n"
|
|
, L"\t{" L"\r\n"
|
|
, L"\t\tTrue," L"\r\n"
|
|
, L"\t\tFalse," L"\r\n"
|
|
, L"\t\tNull," L"\r\n"
|
|
, L"\t}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"\tValue value;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class String:Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken content(JsonUnescapingString)\t\t\t\t@Color(\"String\");" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Number:Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken content;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Array:Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\tNode[] items;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class ObjectField:Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken name(JsonUnescapingString)\t\t\t\t@Color(\"AttName\");" L"\r\n"
|
|
, L"\tNode value;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Object:Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\tObjectField[] fields;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"// Lexer" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"token TRUEVALUE = \"true\"\t\t\t\t\t\t\t@Color(\"Keyword\");" L"\r\n"
|
|
, L"token FALSEVALUE = \"false\"\t\t\t\t\t\t\t@Color(\"Keyword\");" L"\r\n"
|
|
, L"token NULLVALUE = \"null\"\t\t\t\t\t\t\t@Color(\"Keyword\");" L"\r\n"
|
|
, L"token OBJOPEN = \"\\{\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token OBJCLOSE = \"\\}\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token ARROPEN = \"\\[\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token ARRCLOSE = \"\\]\"\t\t\t\t\t\t\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token COMMA = \",\";" L"\r\n"
|
|
, L"token COLON = \":\";" L"\r\n"
|
|
, L"token NUMBER = \"[\\-]?\\d+(.\\d+)?([eE][+\\-]?\\d+)?\"\t@Color(\"Number\");" L"\r\n"
|
|
, L"token STRING = \"\"\"([^\\\\\"\"]|\\\\[^u]|\\\\u\\d{4})*\"\"\"\t\t@ContextColor();" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"discardtoken SPACE = \"\\s+\";" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"// Rules" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"rule Node JLiteral" L"\r\n"
|
|
, L"\t= STRING:content as String" L"\r\n"
|
|
, L"\t= NUMBER:content as Number" L"\r\n"
|
|
, L"\t= \"true\" as Literal with {value = \"True\"}" L"\r\n"
|
|
, L"\t= \"false\" as Literal with {value = \"False\"}" L"\r\n"
|
|
, L"\t= \"null\" as Literal with {value = \"Null\"}" L"\r\n"
|
|
, L"\t;" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"rule ObjectField JField" L"\r\n"
|
|
, L"\t= STRING:name \":\" JValue:value as ObjectField" L"\r\n"
|
|
, L"\t;" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"rule Object JObject" L"\r\n"
|
|
, L"\t= \"{\" [JField:fields {\",\" JField:fields} ] \"}\" as Object" L"\r\n"
|
|
, L"\t;" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"rule Array JArray" L"\r\n"
|
|
, L"\t= \"[\" [JValue:items {\",\" JValue:items} ] \"]\" as Array" L"\r\n"
|
|
, L"\t;" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"rule Node JValue" L"\r\n"
|
|
, L"\t= !JLiteral" L"\r\n"
|
|
, L"\t= !JObject" L"\r\n"
|
|
, L"\t= !JArray" L"\r\n"
|
|
, L"\t;" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"rule Node JRoot" L"\r\n"
|
|
, L"\t= !JObject" L"\r\n"
|
|
, L"\t= !JArray" L"\r\n"
|
|
, L"\t;" L"\r\n"
|
|
};
|
|
const vint lengthTextBuffer[] = {
|
|
2, 68, 8, 68, 2, 12, 3, 3, 2, 20, 3, 13, 4, 9, 10, 9, 4, 2, 15, 3, 2, 19, 3, 59, 3, 2, 19, 3, 17, 3, 2, 18
|
|
, 3, 16, 3, 2, 24, 3, 57, 14, 3, 2, 19, 3, 24, 3, 2, 68, 10, 68, 2, 51, 53, 51, 49, 50, 49, 50, 20, 20, 68, 67, 2, 29
|
|
, 2, 68, 10, 68, 2, 20, 29, 29, 44, 46, 44, 4, 2, 25, 48, 4, 2, 21, 59, 4, 2, 19, 56, 4, 2, 18, 14, 13, 12, 4, 2, 17
|
|
, 13, 12, 4
|
|
};
|
|
const vint lengthTextBufferTotal = 2018;
|
|
|
|
vl::WString JsonGetParserTextBuffer()
|
|
{
|
|
vl::collections::Array<wchar_t> textBuffer(lengthTextBufferTotal + 1);
|
|
wchar_t* reading = &textBuffer[0];
|
|
for(vint i = 0; i < sizeof(parserTextBuffer) / sizeof(*parserTextBuffer); i++)
|
|
{
|
|
memcpy(reading, parserTextBuffer[i], lengthTextBuffer[i] * sizeof(wchar_t));
|
|
reading += lengthTextBuffer[i];
|
|
}
|
|
*reading = 0;
|
|
return &textBuffer[0];
|
|
}
|
|
|
|
/***********************************************************************
|
|
SerializedTable
|
|
***********************************************************************/
|
|
|
|
const vint parserBufferLength = 3809; // 17748 bytes before compressing
|
|
const vint parserBufferBlock = 1024;
|
|
const vint parserBufferRemain = 737;
|
|
const vint parserBufferRows = 4;
|
|
const char* const parserBuffer[] = {
|
|
"\x00\x0B\x00\x02\x83\x80\x07\x7D\x00\x82\x03\xFF\x45\x08\x82\x83\x86\x81\x21\x6F\x6C\x2F\x32\x37\x84\x86\x02\x86\x00\x17\x82\x93\x24\x3A\x39\x34\x37\x67\x06\x98\x8A\x88\x8E\x84\x00\x88\x12\x94\x98\x87\x0B\x93\x81\x20\x3A\x74\x4E\x21\x2D\x35\x32\x90\x86\x92\x0C\xA6\xA8\x93\x85\x88\x84\x96\x86\x3F\x80\x0B\x25\x39\x3F\x3B\x88\x32\x36\x88\xB8\x88\x8A\x99\x88\x9F\x96\x40\x83\x83\xA5\xA7\xA1\xA4\x83\xA5\x04\xCD\xA9\x9D\x94\x81\xA1\xAE\xA9\x44\xC6\xB2\x28\xAC\xA9\x86\x93\xAC\x03\xBB\xAA\x8C\x88\x00\x8D\xB6\x81\x42\x6F\x35\x2E\x34\x31\x32\x39\x3C\x56\xE6\xA5\x89\xBE\xA3\xB4\x85\xB7\x7F\x83\xB1\xB3\xB5\xBF\xB9\xBC\x81\x58\x83\x9A\xAF\xAC\xB6\xB6\xC0\xB9\x74\xF6\xB8\xA5\xB8\xC7\xB2\xC4\xBE\x5B\x8E\xCD\xD0\xB0\xCD\xC3\xC9\x91\x96\x8D\x98\xCC\xC8\x82\x8D\xD3\x81\x4E\x75\x2D\x22\x35\x32\x3B\xC3\x82\x0C\x18\xB1\xCF\x8F\x36\x34\x3B\x32\x78\x74\x2A\xB8\x80\x06\xAF\xCB\x9C\x2E\xF2\x32\x21\x38\xBF\x7E\xE3\xE3\xFF\x3E\xC2\x81\xAC\x21\x37\xDB\xE1\x6C\x48\xC8\xE4\x08\x8C\xEA\x80\x27\x6F\x64\x35\x92\xE6\xE6\xD0\x82\xD3\xA9\xAB\xED\xDC\xED\xE8\x8E\xD3\x27\x62\x6A\x25\x23\x34\x3C\xF3\x7F\x80\x0C\xF0\xC0\x08\xFA\xF4\xF6\x23\x34\x65\x6C\x08\xA4\xFE\xEB\x82\xD2\x8E\x1E\x60\x4E\x7A\x72\x00\x21\x65\x81\x70\xC3\x79\x16\x82\x49\xCE\x65\x1D\x1B\x1C\x03\x90\x50\x01\x73\xCF\x61\x1C\x1B\x82\x03\x76\x16\x85\x1D\xDB\x5C\x7D\x7E\x40\xE0\x6A\x6C\x6A\x1C\x04\x81\x53\x19\x6D\xB7\x76\x6E\x7B\x87\x19\x43\x44\x7F\x7A\x74\x2C\x86\x6A\x19\xF8\x7A\x70\x84\x79\xF2\x44\x42\x7F\x8B\xF6\x75\x84\x1A\x75\x08\x40\x9E\x1B\x4C\x65\x14\x60\x40\x46\x3B\xA9\x70\x8F\x7D\xF9\x64\x18\x86\x40\x1A\xAC\x1C\x87\x8A\xE6\x43\x40\x83\x47\x67\x25\x83\x43\x89\xB6\x65\x16\x6C\x6F\x0F\x18\x44\x08\x46\x61\xBC\x66\x9A\x52\xEE\x64\x77\x9B\x4D\x69\x9C\x7B\x98\x9A\x6D\x88\x7F\x9B\x55\x71\x88\x79\x00\x46\x77\x82\x44\x16\x14\x55\x05\x16\x15\x10\x4C\x3D\x90\x90\x41\x40\x9D\x4C\x84\x6F\x02\x18\x4A\x02\xA2\x03\x46\x10\xA3\x14\x7E\x80\xAD\x9F\x93\x00\x26\x16\x87\x1C\x45\x98\x43\x00\x9E\x9C\x97\x75\x14\x13\x4C\x3F\x91\xA1\x11\x83\x83\x42\x91\x1D\x6C\x2C\x19\xA0\x43\xA5\x8B\x72\x87\x13\x42\x0A\x1F\x10\x14\x45\x0E\x1B\xA8\x42\xB7\x9C\x1B\x1F\xA6\xC0\x5B\x61\x62\x40\xB0\x8A\x13\x10\x13\x4F\x10\xA7\xAC\x41\xB9\xBD\x1D\xA9\x8B\x51\x4D\xB0\x01\x10\x52\x12\x13\xAD\xAD\xC7\x83\x49\xAF\x16\x06\x84\x80\x60\x41\x80\x50\xB2\x17\xB0\xC5\x85\x15\xB6\x40\xB9\x9D\x1C\x8B\xB6\xBF\x4C\x59\x5B\x13\x4D\x0D\x11\x12\x91\x3D\x6C\x04\x82\x7B\x94\x83\x1F\x10\xB1\x4E\x30\xB3\x42\x0E\xE8\x88\x6C\x7D\x95\x9E\x8D\x12\x11\x11\x52\x1F\x08\x46\xC1\x02\x5B\x1C\x15\x0B\x5D\x3F\x0C\x14\x19\x2B\x28\x0E\x0B\xC3\x2B\x29\x0F\x0C\x0A\x5B\x25\x15\x11\x17\x5B\x2B\x0B\xC1\xC3\x14\xD6\xC9\x9C\x42\x23\xDF\x70\xC0\x00\x53\x3B\x99\x12\x13\x47\x1B\x08\x46\xCB\x02\x62\x08\xC6\x17\x5C\x1C\x12\x09\x17\x7C\x35\xCB\x16\x17\x75\x38\xC5\xCD\x1D\x0F\xFB\x14\x0D\x1F\x29\x2A\x02\x0B\xA2\x0C\x48\xD8\x42\x91\x94\x93\x10\x15\x10\x43\x05\x1C\xAC\x42\x53\xDC\x13\x1F\x0A\x39\x89\x44\x7B\x98\xBE\x9C\xB3\x42\x12\x14\xAD\x66\x86\x04\x18\x64\xD2\x40\xD8\x0D\x90\x7E\x0A\x14\x6F\x2F\x14\x1C\x47\x76\x74\x1D\x00\x46\x73\xC2\x40\x10\x08\x24\x3C\x08\xD9\x85\x6C\x3E\x0D\xBC\x00\x80\x7B\xD2\xD8\x1B\x0E\x18\x45\xE3\xD9\x61\xEA\xD0\xDE\x1C\x74\x33\x68\x42\xE3\x77\xFA\xD9\xE2\x85\x7E\xDA\x60\x02\xE0\xD0\x4A\xD4\x42\xD2\x98\xD6\x8E\x09\x0C\xFA\x18\x41\xEA\x40\x92\xE9\xD4\xE6\x0E\x20\x29\xC2\x17\xCA\x47\x20\x08\xE8\x97\x29\xB4\x10\x09\x18\x73\x29\xED\x44\x96\x40\x0D\x0A\x01\xE9\x7C\xFE\x08\xEA\x13\x55\x02\xC4\xC2\xEB\x20\x30\xEE\x96\xEC\xB4\xE0\x01\x7B\x88\xB9\xFB\xED\xE5\xDF\xA8\xE2\x06\xA1\x19\x22\x33\xE5\xEF\xE4\x6C\x37\xD7\x1E\x73\x68\x20\x0B\x1C\x08\x51\x9C\x80\x09\x0F\x20\x22\x04\x16\x1C\x1C\x95\xFD\x1E\xEE\xBC\xC3\xEE\xED\xF9\x96\xAC\x18\xA5\xF5\xC9\xD8\xFA\xF4\xF7\xDE\xE0\xFB\x85\x19\xE3\xE5\xF6\x13\xA5\xD4\x60\x07\xFA\x4E\x78\x7B\xF7\x62\x06\x0D\xA8\x4C\x0C\xFD\x57\x76\x75\xEC\x60\x03\x7B\x74\x1D\x7B\xF7\x61\x7C\x7E\xF2\x62\x01\x35\xA9\x4A\x7F\xDF\x01\x78\x7A\x08\x18\x26\x83\x88\x6D\x83\xDA\x6D\x64\x0F\x22\x34\x2D\x6E\x08\x28\x85\xDE\x4F\x7E\x06\x10\x00\x0A\x46\x5F\x76\x0B\xFE\x1B\x81\x87\xFD\x5F\x75\x07\x18\x38\x84\xE9\x4A\x02\x86\x29\x65\x0F\x7D\x21\x0F\x79\xF3\x7A\x6D\x86",
|
|
"\x0E\x40\x8A\x56\x4A\x4C\x3F\x10\xBC\x8B\x7F\x23\x81\x0A\x38\xC4\x2F\x87\xC9\x4A\x0C\x48\xFD\x34\x87\x6C\x55\x84\x0E\x0B\x33\x0A\x06\x8C\x1D\x8B\x87\x59\x8F\x7E\xEA\x2C\x74\x79\x21\x74\x25\x7C\x3A\x15\x78\x13\xBE\x84\x78\x0A\x96\x78\x04\x3C\x54\x0D\x16\xD2\x86\x23\xAF\x4F\x89\x41\x57\x97\x73\x1D\xC4\x3E\x04\x19\x0C\x10\x23\x7F\x9B\x87\x1E\xF9\x06\x81\x2D\x15\x7B\x0B\x20\x0B\x8E\xF8\x28\x7D\x41\x07\x77\x6F\x7B\x22\x0C\x06\x1A\xC5\x8C\x7E\x46\xB7\x37\x41\x02\x80\x05\x17\x65\x7D\x0B\x05\xA0\x03\x90\xEC\x6A\x0B\x20\x85\x97\x91\x44\x94\x94\x78\x8D\x95\x74\x10\x10\x92\x92\x53\xBB\x78\x95\x97\x95\x75\x1F\x1A\x9C\x92\x4F\x83\x90\x86\x67\x74\x93\xE1\x08\x2B\x96\x45\xA5\x0B\x84\x6E\x66\x84\x19\x59\x62\x20\xF9\x2B\x84\x92\x2D\x94\x8F\x69\x58\x8E\x47\x5D\x84\x25\x97\x59\x80\x99\x09\xF4\x24\x99\x23\x42\x23\x85\x61\x8E\x86\x96\x67\x61\x8F\x92\x43\x23\x64\x48\x95\x3C\x1D\x7D\x84\x12\x8C\x25\x9B\x87\x71\x86\x83\x1E\x25\x94\x8A\x1F\x44\x7C\x46\x4D\x53\x0F\x23\xE5\x7D\x95\x76\x8D\x4F\x9D\x3E\x52\x94\x2D\xA2\x0D\x0E\x4F\xB1\x89\x94\xE9\x91\x7B\x3A\xA0\x08\x90\x7B\xBA\x38\x9F\xF1\x8E\x84\x2B\xEA\x89\x8A\x84\xB6\x41\x93\x9B\x9C\x9E\x3F\xC9\x81\x47\x29\x83\x91\x8F\xA2\x90\x89\x1E\x5B\x85\x08\x8C\x1D\xA2\x90\x1A\xA4\x94\x41\xAE\x9C\x8C\x4B\x8E\x45\x76\x0B\xA4\xA7\x22\xA0\x09\x94\x88\xB5\x97\x8D\x83\x8A\x9A\xC9\x67\x67\xA2\xCB\x59\xA1\x41\x2E\x14\x07\x47\x88\x2B\xA6\xBD\x63\x91\x7A\x86\x83\xA6\x2F\xB0\x97\xA5\xFC\x51\x92\x04\x77\x63\xAA\x49\x98\x93\x97\x88\x9D\x90\xA6\x1A\xBB\x9B\xE5\x5D\x9D\x53\xA9\x94\xA1\xA7\x49\x18\x21\x56\xE8\x94\xA2\x75\xAC\x9D\xA1\xA8\x70\x9F\x43\x8B\xA9\xA8\xB0\xA0\x02\xAC\x64\x1A\x9D\x44\xFD\x9F\x8D\x38\x92\xA9\x9C\x30\x5E\x9A\x40\x60\x91\x8F\x2D\x9B\xA8\x21\x77\xBA\x6D\x40\xE5\x73\xA1\x82\xA6\xA8\xAD\x28\xB4\x9C\x43\xEE\x91\xAD\x7C\xAE\xA2\xA2\x6D\xB4\xA2\x4C\xFE\x36\x8E\x8D\x8E\x9B\x20\xBD\x83\x92\x34\xC2\x95\x9A\x63\xBE\xA1\xA4\x2E\x94\x52\x12\x6C\x6E\x6D\xB7\x9C\xB3\x9C\x31\x05\x04\x46\x22\xBB\x87\xCF\x87\x89\x8E\x4B\x86\xB4\xEA\x41\x81\xA7\xB7\x94\xAC\x21\x74\xB7\xA9\x0C\x77\xA4\x21\xBC\xB0\xAC\x3D\x5E\xB7\x6E\x5F\x84\xB7\xAC\xC3\xA9\xA6\xA0\x64\x0E\xA1\x5A\x87\xBC\xAD\xE4\x71\x88\x97\x7A\x9A\xA0\x46\x92\xB1\x07\x9D\x84\x25\xA7\x37\xA4\x38\x29\xBA\xBA\xA5\x4A\xAC\xA1\x96\x46\xB5\x9F\x29\xCB\xAA\xAD\x97\x89\x7F\x96\x53\x99\x88\x46\xD1\x91\x07\x2F\x88\x26\xBC\x7A\x61\x8C\xEA\x63\x8C\x65\x32\x84\x4F\x6E\x22\x09\x8D\x75\xED\x8F\x94\xE3\x94\xA1\x8B\xAE\xB4\xA1\x99\x08\x2B\xBF\xDB\xA3\x9F\xB3\xC2\x8E\x70\x41\x0E\x7B\x85\x74\x99\xB3\x2F\x67\x7F\xB0\x0A\x84\x28\x85\xCD\xA4\x83\xB2\x74\x3A\x73\x40\x4A\x6B\x84\xD3\xAE\x80\xB9\xC0\xA3\xBE\x8F\x7D\x86\xBC\x82\x28\xB8\xB8\x62\x8A\x65\x7B\xA8\x76\x8C\xFE\x71\xB8\xA9\xF3\xA8\x76\x1B\xF6\xB2\x9D\x2C\x98\xC1\x8B\x20\x88\x21\x8C\xC0\xB2\x9B\xC5\x74\x0D\xB2\x03\x37\x6C\x36\xBE\x4E\x07\x17\xFE\x42\xC0\x03\x2E\x70\x8D\xB6\xC2\xC2\x81\x0A\x69\x72\x20\xD9\xBE\x38\x91\x08\x22\x26\xDC\x9F\xAA\x9F\xB6\xC4\x90\x82\x20\x72\xBC\x7A\xAD\xAB\x4A\xD0\x47\x82\x83\x2D\xC1\xBA\xB6\xC0\xC7\x76\x60\x07\x95\xE2\x9D\xC6\x8B\x9A\xA1\xC6\x04\x33\xC6\x64\xD1\xC4\x0F\xB8\x60\xC8\x00\x3A\xD7\xB1\x82\x65\xC5\x8E\x9A\x9A\xA3\xCA\x00\x02\xCA\x64\xC4\xCC\x51\x30\xF2\xCA\xBA\x18\xD4\x90\x9A\x83\x23\xC6\x4A\xB5\xC5\xCD\x8C\x6F\xCD\x9C\xBE\x94\xCF\x65\x97\x74\x92\x78\xC2\xCA\xA1\xFC\xC9\x69\x1C\xE2\xCC\xD1\x9A\xBF\xB3\x7E\x84\x2D\xBF\xCF\x87\xD1\x6E\x45\xC0\x03\x91\xD6\xCE\xC0\xB7\x7E\x01\xD3\x24\x8F\xCD\xA9\xE3\x96\xC6\xB9\x80\x03\x64\x48\xC6\xB4\x46\xD8\x71\xD4\xCE\x58\x7D\x8F\xA3\x68\x21\xAE\xED\x70\x3B\x10\xEB\x73\xC4\xC5\x68\x47\xF1\x6F\x87\x4A\x90\x0B\x8D\x80\xBF\x61\x7B\xC0\x52\x04\x78\xE3\x76\x37\x8D\xCB\x6D\x37\xB1\x8D\x86\x81\xE9\x5E\x90\x7B\x0F\x98\x7F\x04\xAF\x96\x83\xF3\x69\x7A\x80\xD3\xDD\x75\xF4\x71\x73\x7F\x37\x98\xD8\x82\x12\x9A\x7C\x1B\x96\x8F\x7E\xF9\x41\x85\x0F\xE1\xCE\x7D\xF4\x08\x89\x82\x73\xCD\x81\xDB\x11\x99\x7E\x1B\x96\x88\x82\x05\xA0\xDE\xC7\x4D\x5A\xC1\x93\x39\xAD\xC3\x7D\x43\x21\xBD\x3C\xCB\xBE\x88\xAD\x74\xC4\x22\x68\x8B\x92\xAF\x8A\xC5\x7D\xB5\x71\x8F\x39\x99\xCC\x3D\xAE\xD1\xB6\x38\xAE\x05\x06\xDA\x83\x26\xB6\x7B\xA2\x05\x5F\x89\x9F\xAE\xDF\x82\xB4\xE4\xBC\xA0\xB0\x71\x93\xA2\x9D\xC5",
|
|
"\xA0\x45\xB1\x78\x96\xA6\x64\xB5\x0E\xB9\x81\x10\xBF\xA7\xE5\x61\xA9\x41\xDB\xB7\xBB\xA2\xBF\xB4\xE7\x2D\xAD\xAA\x77\xB5\x71\xA7\x73\x76\xA0\x7B\xCB\x40\x48\x76\x5A\x33\x4E\xAD\x5E\x41\xBC\x3E\x4F\xCD\xC5\xBE\x4C\x36\x0B\x23\x24\x3C\x17\xF5\xA1\x9D\xF3\x34\xA2\xDE\x18\x07\xEA\x4F\xFB\xE9\x74\x8A\x48\xC1\x67\x5A\xA4\x37\x1A\x00\xEE\x74\x01\xDB\x7F\xA4\xE8\x31\x3B\x65\x1C\x34\x07\x6A\xE8\x38\x54\xEE\x6E\xED\xD7\x30\xEC\x6F\x1E\x04\xEF\xE3\x1C\x03\x5C\xAF\x3F\x1C\x6F\x46\x4D\xE9\xC2\xF3\x49\xF0\xCB\x43\x5E\xE1\x80\x0A\xF1\x65\x7C\x34\x52\x14\x98\xEC\x00\x5E\xD5\x0D\x59\xCD\x86\xF0\x52\xB8\x78\x6F\x16\xFC\x6F\xC0\xC6\x42\xF1\x86\xED\xF1\xE1\x90\xFB\x7E\x4A\x6D\xD8\x53\x9C\xE3\x70\xE6\x92\x4A\xF2\xCB\x5E\x69\x84\x9D\xE6\x4B\x3F\x2C\x40\xF5\xC2\xE2\xF5\xE9\xA4\xFE\x86\xE4\xFD\xD9\xF4\xE8\x2B\xF6\x59\xAD\xFD\x6B\x40\x1C\x87\xF2\xA5\x32\xF3\xCB\xE4\x4B\xF0\x43\x0A\xF4\xF0\x09\x5F\x2A\x20\xCE\xD4\x0F\xE6\xC7\xE5\xF9\xA6\xC8\xB9\xDA\x72\x13\xFA\xAF\x4F\x71\xF1\xC7\x89\xFA\xF9\xC8\x58\x21\xF3\xCE\x5F\xF8\x00\x11\xFA\xFB\xBF\x57\x71\xF0\xF3\x48\xB9\x62\xE7\x08\xFD\xAF\xEA\xFF\xE5\x81\xF6\x49\xA9\x60\xFE\x4C\x81\xF7\xF7\x9C\x46\x4D\x02\x8C\x0A\xF4\x45\xFD\x77\x7F\x02\x1D\x7B\x16\x26\x7F\x02\x8B\x75\x33\x5F\x68\xFB\x37\x80\x37\x12\x7B\x46\x24\x20\x0C\x85\x10\x06\x88\x18\x8A\x76\x20\x83\x78\x11\x15\x0E\x7F\x27\x34\x10\x19\x87\x80\x6C\x7E\x43\xE3\x7A\x2E\xBD\x20\x00\x14\x4C\x1B\x00\x7A\x1F\xFF\x0F\x7F\x85\x76\x24\x4E\x68\x2B\x1B\x83\x10\x2D\x87\x7F\x1F\x8C\x21\xB5\x73\x82\x68\x12\x10\xA9\x46\x82\x66\x69\x20\x29\x8F\x82\x67\x26\x24\xD5\x4A\x82\xF1\x1C\x80\x33\x85\x06\x35\x82\x82\x48\x89\x83\x3E\x8C\x2C\xC9\x59\x20\x87\x7E\x80\xAE\x70\x7E\x21\x8F\x26\x52\x77\x5F\x54\x7B\x84\xA6\x10\x5C\x3D\x87\x13\x8A\x7E\x6A\x17\x8C\x10\x83\x62\x10\x13\x8B\x78\x55\x8D\x62\x57\x88\x80\x8C\x5C\x4C\x4D\x2C\x22\x61\x8B\x78\x27\x84\x06\x47\x89\x80\x09\x80\x58\xBC\x19\x75\x5B\x84\x32\x2B\x82\x1B\x9A\x2C\x80\x65\x8B\x24\x67\x8E\x68\x09\x80\x5C\x2C\x28\x67\x86\x7F\x86\x71\x89\x86\x8E\x64\x87\xCE\x73\x10\x41\x1E\x5F\x07\x81\x78\xB5\x61\x81\x23\x12\x7B\x6F\x62\x89\x96\x8A\x7C\x81\x7F\x37\xC8\x77\x89\x81\x75\x4D\x84\x8C\x89\x50\x8C\x10\xDE\x7B\x78\x53\x8B\x26\x94\x23\x48\x3A\x82\x76\x83\x47\x87\x57\x1A\x78\x9B\x6B\x26\x46\x28\x30\x54\x3C\x80\xA7\x87\x76\x58\x80\x73\xC4\x1C\x22\xB2\x82\x83\x3B\x84\x1C\x63\x81\x81\x76\x7D\x1E\xFA\x7F\x26\xFC\x7B\x87\x07\x85\x8B\x4E\x87\x8B\x76\x69\x20\x00\x84\x84\xBD\x89\x07\xBF\x8E\x8C\x62\x74\x49\x86\x78\x78\x1A\x87\x80\xCB\x26\x20\xD5\x45\x88\xCF\x86\x20\x01\x82\x80\x45\x8E\x78\x65\x77\x83\x24\x8D\x76\xD5\x13\x10\x94\x74\x80\x6C\x0F\x7B\x3E\x13\x10\xEB\x71\x7F\xF1\x7C\x7D\xB2\x7F\x79\x0C\x89\x8D\x48\x22\x8D\x8E\x63\x76\xDE\x88\x8F\x81\x84\x49\xE2\x86\x83\xE9\x24\x41\xA6\x70\x40\xEA\x8C\x8E\xE5\x7F\x8E\xC3\x74\x7D\xB1\x73\x12\xB4\x75\x8F\xE3\x83\x10\xDB\x85\x78\x18\x63\x48\xFB\x8E\x81\x53\x4E\x8F\xA3\x75\x76\x91\x77\x8E\xD7\x19\x40\x05\x95\x78\x99\x75\x7D\xE9\x71\x8F\xD8\x31\x78\x04\x2D\x86\xA1\x7F\x90\xC5\x4C\x8F\x88\x8A\x8F\x18\x1F\x8D\xBC\x83\x8D\x0B\x81\x78\xAE\x61\x83\xE0\x75\x81\xF7\x86\x91\xAA\x8A\x51\x15\x90\x8E\x17\x9B\x80\x88\x17\x7C\xD7\x82\x80\xF6\x83\x84\x3A\x99\x8F\x14\x9F\x92\x2C\x9F\x72\xB9\x4B\x3F\xA5\x8E\x2A\xCE\x27\x7E\x51\x83\x80\x5F\x38\x90\x67\x27\x7D\x22\x2D\x1A\xF0\x79\x90\xB0\x73\x38\xDD\x73\x94\xF7\x75\x94\x08\x11\x91\xD6\x7D\x8D\x4A\x97\x94\xFD\x8E\x94\x20\x92\x21\x52\x92\x7C\x54\x9D\x95\xBE\x72\x91\x27\x3E\x7E\x5B\x9F\x96\xF2\x7C\x37\x4D\x7F\x95\x0C\x16\x36\x02\x88\x93\x0C\x1F\x89\x4D\x79\x75\x4F\x90\x00\x92\x75\x62\xA9\x89\x8F\x59\x45\x10\xA1\x88\x10\x13\x0C\x80\x83\x97\x98\x09\x81\x47\x75\x82\x21\xFE\x5C\x8A\x09\x1E\x8A\x79\x8C\x10\xBB\x83\x10\xD1\x85\x96\x5B\x72\x99\x8B\x80\x95\x56\x52\x4E\xBA\x8C\x80\x59\x7D\x99\x02\x81\x8C\x96\x92\x10\xFF\x8B\x34\x67\x93\x8B\x68\x98\x88\xA0\x94\x7E\x8C\x8F\x35\xC7\x5F\x9A\xF7\x77\x9A\x97\x82\x87\x2D\x94\x8D\xA0\x83\x89\x18\x14\x01\xBB\x91\x81\x99\x84\x37\xC3\x90\x9C\x37\x13\x8A\x7C\x97\x7F\x7E\x92\x63\xA6\x94\x99\x71\x43\x98\x85\x94\x24\x90\x9D\x92\x89\x99\x10\xB2\x79\x78\x0E\x90\x90\x02\x16\x93\xCA\x73\x91\x3C\x98\x9B\xE0\x71\x8E\x19\x93\x82\x1B\x9C\x2A\xE8\x88\x3E",
|
|
"\x95\x7A\x90\xAA\x7B\x96\xC0\x72\x92\xF0\x8C\x95\x77\x9E\x95\xF3\x80\x96\xE0\x72\x96\x04\x1E\x9D\x6E\x86\x96\x0C\x10\x93\xE3\x9F\x93\xBA\x75\x9E\x48\x82\x90\x65\x77\x7A\xEB\x9B\x7D\x56\x96\x26\x21\x98\x97\x53\x90\x38\x55\x9D\x40\x81\x7D\x90\xD8\x8A\x92\x00\x0A\x9F\xDC\x8B\x93\x09\x2D\x93\x31\x99\x8F\x18\x98\x7B\x1A\x96\x8E\xE8\x9D\x91\xA9\x2F\x91\x81\x9C\x7A\xF0\x92\x9F\x24\x90\xA1\xB2\x77\x92\x0C\x8D\x9C\xF9\x9B\x94\x4C\x8E\x92\xFD\x90\xA3\x59\x84\x8D\x34\x9D\x64\x2D\xA4\xA1\x16\xA2\x97\x18\xA4\x1C\x1A\xAF\x9F\x32\x9E\x43\x90\x8D\x67\xC7\x9A\x98\x23\x1B\x89\x87\x87\x26\xF8\x90\x83\x34\xA8\x8B\x64\x73\xA3\xB1\x9C\x94\x0A\x80\x82\xEE\x9D\x8E\xD0\x72\x6C\x5F\x2D\xA0\xC4\x7C\xA0\x9E\x9E\x68\xD8\x75\x97\x0E\xA0\x97\x16\x2A\x97\x2E\x83\xA1\xDC\x95\xA1\x4D\xAB\x8C\x3E\xA2\x9E\xDF\x90\xA0\x1C\x23\x98\x52\x5D\x96\x23\x92\x9F\xCF\x37\xA1\x8E\x64\x97\x5A\xAF\xA0\x5C\xA8\x7F\xB2\x78\x67\x1D\x85\xA4\x80\xA1\x94\x23\x1A\x9D\x66\xA8\x84\x1C\x89\xA6\x97\x39\x45\x3F\xAD\xA6\x41\xAC\x21\xAD\x94\x8E\xE4\x87\x9E\x41\x29\x9E\x1C\x24\xA2\x73\x2B\xA0\xED\x9E\x96\x61\xA3\x9F\xD0\x1E\x79\xF6\x9A\x7C\x4B\xA2\x10\x7F\xAB\xA1\x81\x8A\xA8\x6C\xAB\x9F\x8D\xA5\x06\x8F\xA9\x2E\x91\xA5\x7A\x05\xA4\x90\xEC\x91\x97\x25\xAF\x9E\x7B\xA1\x9F\x76\x92\x8F\x0C\x9F\xA9\x8B\x71\xAA\x00\x03\xAA\x40\xA8\x98\x3E\x2B\xA8\xA8\xAC\xA1\x20\xA3\x27\xB9\x7E\xA8\x1C\x90\x00\xBC\x71\xAB\x16\x26\x90\xB5\x92\x10\x09\xAA\x8E\x26\x9F\x41\x39\xA7\xA6\xBE\xAC\xA8\xC0\xAD\x24\xC2\xA6\xA7\x69\x9E\x43\x46\xA7\x13\x35\x95\xAD\x86\xA3\x10\xD7\xA3\xAC\xA5\xA1\xAC\xA7\xAC\xAD\xBD\x90\x94\xDF\xAA\x14\x48\xAB\x9D\xE3\xA2\xAA\x88\xA0\x5C\xDB\xAC\xA3\xC4\xA4\xA5\xB3\xA6\xA5\xE6\x78\xA5\xD2\x79\xA7\x62\xAB\x8E\xF6\xA9\x80\x5F\xAE\xAF\x9C\xA3\xA6\xB2\x73\x8A\x49\xA6\x26\xBC\xA5\xAE\xEA\xA2\xA5\xF4\xA9\xAE\x01\xBB\xAE\xF8\xA7\xA9\x6C\x9C\xAF\x60\xAB\xA5\x99\xAC\x7E\x73\x97\x3B\x20\x17\xB1\x7A\xA4\x9F\x23\x1C\x1B\x17\x01\xA8\x96\x84\xA6\x04\x1B\x9C\x52\x82\x7E\x85\x73\x9D\x34\x15\x9D\x0E\xB9\x45\x81\x7C\x1B\x19\x04\xB2\x98\x8B\xA2\xD4\xA4\xB3\x82\xA7\x13\xBC\x10\x33\x38\xB5\x8D\xB2\x71\xAE\x34\xB1\xB3\x10\xBD\xB3\xD8\x93\xA8\xBA\xA6\x78\x63\x85\xAF\x5D\xAD\xAD\xC8\xAE\xA1\xE6\x95\xAC\x84\x24\xA9\x07\xA9\x7E\x75\xA5\xA5\x07\x97\xA2\x76\x99\xA2\x0B\x97\x13\xF4\x87\x80\x49\xB3\xB4\x1A\xB9\xAA\xAB\xA2\x1A\x4F\xBE\x43\x03\x9E\x6E\x96\xAF\x26\x98\xA2\xAB\x73\xA7\xAB\x25\x92\x7B\x12\xA2\x80\x5F\xB0\xA5\x3E\x92\xB6\x02\xAD\xAA\x01\xA1\xA2\xCA\xAE\x91\xCC\xA0\xB0\xF9\xA7\xB5\xB5\xA8\xA2\x74\xAF\xB6\x23\x1C\xA2\x07\x8C\x34\x60\xBF\x26\x45\x8D\xAE\x57\x10\xB4\x02\x88\xB8\x74\xB4\xAA\x12\xB7\x28\x39\xBE\xAE\x47\xB5\x78\x73\xB8\x10\xFE\x98\xAD\x4C\xB9\x29\x7F\xBF\xAC\xFB\xAD\x25\x59\xAA\xA9\x18\xBC\xB6\x8A\xB7\x32\x03\xB4\xBA\x1F\xBD\xA9\x07\xB7\xB9\x4D\x79\xB9\x04\x1B\xB9\xE6\xA3\xB9\x9E\xB4\xB1\x51\x96\xB1\x04\xB5\xB5\x4B\xB8\x88\x78\xAA\xBA\xFF\xA2\xB4\x9A\x94\xB4\x79\x96\xB3\x60\x8E\x98\x14\xAB\x99\xCA\x71\x8C\x8C\xB9\x10\x8E\xB7\x7F\x90\xB8\x10\xC8\xBB\x78\xCA\xB2\xBC\x92\x80",
|
|
};
|
|
|
|
void JsonGetParserBuffer(vl::stream::MemoryStream& stream)
|
|
{
|
|
vl::stream::MemoryStream compressedStream;
|
|
for (vint i = 0; i < parserBufferRows; i++)
|
|
{
|
|
vint size = i == parserBufferRows - 1 ? parserBufferRemain : parserBufferBlock;
|
|
compressedStream.Write((void*)parserBuffer[i], size);
|
|
}
|
|
compressedStream.SeekFromBegin(0);
|
|
vl::stream::LzwDecoder decoder;
|
|
vl::stream::DecoderStream decoderStream(compressedStream, decoder);
|
|
vl::collections::Array<vl::vuint8_t> buffer(65536);
|
|
while (true)
|
|
{
|
|
vl::vint size = decoderStream.Read(&buffer[0], 65536);
|
|
if (size == 0) break;
|
|
stream.Write(&buffer[0], size);
|
|
}
|
|
stream.SeekFromBegin(0);
|
|
}
|
|
/***********************************************************************
|
|
Unescaping Function Foward Declarations
|
|
***********************************************************************/
|
|
|
|
extern void JsonUnescapingString(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
|
|
/***********************************************************************
|
|
Parsing Tree Conversion Driver Implementation
|
|
***********************************************************************/
|
|
|
|
class JsonTreeConverter : public vl::parsing::ParsingTreeConverter
|
|
{
|
|
public:
|
|
using vl::parsing::ParsingTreeConverter::SetMember;
|
|
|
|
bool SetMember(JsonLiteral::JsonValue& member, vl::Ptr<vl::parsing::ParsingTreeNode> node, const TokenList& tokens)
|
|
{
|
|
vl::Ptr<vl::parsing::ParsingTreeToken> token=node.Cast<vl::parsing::ParsingTreeToken>();
|
|
if(token)
|
|
{
|
|
if(token->GetValue()==L"True") { member=JsonLiteral::JsonValue::True; return true; }
|
|
else if(token->GetValue()==L"False") { member=JsonLiteral::JsonValue::False; return true; }
|
|
else if(token->GetValue()==L"Null") { member=JsonLiteral::JsonValue::Null; return true; }
|
|
else { member=JsonLiteral::JsonValue::True; return false; }
|
|
}
|
|
member=JsonLiteral::JsonValue::True;
|
|
return false;
|
|
}
|
|
|
|
void Fill(vl::Ptr<JsonNode> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
}
|
|
|
|
void Fill(vl::Ptr<JsonLiteral> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->value, obj->GetMember(L"value"), tokens);
|
|
}
|
|
|
|
void Fill(vl::Ptr<JsonString> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
if(SetMember(tree->content, obj->GetMember(L"content"), tokens))
|
|
{
|
|
JsonUnescapingString(tree->content, tokens);
|
|
}
|
|
}
|
|
|
|
void Fill(vl::Ptr<JsonNumber> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->content, obj->GetMember(L"content"), tokens);
|
|
}
|
|
|
|
void Fill(vl::Ptr<JsonArray> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->items, obj->GetMember(L"items"), tokens);
|
|
}
|
|
|
|
void Fill(vl::Ptr<JsonObjectField> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
if(SetMember(tree->name, obj->GetMember(L"name"), tokens))
|
|
{
|
|
JsonUnescapingString(tree->name, tokens);
|
|
}
|
|
SetMember(tree->value, obj->GetMember(L"value"), tokens);
|
|
}
|
|
|
|
void Fill(vl::Ptr<JsonObject> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->fields, obj->GetMember(L"fields"), tokens);
|
|
}
|
|
|
|
vl::Ptr<vl::parsing::ParsingTreeCustomBase> ConvertClass(vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)override
|
|
{
|
|
if(obj->GetType()==L"Literal")
|
|
{
|
|
vl::Ptr<JsonLiteral> tree = new JsonLiteral;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<JsonNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"String")
|
|
{
|
|
vl::Ptr<JsonString> tree = new JsonString;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<JsonNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Number")
|
|
{
|
|
vl::Ptr<JsonNumber> tree = new JsonNumber;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<JsonNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Array")
|
|
{
|
|
vl::Ptr<JsonArray> tree = new JsonArray;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<JsonNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"ObjectField")
|
|
{
|
|
vl::Ptr<JsonObjectField> tree = new JsonObjectField;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<JsonNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Object")
|
|
{
|
|
vl::Ptr<JsonObject> tree = new JsonObject;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<JsonNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
vl::Ptr<vl::parsing::ParsingTreeCustomBase> JsonConvertParsingTreeNode(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
JsonTreeConverter converter;
|
|
vl::Ptr<vl::parsing::ParsingTreeCustomBase> tree;
|
|
converter.SetMember(tree, node, tokens);
|
|
return tree;
|
|
}
|
|
|
|
/***********************************************************************
|
|
Parsing Tree Conversion Implementation
|
|
***********************************************************************/
|
|
|
|
vl::Ptr<JsonLiteral> JsonLiteral::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonLiteral>();
|
|
}
|
|
|
|
vl::Ptr<JsonString> JsonString::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonString>();
|
|
}
|
|
|
|
vl::Ptr<JsonNumber> JsonNumber::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonNumber>();
|
|
}
|
|
|
|
vl::Ptr<JsonArray> JsonArray::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonArray>();
|
|
}
|
|
|
|
vl::Ptr<JsonObjectField> JsonObjectField::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonObjectField>();
|
|
}
|
|
|
|
vl::Ptr<JsonObject> JsonObject::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return JsonConvertParsingTreeNode(node, tokens).Cast<JsonObject>();
|
|
}
|
|
|
|
/***********************************************************************
|
|
Parser Function
|
|
***********************************************************************/
|
|
|
|
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)
|
|
{
|
|
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
|
|
state.Reset(L"JRoot");
|
|
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
|
|
return node;
|
|
}
|
|
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> JsonParseAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
|
|
{
|
|
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
|
|
return JsonParseAsParsingTreeNode(input, table, errors, codeIndex);
|
|
}
|
|
|
|
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)
|
|
{
|
|
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
|
|
state.Reset(L"JRoot");
|
|
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
|
|
if(node && errors.Count()==0)
|
|
{
|
|
return JsonConvertParsingTreeNode(node, state.GetTokens()).Cast<JsonNode>();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
vl::Ptr<JsonNode> JsonParse(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
|
|
{
|
|
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
|
|
return JsonParse(input, table, errors, codeIndex);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Table Generation
|
|
***********************************************************************/
|
|
|
|
vl::Ptr<vl::parsing::tabling::ParsingTable> JsonLoadTable()
|
|
{
|
|
vl::stream::MemoryStream stream;
|
|
JsonGetParserBuffer(stream);
|
|
vl::Ptr<vl::parsing::tabling::ParsingTable> table=new vl::parsing::tabling::ParsingTable(stream);
|
|
table->Initialize();
|
|
return table;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\PARSINGXML.CPP
|
|
***********************************************************************/
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace xml
|
|
{
|
|
using namespace stream;
|
|
using namespace collections;
|
|
using namespace regex;
|
|
|
|
/***********************************************************************
|
|
Unescaping Function Foward Declarations
|
|
***********************************************************************/
|
|
|
|
void XmlMergeTextFragment(vl::collections::List<vl::Ptr<XmlNode>>& value, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
vint begin=-1;
|
|
vint end=-1;
|
|
for(vint i=value.Count()-1;i>=-1;i--)
|
|
{
|
|
if(i==-1)
|
|
{
|
|
if(end!=-1) begin=0;
|
|
}
|
|
else if(value[i].Cast<XmlText>())
|
|
{
|
|
if(end==-1) end=i;
|
|
}
|
|
else
|
|
{
|
|
if(end!=-1) begin=i+1;
|
|
}
|
|
if(begin!=-1 && end!=-1)
|
|
{
|
|
vint tokenBegin=value[begin].Cast<XmlText>()->content.tokenIndex;
|
|
vint tokenEnd=value[end].Cast<XmlText>()->content.tokenIndex;
|
|
while(tokenBegin>0)
|
|
{
|
|
if(tokens.Get(tokenBegin-1).token==(vint)XmlParserTokenIndex::SPACE || tokens.Get(tokenBegin-1).token==-1)
|
|
{
|
|
tokenBegin--;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
while(tokenEnd<tokens.Count()-1)
|
|
{
|
|
if(tokens.Get(tokenEnd+1).token==(vint)XmlParserTokenIndex::SPACE || tokens.Get(tokenEnd+1).token==-1)
|
|
{
|
|
tokenEnd++;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
const RegexToken& beginToken=tokens.Get(tokenBegin);
|
|
const RegexToken& endToken=tokens.Get(tokenEnd);
|
|
const wchar_t* textBegin=beginToken.reading;
|
|
const wchar_t* textEnd=endToken.reading+endToken.length;
|
|
WString text(textBegin, vint(textEnd-textBegin));
|
|
ParsingTextRange range(&beginToken, &endToken);
|
|
|
|
Ptr<XmlText> xmlText=new XmlText;
|
|
xmlText->codeRange=range;
|
|
xmlText->content.codeRange=range;
|
|
xmlText->content.value=XmlUnescapeValue(text);
|
|
|
|
value.RemoveRange(begin, end-begin+1);
|
|
value.Insert(begin, xmlText);
|
|
|
|
begin=-1;
|
|
end=-1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void XmlUnescapeAttributeValue(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
value.value=XmlUnescapeValue(value.value.Sub(1, value.value.Length()-2));
|
|
}
|
|
|
|
void XmlUnescapeCData(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
value.value=XmlUnescapeCData(value.value);
|
|
}
|
|
|
|
void XmlUnescapeComment(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
value.value=XmlUnescapeComment(value.value);
|
|
}
|
|
|
|
/***********************************************************************
|
|
XmlPrintVisitor
|
|
***********************************************************************/
|
|
|
|
class XmlPrintVisitor : public Object, public XmlNode::IVisitor
|
|
{
|
|
public:
|
|
TextWriter& writer;
|
|
|
|
XmlPrintVisitor(TextWriter& _writer)
|
|
:writer(_writer)
|
|
{
|
|
}
|
|
|
|
void Visit(XmlText* node)
|
|
{
|
|
writer.WriteString(XmlEscapeValue(node->content.value));
|
|
}
|
|
|
|
void Visit(XmlCData* node)
|
|
{
|
|
writer.WriteString(XmlEscapeCData(node->content.value));
|
|
}
|
|
|
|
void Visit(XmlAttribute* node)
|
|
{
|
|
writer.WriteString(node->name.value);
|
|
writer.WriteString(L"=\"");
|
|
writer.WriteString(XmlEscapeValue(node->value.value));
|
|
writer.WriteString(L"\"");
|
|
}
|
|
|
|
void Visit(XmlComment* node)
|
|
{
|
|
writer.WriteString(XmlEscapeComment(node->content.value));
|
|
}
|
|
|
|
void Visit(XmlElement* node)
|
|
{
|
|
writer.WriteChar(L'<');
|
|
writer.WriteString(node->name.value);
|
|
FOREACH(Ptr<XmlAttribute>, att, node->attributes)
|
|
{
|
|
writer.WriteChar(L' ');
|
|
att->Accept(this);
|
|
}
|
|
if(node->subNodes.Count()==0)
|
|
{
|
|
writer.WriteString(L"/>");
|
|
}
|
|
else
|
|
{
|
|
writer.WriteChar(L'>');
|
|
FOREACH(Ptr<XmlNode>, subNode, node->subNodes)
|
|
{
|
|
subNode->Accept(this);
|
|
}
|
|
writer.WriteString(L"</");
|
|
writer.WriteString(node->name.value);
|
|
writer.WriteChar(L'>');
|
|
}
|
|
}
|
|
|
|
void Visit(XmlInstruction* node)
|
|
{
|
|
writer.WriteString(L"<?");
|
|
writer.WriteString(node->name.value);
|
|
FOREACH(Ptr<XmlAttribute>, att, node->attributes)
|
|
{
|
|
writer.WriteChar(L' ');
|
|
att->Accept(this);
|
|
}
|
|
writer.WriteString(L"?>");
|
|
}
|
|
|
|
void Visit(XmlDocument* node)
|
|
{
|
|
FOREACH(Ptr<XmlNode>, prolog, node->prologs)
|
|
{
|
|
prolog->Accept(this);
|
|
}
|
|
node->rootElement->Accept(this);
|
|
}
|
|
};
|
|
|
|
/***********************************************************************
|
|
API
|
|
***********************************************************************/
|
|
|
|
WString XmlEscapeValue(const WString& value)
|
|
{
|
|
WString result;
|
|
const wchar_t* reading=value.Buffer();
|
|
while(wchar_t c=*reading++)
|
|
{
|
|
switch(c)
|
|
{
|
|
case L'<':
|
|
result+=L"<";
|
|
break;
|
|
case L'>':
|
|
result+=L">";
|
|
break;
|
|
case L'&':
|
|
result+=L"&";
|
|
break;
|
|
case L'\'':
|
|
result+=L"'";
|
|
break;
|
|
case L'\"':
|
|
result+=L""";
|
|
break;
|
|
default:
|
|
result+=c;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
WString XmlUnescapeValue(const WString& value)
|
|
{
|
|
WString result;
|
|
const wchar_t* reading=value.Buffer();
|
|
while(*reading)
|
|
{
|
|
if(wcsncmp(reading, L"<", 4)==0)
|
|
{
|
|
result+=L'<';
|
|
reading+=4;
|
|
}
|
|
else if(wcsncmp(reading, L">", 4)==0)
|
|
{
|
|
result+=L'>';
|
|
reading+=4;
|
|
}
|
|
else if(wcsncmp(reading, L"&", 5)==0)
|
|
{
|
|
result+=L'&';
|
|
reading+=5;
|
|
}
|
|
else if(wcsncmp(reading, L"'", 6)==0)
|
|
{
|
|
result+=L'\'';
|
|
reading+=6;
|
|
}
|
|
else if(wcsncmp(reading, L""", 6)==0)
|
|
{
|
|
result+=L'\"';
|
|
reading+=6;
|
|
}
|
|
else
|
|
{
|
|
result+=*reading++;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
WString XmlEscapeCData(const WString& value)
|
|
{
|
|
return L"<![CDATA["+value+L"]]>";
|
|
}
|
|
|
|
WString XmlUnescapeCData(const WString& value)
|
|
{
|
|
return value.Sub(9, value.Length()-12);
|
|
}
|
|
|
|
WString XmlEscapeComment(const WString& value)
|
|
{
|
|
return L"<!--"+value+L"-->";
|
|
}
|
|
|
|
WString XmlUnescapeComment(const WString& value)
|
|
{
|
|
return value.Sub(4, value.Length()-7);
|
|
}
|
|
|
|
void XmlPrint(Ptr<XmlNode> node, stream::TextWriter& writer)
|
|
{
|
|
XmlPrintVisitor visitor(writer);
|
|
node->Accept(&visitor);
|
|
}
|
|
|
|
void XmlPrintContent(Ptr<XmlElement> element, stream::TextWriter& writer)
|
|
{
|
|
XmlPrintVisitor visitor(writer);
|
|
FOREACH(Ptr<XmlNode>, node, element->subNodes)
|
|
{
|
|
node->Accept(&visitor);
|
|
}
|
|
}
|
|
|
|
WString XmlToString(Ptr<XmlNode> node)
|
|
{
|
|
return GenerateToStream([&](StreamWriter& writer)
|
|
{
|
|
XmlPrint(node, writer);
|
|
});
|
|
}
|
|
|
|
/***********************************************************************
|
|
Linq To Xml
|
|
***********************************************************************/
|
|
|
|
Ptr<XmlAttribute> XmlGetAttribute(Ptr<XmlElement> element, const WString& name)
|
|
{
|
|
return XmlGetAttribute(element.Obj(), name);
|
|
}
|
|
|
|
Ptr<XmlElement> XmlGetElement(Ptr<XmlElement> element, const WString& name)
|
|
{
|
|
return XmlGetElement(element.Obj(), name);
|
|
}
|
|
|
|
collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element)
|
|
{
|
|
return XmlGetElements(element.Obj());
|
|
}
|
|
|
|
collections::LazyList<Ptr<XmlElement>> XmlGetElements(Ptr<XmlElement> element, const WString& name)
|
|
{
|
|
return XmlGetElements(element.Obj(), name);
|
|
}
|
|
|
|
WString XmlGetValue(Ptr<XmlElement> element)
|
|
{
|
|
return XmlGetValue(element.Obj());
|
|
}
|
|
|
|
Ptr<XmlAttribute> XmlGetAttribute(XmlElement* element, const WString& name)
|
|
{
|
|
FOREACH(Ptr<XmlAttribute>, att, element->attributes)
|
|
{
|
|
if(att->name.value==name)
|
|
{
|
|
return att;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Ptr<XmlElement> XmlGetElement(XmlElement* element, const WString& name)
|
|
{
|
|
FOREACH(Ptr<XmlNode>, node, element->subNodes)
|
|
{
|
|
Ptr<XmlElement> subElement=node.Cast<XmlElement>();
|
|
if(subElement && subElement->name.value==name)
|
|
{
|
|
return subElement;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element)
|
|
{
|
|
return From(element->subNodes)
|
|
.FindType<XmlElement>();
|
|
}
|
|
|
|
collections::LazyList<Ptr<XmlElement>> XmlGetElements(XmlElement* element, const WString& name)
|
|
{
|
|
return From(element->subNodes)
|
|
.FindType<XmlElement>()
|
|
.Where([name](Ptr<XmlElement> e){return e->name.value==name;});
|
|
}
|
|
|
|
WString XmlGetValue(XmlElement* element)
|
|
{
|
|
WString result;
|
|
FOREACH(Ptr<XmlNode>, node, element->subNodes)
|
|
{
|
|
if(Ptr<XmlText> text=node.Cast<XmlText>())
|
|
{
|
|
result+=text->content.value;
|
|
}
|
|
else if(Ptr<XmlCData> text=node.Cast<XmlCData>())
|
|
{
|
|
result+=text->content.value;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/***********************************************************************
|
|
XmlElementWriter
|
|
***********************************************************************/
|
|
|
|
XmlElementWriter::XmlElementWriter(Ptr<XmlElement> _element, const XmlElementWriter* _previousWriter)
|
|
:element(_element)
|
|
,previousWriter(_previousWriter)
|
|
{
|
|
}
|
|
|
|
XmlElementWriter::~XmlElementWriter()
|
|
{
|
|
}
|
|
|
|
const XmlElementWriter& XmlElementWriter::Attribute(const WString& name, const WString& value)const
|
|
{
|
|
Ptr<XmlAttribute> node=new XmlAttribute;
|
|
node->name.value=name;
|
|
node->value.value=value;
|
|
element->attributes.Add(node);
|
|
return *this;
|
|
}
|
|
|
|
XmlElementWriter XmlElementWriter::Element(const WString& name)const
|
|
{
|
|
Ptr<XmlElement> node=new XmlElement;
|
|
node->name.value=name;
|
|
element->subNodes.Add(node);
|
|
return XmlElementWriter(node, this);
|
|
}
|
|
|
|
const XmlElementWriter& XmlElementWriter::End()const
|
|
{
|
|
return *previousWriter;
|
|
}
|
|
|
|
const XmlElementWriter& XmlElementWriter::Text(const WString& value)const
|
|
{
|
|
Ptr<XmlText> node=new XmlText;
|
|
node->content.value=value;
|
|
element->subNodes.Add(node);
|
|
return *this;
|
|
}
|
|
|
|
const XmlElementWriter& XmlElementWriter::CData(const WString& value)const
|
|
{
|
|
Ptr<XmlCData> node=new XmlCData;
|
|
node->content.value=value;
|
|
element->subNodes.Add(node);
|
|
return *this;
|
|
}
|
|
|
|
const XmlElementWriter& XmlElementWriter::Comment(const WString& value)const
|
|
{
|
|
Ptr<XmlComment> node=new XmlComment;
|
|
node->content.value=value;
|
|
element->subNodes.Add(node);
|
|
return *this;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\PARSINGXML_AST.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingXml.parser.txt
|
|
|
|
This file is generated by: Vczh Parser Generator
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace xml
|
|
{
|
|
/***********************************************************************
|
|
Visitor Pattern Implementation
|
|
***********************************************************************/
|
|
|
|
void XmlText::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlCData::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlAttribute::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlComment::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlElement::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlInstruction::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
void XmlDocument::Accept(XmlNode::IVisitor* visitor)
|
|
{
|
|
visitor->Visit(this);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
namespace vl
|
|
{
|
|
namespace reflection
|
|
{
|
|
namespace description
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
using namespace vl::parsing::xml;
|
|
|
|
#define PARSING_TOKEN_FIELD(NAME)\
|
|
CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(get_##NAME, NO_PARAMETER, vl::WString(ClassType::*)(), [](ClassType* node) { return node->NAME.value; }, L"*", L"*")\
|
|
CLASS_MEMBER_EXTERNALMETHOD_TEMPLATE(set_##NAME, { L"value" }, void(ClassType::*)(const vl::WString&), [](ClassType* node, const vl::WString& value) { node->NAME.value = value; }, L"*", L"*")\
|
|
CLASS_MEMBER_PROPERTY_REFERENCETEMPLATE(NAME, get_##NAME, set_##NAME, L"$This->$Name.value")\
|
|
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlNode, system::XmlNode)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlText, system::XmlText)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlCData, system::XmlCData)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlAttribute, system::XmlAttribute)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlComment, system::XmlComment)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlElement, system::XmlElement)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlInstruction, system::XmlInstruction)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlDocument, system::XmlDocument)
|
|
IMPL_TYPE_INFO_RENAME(vl::parsing::xml::XmlNode::IVisitor, system::XmlNode::IVisitor)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlNode)
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Accept, {L"visitor"}, void(XmlNode::*)(XmlNode::IVisitor* visitor))
|
|
END_CLASS_MEMBER(XmlNode)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlText)
|
|
CLASS_MEMBER_BASE(XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<XmlText>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(content)
|
|
END_CLASS_MEMBER(XmlText)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlCData)
|
|
CLASS_MEMBER_BASE(XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<XmlCData>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(content)
|
|
END_CLASS_MEMBER(XmlCData)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlAttribute)
|
|
CLASS_MEMBER_BASE(XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<XmlAttribute>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(name)
|
|
PARSING_TOKEN_FIELD(value)
|
|
END_CLASS_MEMBER(XmlAttribute)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlComment)
|
|
CLASS_MEMBER_BASE(XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<XmlComment>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(content)
|
|
END_CLASS_MEMBER(XmlComment)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlElement)
|
|
CLASS_MEMBER_BASE(XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<XmlElement>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(name)
|
|
PARSING_TOKEN_FIELD(closingName)
|
|
CLASS_MEMBER_FIELD(attributes)
|
|
CLASS_MEMBER_FIELD(subNodes)
|
|
END_CLASS_MEMBER(XmlElement)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlInstruction)
|
|
CLASS_MEMBER_BASE(XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<XmlInstruction>(), NO_PARAMETER)
|
|
|
|
PARSING_TOKEN_FIELD(name)
|
|
CLASS_MEMBER_FIELD(attributes)
|
|
END_CLASS_MEMBER(XmlInstruction)
|
|
|
|
BEGIN_CLASS_MEMBER(XmlDocument)
|
|
CLASS_MEMBER_BASE(XmlNode)
|
|
|
|
CLASS_MEMBER_CONSTRUCTOR(vl::Ptr<XmlDocument>(), NO_PARAMETER)
|
|
|
|
CLASS_MEMBER_FIELD(prologs)
|
|
CLASS_MEMBER_FIELD(rootElement)
|
|
END_CLASS_MEMBER(XmlDocument)
|
|
|
|
BEGIN_INTERFACE_MEMBER(XmlNode::IVisitor)
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlText* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlCData* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlAttribute* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlComment* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlElement* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlInstruction* node))
|
|
CLASS_MEMBER_METHOD_OVERLOAD(Visit, {L"node"}, void(XmlNode::IVisitor::*)(XmlDocument* node))
|
|
END_INTERFACE_MEMBER(XmlNode)
|
|
|
|
#undef PARSING_TOKEN_FIELD
|
|
|
|
class XmlTypeLoader : public vl::Object, public ITypeLoader
|
|
{
|
|
public:
|
|
void Load(ITypeManager* manager)
|
|
{
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlNode)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlText)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlCData)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlAttribute)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlComment)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlElement)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlInstruction)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlDocument)
|
|
ADD_TYPE_INFO(vl::parsing::xml::XmlNode::IVisitor)
|
|
}
|
|
|
|
void Unload(ITypeManager* manager)
|
|
{
|
|
}
|
|
};
|
|
#endif
|
|
|
|
bool XmlLoadTypes()
|
|
{
|
|
#ifndef VCZH_DEBUG_NO_REFLECTION
|
|
ITypeManager* manager=GetGlobalTypeManager();
|
|
if(manager)
|
|
{
|
|
Ptr<ITypeLoader> loader=new XmlTypeLoader;
|
|
return manager->AddTypeLoader(loader);
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\XML\PARSINGXML_PARSER.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Vczh Library++ 3.0
|
|
Developer: Zihan Chen(vczh)
|
|
Parser::ParsingXml.parser.txt
|
|
|
|
This file is generated by: Vczh Parser Generator
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace parsing
|
|
{
|
|
namespace xml
|
|
{
|
|
/***********************************************************************
|
|
ParserText
|
|
***********************************************************************/
|
|
|
|
const wchar_t* const parserTextBuffer[] = {
|
|
L"" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"// AST" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Text : Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken content;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class CData : Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken content (XmlUnescapeCData);" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Attribute : Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken name\t\t\t\t\t\t\t\t\t@Color(\"AttName\");" L"\r\n"
|
|
, L"\ttoken value (XmlUnescapeAttributeValue)\t\t@Color(\"AttValue\");" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Comment : Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken content (XmlUnescapeComment);" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Element : Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken name\t\t\t\t\t\t\t\t\t@Color(\"TagName\");" L"\r\n"
|
|
, L"\ttoken closingName\t\t\t\t\t\t\t@Color(\"TagName\");" L"\r\n"
|
|
, L"\tAttribute[] attributes;" L"\r\n"
|
|
, L"\tNode[] subNodes (XmlMergeTextFragment);" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Instruction : Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\ttoken name\t\t\t\t\t\t\t\t\t@Color(\"TagName\");" L"\r\n"
|
|
, L"\tAttribute[] attributes;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"class Document : Node" L"\r\n"
|
|
, L"{" L"\r\n"
|
|
, L"\tNode[] prologs;" L"\r\n"
|
|
, L"\tElement rootElement;" L"\r\n"
|
|
, L"}" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"// Lexer" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"token INSTRUCTION_OPEN = \"/</?\"\t\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token INSTRUCTION_CLOSE = \"/?/>\"\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token COMPLEX_ELEMENT_OPEN = \"/<//\"\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token SINGLE_ELEMENT_CLOSE = \"///>\"\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token ELEMENT_OPEN = \"/<\"\t\t\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token ELEMENT_CLOSE = \"/>\"\t\t\t\t@Color(\"Boundary\");" L"\r\n"
|
|
, L"token EQUAL = \"/=\";" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"token NAME = \"[a-zA-Z0-9:._/-]+\"\t\t\t\t\t\t\t\t@ContextColor();" L"\r\n"
|
|
, L"token ATTVALUE = \"\"\"[^<>\"\"]*\"\"|\'[^<>\']*\'\"\t\t\t\t\t\t@ContextColor();" L"\r\n"
|
|
, L"token COMMENT = \"/</!--([^/->]|-[^/->]|--[^>])*--/>\"\t\t\t@Color(\"Comment\");" L"\r\n"
|
|
, L"token CDATA = \"/</!/[CDATA/[([^/]]|/][^/]]|/]/][^>])*/]/]/>\";" L"\r\n"
|
|
, L"token TEXT = \"([^<>=\"\"\' /r/n/ta-zA-Z0-9:._/-])+|\"\"|\'\";" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"discardtoken SPACE = \"/s+\";" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"// Rules" L"\r\n"
|
|
, L"//////////////////////////////////////////////////////////////////" L"\r\n"
|
|
, L"" L"\r\n"
|
|
, L"rule Attribute XAttribute = NAME:name \"=\" ATTVALUE:value as Attribute;" L"\r\n"
|
|
, L"rule Text XText = (NAME:content | EQUAL:content | ATTVALUE:content | TEXT:content) as Text;" L"\r\n"
|
|
, L"rule CData XCData = CDATA:content as CData;" L"\r\n"
|
|
, L"rule Comment XComment = COMMENT:content as Comment;" L"\r\n"
|
|
, L"rule Element XElement = \"<\" NAME:name {XAttribute:attributes} (\"/>\" | \">\" {XSubNode:subNodes} \"</\" NAME:closingName \">\") as Element;" L"\r\n"
|
|
, L"rule Node XSubNode = !XText | !XCData | !XComment | !XElement;" L"\r\n"
|
|
, L"rule Instruction XInstruction = \"<?\" NAME:name {XAttribute:attributes} \"?>\" as Instruction;" L"\r\n"
|
|
, L"rule Document XDocument = {XInstruction:prologs | XComment:prologs} XElement:rootElement as Document;" L"\r\n"
|
|
};
|
|
const vint lengthTextBuffer[] = {
|
|
2, 68, 8, 68, 2, 12, 3, 3, 2, 19, 3, 17, 3, 2, 20, 3, 36, 3, 2, 24, 3, 40, 63, 3, 2, 22, 3, 38, 3, 2, 22, 3
|
|
, 40, 45, 26, 42, 3, 2, 26, 3, 40, 26, 3, 2, 23, 3, 18, 23, 3, 2, 68, 10, 68, 2, 55, 55, 58, 58, 50, 51, 21, 2, 58, 65
|
|
, 75, 63, 56, 2, 29, 2, 68, 10, 68, 2, 72, 93, 45, 53, 134, 64, 93, 103
|
|
};
|
|
const vint lengthTextBufferTotal = 2487;
|
|
|
|
vl::WString XmlGetParserTextBuffer()
|
|
{
|
|
vl::collections::Array<wchar_t> textBuffer(lengthTextBufferTotal + 1);
|
|
wchar_t* reading = &textBuffer[0];
|
|
for(vint i = 0; i < sizeof(parserTextBuffer) / sizeof(*parserTextBuffer); i++)
|
|
{
|
|
memcpy(reading, parserTextBuffer[i], lengthTextBuffer[i] * sizeof(wchar_t));
|
|
reading += lengthTextBuffer[i];
|
|
}
|
|
*reading = 0;
|
|
return &textBuffer[0];
|
|
}
|
|
|
|
/***********************************************************************
|
|
SerializedTable
|
|
***********************************************************************/
|
|
|
|
const vint parserBufferLength = 4440; // 18926 bytes before compressing
|
|
const vint parserBufferBlock = 1024;
|
|
const vint parserBufferRemain = 344;
|
|
const vint parserBufferRows = 5;
|
|
const char* const parserBuffer[] = {
|
|
"\x00\x0E\x00\x02\x83\x80\x07\x7D\x00\x82\x03\xFF\x45\x08\x82\x83\x86\x81\x21\x6F\x6C\x2F\x32\x37\x84\x87\x02\x86\x00\x17\x82\x81\x24\x3C\x3A\x27\x30\x6D\x65\x06\x98\x8A\x80\x8E\x86\x00\x10\x92\x94\x98\x88\x04\x97\x80\x8E\x74\x56\x21\x2C\x35\x3A\x91\x8A\x84\x25\x8C\xA7\x89\x93\x8F\x98\x82\x8D\x08\xC0\x94\x21\x37\x37\x8D\x91\x91\x0C\xB9\x88\x9B\x91\x8D\x9C\x8C\xA0\x3F\x83\x83\xA5\xA0\x96\x98\x93\x93\x04\xCC\xAA\x9E\x93\x80\xA9\xAE\xA9\x44\xC6\x96\xA9\xA8\xAB\x82\xAC\xA7\x0C\xAD\xA9\xA3\x82\x27\x35\x3A\x37\x64\x61\x32\x39\x38\xA0\x9D\xB3\x86\x03\xBC\xAB\x8B\xBC\xB8\x01\xB7\xB7\x71\xF3\xB5\xA4\x8A\xA1\xAD\xBD\xA6\x7B\x88\xAA\xAA\xCC\xB6\xB4\xB8\xB9\x74\xDC\x82\x85\xC6\xB7\xC3\xAC\x97\x7D\xFF\x8F\xC2\xC2\xCD\x83\xBA\x00\x67\x89\xC4\x8B\xC3\xD5\xC4\xC0\xC8\x83\x89\x9F\xC1\xDD\xCC\xD3\x81\xC5\x9A\x81\xD1\xC4\x9C\x00\x8D\xDB\x87\x6F\x6E\x34\x25\x38\x3C\x3A\xBC\x8C\x05\x9D\xFF\x77\xD8\x84\xE0\x88\xDD\xBC\xBE\xC8\xC0\xE9\xD3\xCB\xD4\xCB\x68\xC1\x8F\xA7\xCD\x31\x92\xDC\xD7\x02\x89\x18\x9A\xEB\x8D\x8E\x39\x34\x62\x75\x3B\xDF\x74\xF5\xF0\xF3\xE7\x0F\xC4\x21\x34\x31\x36\xF2\xF2\xAF\x02\xC0\x90\x95\xE5\x32\xDE\xF7\xF2\xD8\x80\x0B\xC4\x2F\x33\x31\x3A\xEB\x74\x37\x74\x78\x7C\x19\x43\x45\x10\x1B\x65\x00\x82\x83\x3F\x0B\x18\x4D\x82\x40\x49\x2E\x13\x1C\x1D\x72\x35\x13\x18\x1D\x69\x39\x6B\x80\x01\x18\x5C\x82\x42\x13\x6F\x24\x12\x4A\x80\x1E\x88\x45\x88\x15\xC9\x4B\x8D\x03\x76\x2C\x9D\x74\x84\x78\xE2\x65\x15\x88\x41\x25\xAE\x15\x54\x70\xDC\x48\x49\x8C\x4C\xDF\x61\x7B\x6C\x7A\x00\x36\x13\x4D\x4D\x9D\x40\x93\x12\x7A\xEC\x44\x80\x53\x18\xB9\x7B\x66\x7E\x80\x4A\x94\x70\x81\x94\x02\x4C\x98\x73\x93\xF7\x79\x7B\x7D\x7F\xFF\x75\x74\x1C\x95\x00\x30\x12\x1D\x53\x67\x33\x1B\x82\x96\x03\x7C\x7E\x7C\x80\x0F\x88\x4D\x9B\x98\x6F\x34\x17\x81\x82\x5E\x8B\x80\x9B\x9C\x00\x8A\x08\x46\x9E\x02\x6B\x7F\x8A\x8F\x65\x26\x90\x97\x74\x02\x78\x9E\x95\x9B\x04\x6D\x93\x1A\x44\x73\x29\x1E\x18\x55\x21\x43\x04\xA2\x74\x85\x88\x80\x83\x8C\x03\x75\x85\x56\x00\x93\x91\x55\xA4\x9D\xD7\x58\x60\x03\x1C\x75\x22\x10\x8A\x88\x82\xB7\x78\xA3\x40\x6D\x91\x83\x85\x85\x17\x99\x8E\x18\x9F\x08\x74\xAE\x9D\x8F\x31\xA9\xAE\x7B\xAA\x02\x6D\xA2\x84\x85\x16\x98\x89\x6C\xA6\x02\x5A\xA1\x48\xB1\x00\x08\xB7\x89\x72\x60\x96\x9E\x91\x80\x02\x90\x08\x45\x0C\x18\x52\xB0\x73\xB5\x38\x4B\x82\x80\xB6\x49\x5A\xB7\x7C\xB7\xD9\x9E\xB6\x78\xB8\x84\x62\xB6\x7A\xB5\x08\x68\xB9\x12\x13\x53\x14\x12\x15\x15\x43\x14\x19\x13\x13\x4E\x1F\x1F\x10\x14\x45\x0E\x1A\xB3\x40\x2F\x3C\x0F\x0B\x0F\xC0\x5F\x61\x04\x46\x03\xD0\x8C\xBA\xBB\xF0\xB2\xB4\xBF\x17\x43\x0C\x1F\x13\x14\x45\x3B\xB2\x43\xBF\x2F\x3E\x0D\x66\x01\x18\x54\x09\xC5\x5E\x4F\x0D\x10\x14\x13\x45\x18\x1F\x15\x11\x20\xCD\x19\xBC\x15\xF6\xB8\xBA\xBD\x87\xFC\xBE\xBF\x08\xA7\x16\x5B\xCC\x42\xC6\x02\x53\x1B\xBB\x11\x20\xE3\xC5\xCB\xC9\x0C\xCE\xC0\xC6\xC4\x00\x2F\x02\xD2\x0F\x92\xBD\x54\x40\x71\x47\xC6\x8B\xCE\x13\x28\xF7\xB9\xBC\xCC\x08\x50\xDD\xBC\xB2\x39\x84\x4B\x88\x43\x57\xC0\x04\xC9\x11\x26\xCC\xDD\xCF\xC3\x45\x10\xD4\x42\xD4\x3E\x1F\x64\xAE\x61\x3A\x46\x81\x15\x15\x41\x0C\x12\xDB\x40\x52\xFD\x08\xC5\xB7\xF7\x40\xDE\x11\x10\x26\xC5\xC8\x42\xDE\x5B\x21\x1D\x0A\x1E\x41\x2D\x0A\x14\x0C\x2D\x39\x0A\x0E\x0B\x5F\x2F\x0D\x09\x17\x2B\x04\x8C\xAE\x7E\xA2\x81\x14\x14\x15\x56\x2D\xD5\x15\x11\x13\x18\x49\xE6\x40\x22\x1B\x1E\x14\x0F\x3E\x22\x0D\x16\x0A\x22\x3C\x17\x0A\xE7\xA0\xE7\x03\xEB\x09\xF9\x48\xDF\x55\xCC\x0F\x5D\xCD\xD4\x15\x22\x18\x45\xEF\xC4\xFE\xA1\x0D\x09\x0B\x28\x1E\xEA\xE2\x0F\x5D\x3C\x1D\x0A\xEF\x2D\x00\xF2\xF3\xF0\x5E\x00\xF9\x0A\x0A\xBB\xD5\xC5\xD7\x40\x59\xE8\xDB\x51\x5E\x44\x12\xE1\x10\x0B\x18\x58\xF8\xEF\x0B\x21\x2F\x0B\x17\x91\xD6\xDE\xFD\xEE\x17\x2F\x1D\x11\xF1\xF9\xBE\xE6\xFC\x1D\xF9\xE8\xC9\xFD\x17\xF2\xEC\xDD\x15\xC7\xD9\x09\x64\x8C\xCA\x40\x54\x21\xC4\x14\x09\x18\x7C\xF2\x43\xF8\xA0\x7D\x06\x08\x27\x00\x05\x17\x32\x0F\x05\x6E\x0F\x04\x7B\x7F\x61\x71\xC1\x45\x77\x70\x89\x6B\x71\x0A\x2B\x0C\x0F\xD2\x67\x07\x71\x0B\x45\x4A\x49\x03\x23\x0A\x28\x01\x0B\x08\x45\x05\x68\x42\x22\x8F\x05\x39\x2B\x06\x75\x93\x22\x40\xB5\x0C\x24\x7E\x81\x34\x50\x0B\x3C\x50\x47\x6E\x34\x68\x20\x1A\xB0\x86\x3B\x32\x85\x0E\x0B\x52\x0F\x0D\x38\x53\x0C\x3D\x72\x14\x0F\x03\x18\x23\x88",
|
|
"\x81\x00\x08\x04\x24\x1C\x07\x0D\xFF\x41\x46\x1F\x2D\x80\x00\x2F\x91\x84\xA0\x68\x54\x20\x74\x4B\x88\x57\xBB\x2E\x07\x0F\xF2\x24\x0F\x80\x0C\x26\x8B\x00\x07\x8A\x12\xD2\x8D\x89\x27\x91\x88\x87\x80\x48\x84\x00\x44\x37\x8B\x1C\xAE\x01\x06\x3C\x18\x21\x1C\x82\x23\x8C\x34\x8D\x8A\x07\x20\x17\x6E\xC9\x20\x08\x8E\x1B\x61\x27\x88\x22\x02\x80\x08\x12\x74\x72\xCB\x45\x0C\x8F\x20\x02\x48\x4D\x65\x00\x05\x30\x33\x0B\x90\x76\x9B\x36\x19\x83\x2D\x8D\x34\xB6\x34\x92\x64\x99\x8A\x0C\x73\x88\x20\x4E\xB5\x8C\x89\xBB\x3E\x04\x1E\xFA\x87\x91\x3E\x95\x28\x04\x81\x82\x07\x11\x84\x95\x72\x26\x17\x70\x91\x8A\x95\x25\x23\x8F\x99\x93\x32\x13\x92\x20\x95\x91\x46\x1A\xEC\x85\x96\x17\x33\x04\x93\x04\x3E\x91\x2E\xA1\x93\x94\xBC\x65\x90\x04\x7E\x8C\x91\x2A\x83\x93\x73\x56\xAF\x90\x8F\xB1\x8C\x92\x23\x90\x90\x95\x32\x00\x0F\x96\x00\x03\x99\x19\x12\x08\x22\x6E\xB8\x95\x97\x3C\x91\x4D\x11\x70\x25\x88\x84\x25\x99\x89\xDA\x9E\x04\x08\x40\x08\x4C\x5C\x86\x52\x37\xD8\x98\x0B\x3B\xF4\x0E\x04\x19\x0E\x02\x32\xF7\x94\x8E\x3C\x96\x5E\x4A\x51\xA8\x94\x07\x22\x19\x8E\x31\x88\x99\x99\x23\xBB\x08\x04\xDA\x88\x93\xAD\x39\x8F\x91\x3E\x20\x00\x05\xA8\x95\x61\x40\xFC\x08\x95\xD0\x60\x07\xA0\x58\x13\x09\xA9\x27\x5C\x90\x3C\xA4\x56\x54\x21\x41\x50\x08\x0E\xA2\x04\x7F\x41\xA4\x94\x88\x8B\x53\x1B\x0D\x5F\x50\xB1\x15\xA1\xA0\x29\x13\x94\x08\x73\x9D\x00\x05\x0A\x8B\x9E\xFE\x85\xA7\x49\x83\xA6\x95\x90\x2B\x98\xA3\xB5\x8A\xA1\x24\xA2\xAE\xA0\x88\xA2\x02\xA2\x20\x14\xA2\x08\x16\xA8\xA2\x8D\xA0\xA2\x44\x88\x9F\xA0\x47\x8D\xAF\x9F\x17\x3B\xA3\x8F\x78\x8A\xA4\x4B\x90\x5A\x98\x8B\xB1\xA3\x9A\xF3\x9B\x94\x25\xAE\x50\x59\x58\x79\x30\x8C\x04\x20\x8C\x16\x64\xA0\x56\x61\x6E\x0D\x9E\xA4\x18\x21\x5C\xFA\x9C\xAD\x60\x72\x51\xA7\x3C\x1F\x07\x55\xC7\x95\xA1\x8B\x88\xA1\xA8\x78\x8B\xA0\xA0\x54\xA2\x05\x1F\x16\xA3\x9A\x75\xA6\xAE\x1B\x35\xAA\x89\xC4\xAE\xA8\xAF\x7A\xA2\xA0\x56\xC8\x97\x94\x20\x00\xAB\xA8\x42\xB5\x98\x61\x86\xB1\xA0\xC4\xBF\x55\xAD\xB2\x4D\x9D\x36\xF3\x91\x9F\x79\xAE\x04\x06\xF9\x88\x21\x6A\xB7\xAC\x9E\xDD\x38\xAB\xAF\x04\xA7\x97\x65\xD5\x99\xB2\x2C\x84\xAF\xA1\x11\xB6\xA2\x52\xA1\x76\xA0\x84\x8E\xAC\xA3\x51\xBB\xA1\x48\x84\xB6\xA4\xC9\x87\x9A\xAB\x8E\x5C\xAB\x4B\xA0\x0F\xAB\x47\xB4\xA6\xA6\xFB\x80\x54\x1D\x2F\xB6\xB9\xD8\xBE\xA3\xB6\xB6\xB5\xB4\x43\xA3\xA8\xB7\xA3\xBA\xB3\xB9\x96\xBE\xB6\x70\xD0\xAE\xA3\xF1\xB7\xB5\xA4\x56\xB5\xB9\x56\x8C\x59\xB8\x97\x8B\xA8\xA6\x32\xB3\x9E\x68\xD1\xB9\x4F\x3D\x54\x96\xB4\x33\x06\x10\x46\x7A\xBA\x9E\x9C\xB8\x8A\xA7\xEA\xB4\xB3\x75\xFF\xA8\xB3\xC0\x83\xAC\xAA\x46\xA8\xAB\x6E\x81\xAD\xA8\xF3\x81\xBF\xA9\xE7\xA5\xB8\x4A\xEB\xBB\xA5\xF6\xA7\x97\xBD\xCC\xB1\xBD\x6B\xF4\x00\x08\xB1\xB8\x96\xB1\xB2\x48\xAF\x40\x6A\xA0\xC5\xDC\x3E\x91\x0A\x18\x28\xC4\x5D\x9F\xB6\xAF\xDC\x10\xB0\xB6\x3D\xAC\x90\x76\xB9\x8A\xBB\xC1\x9C\xBD\xB0\x87\xAF\x91\x89\xEE\x0C\x9C\x51\x74\xBE\x4B\xA5\xBB\xC2\x0B\x36\x0C\xBE\x84\x05\xCC\xB5\xD2\xB4\xBB\x84\x82\xC2\xC6\x02\xF4\xB6\xC0\x9A\xBC\xB9\x82\xDF\xB8\xC3\x06\xD0\xC7\xC1\x53\xB7\xC6\x49\xC7\x8B\xC8\xE4\xAD\xA7\xC2\x5E\xBA\xC2\x74\xC0\x48\x0A\x14\x7D\x30\x4C\x65\xC9\x3B\x1B\xD8\x08\x22\x36\xFA\x9E\xCC\xD3\xA5\x9B\x64\xCE\x5E\x4B\xA4\xB3\xA3\x6D\x6D\x69\xA5\x93\x75\xC4\xA2\x56\x86\x92\xCF\x57\x54\x0E\x9D\xF9\x75\xCC\x40\xCF\x5A\xA6\x70\xC0\x0B\xDC\x08\x2B\xD0\x2C\x07\x4B\x3D\x61\x13\xBF\xA3\xEC\x3F\x8D\x11\x18\x26\xD2\xFA\x93\xD1\x18\x7E\x90\x7C\x2A\x01\x0E\xD0\x75\xD3\x9A\xA6\xBD\xCD\x2E\x47\xEF\x0C\x3E\xF0\x96\xBC\x2E\xF3\x30\x41\x37\xA9\x00\x23\xAF\xD9\xD3\xA9\x80\x4C\xD2\xD9\x67\x60\xD4\xBA\x32\xA4\xAB\xDE\x44\xD4\xC6\x2E\x9B\xC3\x41\xD2\xBB\x1B\xC5\xC4\x21\x23\xFF\xC6\xB5\xFF\xA0\xA0\x97\xBC\xAC\xC8\xBF\x89\xA0\xCA\xB6\xA8\xC1\x6E\x93\xAB\xB8\x2B\xC0\xBD\xBC\x10\xC4\xB9\x7A\xDD\xCC\xBD\x2F\xFE\xA0\xC3\xCD\xB3\xA7\x86\xF3\xB3\x9E\x2A\x83\x26\x8A\xA6\xA1\x9E\x9C\x70\x21\x7A\xE8\x43\x20\x9D\x38\xAB\x9F\x7C\xBF\xB1\xA5\x78\xB4\xDA\x44\x6F\x95\x04\x46\x7A\xDA\x9F\x7B\xE5\x0E\x9F\x21\x09\xCD\x6F\x76\xC1\xE0\x4D\xC4\xE6\xD4\xA8\xC2\xD0\x45\x81\xE3\x9E\x20\x0F\x79\x3B\x94\x8A\x4D\x97\x3A\x3F\x71\x36\x58\x0A\xE2\xAD\xD1\x04\x18\x18\x2B\xE2\x7D\x98\xE5\x9F\x78\x98\xA3\x8E\x88\x92\x4C\x32\x4F\x94\xA2\x08\xE0\x40\xC9\xE3\x42\x23\x32",
|
|
"\x5C\xBF\xD8\x82\xD8\x8C\x9C\x72\x4B\xC2\x99\x9F\xE2\x37\x1D\xD7\x93\x87\xAC\xCA\xB0\x1A\x84\x26\x86\x3B\xDB\x85\x0F\xEB\xD4\x0C\xBD\x44\x22\x6F\xE8\x9B\xC6\x3A\x8E\xED\x45\x6C\xB7\xE4\x0E\x15\xF1\xE0\x97\x2D\xD2\x07\x8E\xC8\x26\xEA\x4A\x8F\xEA\x3F\xE1\xBB\xAC\x9E\xEE\xAB\xE5\x26\xF6\xCD\xCA\xF5\xC8\x8F\x92\xED\xE4\xAA\x30\xE8\x93\xCC\xF3\x96\xE7\xA9\xDE\x4C\xDC\xC0\xCA\xD7\x68\xC2\xC7\x06\x62\xC3\x26\xD8\xFE\xBF\x9C\x8C\xCD\xD3\xC6\x40\x75\xC1\x57\x52\xD3\xDA\x9D\xD5\xC2\xBD\x2B\xD8\xD9\xCB\x24\xB2\xC0\xB3\xDE\xCC\xAA\x40\xA1\xC8\xAC\x1B\xC4\xCC\x9C\xED\xD2\x21\xAC\x42\xE4\x9E\xEA\xC3\x9C\x19\x58\x98\x9C\x38\xCB\xEB\xD1\x04\x2D\xD2\xA6\xA2\xC2\x20\xB5\x9A\xD2\xE8\xE2\x90\x2D\xD4\x82\x28\x9C\x4D\xCB\xEA\xD2\xB3\xDE\x4A\xB9\x82\x26\x8B\x5D\xFA\x30\xF5\x44\xF4\xF0\x00\x59\x6D\xF5\xD8\xEE\xB2\xDE\x3E\xDE\xDF\xEC\x80\x06\x8A\x7F\xF8\xF2\xF3\xBA\xFC\xF6\x12\xFE\xDB\xE9\x87\xC0\x01\x47\x17\xEE\xEE\x6E\x46\xE3\x20\xBD\x51\xFB\x4D\x5E\x47\xF8\x5C\x24\xF0\x21\x77\xD9\xEA\xFA\xD3\xAB\x9E\x87\xD9\x9B\xC6\xEE\xE4\xC6\xEB\xB2\x4F\x8E\x8A\x88\x2B\xFD\xC6\xA8\xFE\xC5\xC9\xDA\xAF\xB2\x93\xB9\x98\x67\xC0\xB5\x91\x07\xD7\xC4\x67\xB2\xAB\xC6\xC9\xC9\x3D\x9C\x04\x15\x4E\x97\x78\x7B\x5B\x41\x44\xD8\x47\x44\x9D\x79\x1C\x65\x3B\x41\xB8\x40\x67\xAB\x79\x4D\x70\x6A\x45\x40\x44\x07\xCE\x79\x23\x62\x47\x79\x3E\x00\x7A\x03\x12\x7A\x48\x21\x06\xC3\x75\x7B\x1D\x84\x80\x13\x8F\x80\x08\x8A\x44\xAE\x7A\x81\x02\x1C\x81\x90\x63\x7E\x8E\x61\x82\x05\x84\x07\x07\x80\x02\x26\x8D\x81\x3E\x00\x7B\x09\x7E\x4D\x08\x18\x83\x63\x77\x7B\xEA\x6F\x82\xC9\x73\x10\x25\x8B\x83\xD3\x56\x83\x00\x26\x7E\x94\x46\x7B\xF4\x4F\x82\xE3\x77\x81\x48\x85\x83\x3E\x63\x4F\x38\x84\x10\x3A\x89\x6E\x43\x7E\x83\x18\x19\x35\x41\x88\x53\x70\x72\x5D\x46\x8F\x6B\xC2\x6A\x84\x3A\x71\x46\x32\x80\x73\x4E\x85\x6A\xFE\x61\x85\x03\x1A\x83\xC6\x7D\x83\x13\x8F\x83\x46\x48\x44\xCB\x76\x5E\x65\x8E\x6B\xD9\x4E\x6F\x5D\x85\x87\xE6\x52\x81\x5C\x4B\x84\x63\x8C\x7C\x2C\x8B\x63\x16\x08\x11\x81\x8B\x73\xAF\x2D\x62\x6F\x5C\x86\x5C\x44\x7D\x02\x1A\x37\x41\x8A\x74\x7F\x8F\x7E\x6E\x08\x86\x02\x1A\x83\x41\x7F\x82\x1F\x80\x84\x63\x8A\x74\x15\x82\x75\xD8\x7A\x1B\x9B\x38\x10\x9F\x87\x7D\x13\x78\x79\x55\x83\x81\x77\x81\x84\x5A\x7B\x89\xB8\x4F\x74\x00\x83\x10\x02\x8F\x74\x7A\x81\x44\x6E\x82\x86\xDF\x7D\x89\xD3\x51\x4F\xB5\x4C\x82\xBD\x44\x03\xC0\x43\x10\xC2\x45\x4B\xFE\x4B\x64\xF5\x7B\x4C\x7E\x6E\x4A\xC7\x41\x4D\x32\x55\x4B\x40\x0E\x7F\x67\x63\x29\x03\x82\x03\x6E\x68\x10\xD1\x8A\x44\x9E\x72\x67\xC7\x5B\x67\xB9\x64\x51\x45\x08\x67\x4C\x08\x6B\x0A\x7C\x4C\x85\x46\x8C\xDE\x83\x68\xFA\x33\x8E\xD3\x49\x68\x28\x80\x00\x2A\x8C\x1E\x92\x61\x82\x32\x08\x69\x08\x10\x8F\x33\x80\x69\x9C\x65\x3D\x9E\x66\x8E\x8F\x43\x6A\x44\x80\x64\x72\x72\x84\xF5\x41\x6B\x08\x10\x90\x26\x8E\x7B\x71\x60\x02\x43\x06\x6B\x4C\x38\x8F\x06\x94\x90\xBD\x65\x1A\x5E\x85\x5F\x2C\x47\x5F\x42\x65\x03\x76\x72\x10\x78\x7B\x61\x4A\x6C\x6C\xF5\x7D\x77\x31\x2F\x77\xBB\x12\x6D\xDE\x54\x6D\x84\x79\x51\x0E\x67\x78\xC3\x5A\x65\xDB\x6B\x78\xDD\x6A\x5C\xE0\x62\x66\x00\x29\x73\x0C\x1C\x46\xE5\x78\x11\xE7\x75\x88\x8A\x57\x5A\xEB\x74\x10\xED\x7D\x75\x36\x9F\x58\xF1\x7B\x77\x1B\x9E\x64\xD9\x50\x6D\xDB\x54\x52\xFB\x7E\x59\x3D\x92\x2B\x4C\x7C\x10\xD0\x7F\x74\x0F\x82\x8A\xAD\x63\x03\x56\x74\x10\x58\x70\x95\x20\x7E\x6C\x23\x75\x76\x2C\x7F\x06\x2E\x78\x72\x48\x80\x76\x67\x7F\x72\x6C\x72\x73\x43\x7C\x76\xD3\x4F\x74\x0D\x93\x10\xB8\x83\x54\xAA\x80\x00\xB5\x44\x2E\xF5\x37\x1F\xCC\x84\x07\x40\x30\x67\xC0\x1C\x01\x24\x12\x20\xE9\x8B\x8E\x61\x06\x24\x1D\x80\x1C\x1E\x09\x97\x59\x2E\x63\x48\x80\x26\x48\x80\x1C\x20\x02\x98\xEE\x1B\x85\x53\x23\x29\xF3\x40\x1C\xB7\x31\x2E\x8B\x91\x7C\xE6\x56\x37\x21\x50\x1C\xFE\x32\x99\xE6\x1F\x88\x49\x99\x1B\x0F\x8B\x63\xC0\x16\x02\x8A\x96\x1E\x6D\x96\x95\xA1\x2D\x17\x4F\x70\x1C\x28\x03\x9A\xE5\x10\x01\x22\x49\x10\xC2\x10\x1C\x9D\x10\x97\xB4\x95\x9B\x38\x12\x1C\x8F\x3F\x36\xB6\x90\x00\x9D\x13\x9B\xF7\x36\x22\x03\x19\x4C\xC0\x1B\x96\xD5\x40\x97\xCD\x15\x10\x4F\x4F\x9A\xBB\x9B\x9C\x24\x12\x1C\x6A\x48\x2C\xB5\x9D\x9B\xB4\x90\x24\xD1\x43\x9C\xFD\x8F\x96\xB0\x9D\x9C\x0C\x8C\x9C\xBC\x9C\x9D\x10\x7C\x94\x2F\x13\x54\xD6\x91\x91\xDF\x43\x54\xFF\x0A\x9B\x05\x18\x9E",
|
|
"\x04\x22\x9B\x9D\x23\x10\xCA\x9B\x9B\x6D\x98\x9D\xE4\x95\x2B\x98\x43\x54\xE9\x8B\x9E\xB4\x94\x9C\xB6\x58\x9E\xE3\x94\x9F\x7D\x27\x60\xC0\x1C\x99\x65\x5E\x56\xE7\x98\x11\xE9\x8C\x9E\x0C\x19\x8E\xEF\x96\x9B\xF1\x92\x9E\x72\x74\x10\x67\x45\x4D\x7B\x9E\x9D\x50\x47\x9D\x43\x5C\x9F\x0F\xAA\x96\x03\x12\x58\xB9\x20\x1C\x8C\x9E\x25\x14\xA4\x2E\xC7\x9F\x0F\x04\x2E\x7C\x21\xA1\x1C\x24\x1E\x7C\xF9\x17\xA2\x23\xA9\x9B\x14\xA8\x9E\x9F\x17\xA0\xB4\x9F\xA1\xBA\x1E\x9B\x0C\x10\x34\xC2\x99\xA1\x2E\x45\x9F\xC5\x9C\x1C\xC2\x16\x36\x27\xAC\x2D\x2D\xA8\x11\x18\xA0\x97\x30\xAD\x9E\xBB\x92\xA0\xA0\x59\x1B\x36\xA0\x9C\x37\xA1\x9C\x37\x2A\xA3\x15\xA5\x9E\x3D\xAE\xA3\x24\x19\x8E\x8F\x3C\xA2\xC2\x19\x1F\xAD\x8B\x9B\x47\xA6\x34\xCB\x94\xA3\x74\x0F\x19\x25\x04\xA1\xF3\x66\x5E\x28\xA9\x14\x4F\x4A\x46\xB5\x9B\xA0\x9F\x1B\xA2\x33\xAF\x84\x91\x78\x11\x65\xAE\x9D\x67\xA0\x61\x4D\xAE\x29\x94\x20\x00\x74\x6A\x1B\x01\x3B\x9D\x97\x73\xA4\x31\x94\xA1\x6E\xA2\x2A\xCC\x92\xA6\x64\xA6\xA6\x94\x98\xA7\xB4\x9D\x2C\xD8\x84\x07\x7F\xA9\x36\x0D\x89\x22\xCE\x91\x86\xCC\x95\xA8\x60\xAB\x9B\x88\xA4\xA7\x8A\xA6\x86\xE6\x59\xA7\xAF\x3B\xA7\x7D\xA0\xA9\xDB\x92\x3D\x81\xA2\x1C\xBA\x7C\x7D\x6D\xA5\xAA\xAF\x1D\xA9\x74\x80\x73\x89\xA6\xA7\x8B\xAC\x51\xA0\xA1\x1F\x93\x23\xAA\x1E\xA4\x98\x04\x93\xA2\xDC\x7A\x7B\xAB\xA2\xA9\x74\x87\xA8\x72\xA3\x66\x9C\xA2\xAB\x9E\xAC\xA8\x70\x9E\xA8\x81\x60\x1C\x13\xAB\x6A\x1D\x83\xA2\x5D\xAB\x46\x84\xAC\xAA\x02\x10\xA7\x70\x9B\xA9\x0C\x15\xA7\xDC\x97\xA7\xB4\xAD\xA8\xB7\xAF\xA8\x91\xA3\x3D\x93\xAD\x1B\x69\xA7\x9B\xD5\x24\xA1\xB5\xA7\x2D\x77\x2B\x61\xB9\xA5\x6A\xF3\x4F\x0F\x0B\xA5\xA0\x0C\x12\x89\xD7\x2D\x19\x00\x94\x10\x0B\xA5\x9B\xEB\xA2\x5D\xED\xAF\xAA\xF3\x49\x8E\xF7\xA1\xA6\xC3\xA0\x20\xE9\xAF\x80\x6B\x7C\xAE\x4D\x74\x10\x4D\x90\x7E\xF2\xAB\x37\xB4\x9D\x19\xDA\xA8\xAF\x14\xAB\xAF\x00\x2D\xAF\x0E\x93\x77\xD2\x59\x8E\x11\xB2\xB0\xEE\xAB\x61\xF9\xAE\xAA\x17\xB4\x92\x10\x6D\xB0\x52\x8F\xB0\x32\x33\x42\x13\xBE\x98\x08\xB9\xA9\x90\x3F\x90\x5E\x29\x8E\x3E\x7C\xB1\xFE\xAB\x61\x05\xBE\x20\x03\x17\xB0\xFC\xA9\xB0\x03\x1B\xB0\xB6\x86\x9C\xC2\x1D\x19\x9F\x8C\x9C\xE9\xA0\x1C\x9F\x90\x89\x01\xA1\x86\x3C\x93\xA0\xB2\x24\xB2\x09\x18\x9E\x31\xB8\x2D\xF6\xA8\x11\x1F\xB0\x97\x45\xBD\x99\x6E\x07\xB4\x83\xA4\x88\x4A\xB9\x1B\x00\xB4\xA1\x4A\xA6\x88\x45\xAB\xA7\x7A\xA6\x76\x5C\x93\x07\x38\x2D\x74\xA6\x91\x20\x4E\xB6\xB2\x33\x32\xB5\x14\xA5\xB5\x5B\xB7\xB5\x96\xA3\x10\x32\x90\x89\x30\xBE\xB5\x48\xBB\x63\x61\xBA\xA7\x63\xBB\x95\x65\x27\xB6\xE0\x9B\x8A\xE0\x71\xA2\x82\xA8\x10\x15\x08\xAE\x18\x15\xB3\x0C\x1A\x28\x2B\x92\x16\x16\xBD\xAA\x2E\xBE\xA7\x84\x1F\xB3\x82\x88\xB8\xDE\x95\x97\xC9\x11\xAE\xA6\xA0\x67\x23\xA8\x9E\x8A\x85\xAF\xC5\xA8\xB2\x97\xBF\x9B\x76\x94\xAD\xA0\x14\x49\x70\x6A\xB1\x14\xA3\x97\x53\xBB\xAD\xB3\xA7\x99\x22\xA4\xB9\x0C\x17\x01\x96\xBC\x9D\x7E\x90\x69\xCC\xA6\xA0\x47\x8F\xAC\xC2\x1E\xB9\x6C\xB8\x10\x1B\xB2\x10\xAD\xB0\x2E\xB7\xBC\x1E\xB9\xB9\xA0\xBB\xB0\x69\xAA\xBE\x9D\xCD\xA9\x4D\x9A\x63\xBC\x32\xB1\xB2\xFE\x6E\xB3\xDA\x9C\x10\x18\x05\xBB\xCC\x96\x98\x04\x9F\xB8\xD5\xA7\x84\xBB\xA1\xAF\x6B\xB0\x97\x51\xBC\x10\xD0\xB8\x2D\xDA\xB9\x70\xDC\xBD\xB2\xCE\xB4\x90\x5D\xB6\xAC\xAF\xA8\x84\x7B\xB1\xAA\x7D\xB6\x72\x80\xBA\x23\x9C\x83\x8A\x4C\xBB\x88\xBF\xB4\x10\xC1\xB0\x00\xE5\xBA\xAE\x93\x27\x98\x86\xA0\xB9\xEB\xB9\x70\xCB\xBE\xBA\xA5\x68\x84\xFF\xB5\x9B\xDC\xA1\x52\xF9\xB0\x00\x4F\xB0\xBA\x6D\xB4\xBE\x29\xB0\x3B\x28\x1B\xBD\x03\xCD\xBD\xAB\x6C\xBE\x27\xB2\xAC\x09\xC4\x90\xF1\xB6\xAB\x16\xC4\xB6\x7F\xBA\xB3\xDF\x9E\x74\x83\xB4\xA1\x85\xB1\x7A\xD8\xB3\x10\xE9\xA8\xA3\x51\xAC\xB2\x8B\x10\x73\xDC\x93\xA2\x9D\x19\x01\x41\xA6\xAE\x49\x18\x9E\xD6\xA8\x10\xAD\x14\xA4\xBA\xBC\xB2\x0C\xCF\xBA\x22\x21\xC2\xEA\xB7\xB1\x52\x53\x5C\xE9\xB3\xC3\x8F\x91\xBB\xD5\xB8\x10\x1A\x0D\xC2\x9A\xA2\x2A\xA9\x96\xC2\xCF\x77\xBF\x15\xB9\xC3\x49\x12\x1C\xC8\x2B\x01\x52\xC7\xBA\x13\xCC\x9D\xA5\x95\xC5\xE5\xA4\x18\x5C\xAF\xC5\x9F\x11\xC1\xB5\x93\xC6\x29\xC3\x19\xA8\xA4\x93\x2F\xA6\xBA\x6A\xC4\x9B\x6C\xC6\x8B\xE9\xAA\xAC\xCF\x2B\xC4\xDE\xB8\xBE\xD8\x23\xA2\x6D\x9A\xC5\x80\xC1\xC8\x82\xCF\xC4\x84\x1F\x38\xF8\x92\xBE\x89\xB4\x9B\x30\xC1\x12\x58\xB5\x1C\x63\x56\xB4\xD9\x99\x14\xC0\x1D\x01\x83",
|
|
"\xC4\xB8\xC2\x1B\xA6\x5F\xC7\xC7\xDF\xAB\xAC\xA6\xB7\x12\xA7\xA4\x12\x8F\x3C\xA6\xFB\xBE\xC2\xDE\xA6\xC1\xB8\xAD\xC9\xA8\xB4\xA9\xB4\x13\xB7\xBB\x92\x9D\xC9\xAB\xC9\x79\xC8\xCA\xE3\xA4\xAA\xD0\xAC\xCA\xB6\x9E\xCA\xE4\x28\xC7\x20\xA2\xCB\x10\x8A\xCA\x92\xC8\x11\x1F\x05\xC9\x39\xCC\xAB\x57\x89\xC9\xA5\xC2\xAA\xE0\xA1\xC4\x8C\x69\xBC\xC6\xB3\xA2\xC0\x11\x02\xC2\xCA\xA5\x24\x19\xAA\xC6\xCF\xCA\xA6\xC9\xCC\x32\xCB\xC7\x59\xCE\xCC\x97\x61\xCD\xCB\x93\xA2\x67\xCE\xCD\x65\xC9\x10\xC0\x1D\xBF\xE2\xCD\xC7\x5B\xA4\x44\x68\xC1\xBA\x1E\xCF\xAA\xD3\xB3\xA2\x98\xCE\x9D\x5F\xA0\xBC\x20\xB4\xC0\x22\xBD\xAD\xD6\xC8\xCC\x9C\xC0\xAC\x9B\xBE\xCB\x38\x11\xCA\x71\xCC\xCF\x03\x16\xCE\x71\xA7\xAC\xF8\xC9\xCB\xB0\xCB\xCB\x02\xD8\x17\xB3\xC3\xA2\xE3\x7C\x9C\xF3\xCC\xBF\xF5\xCA\xC1\x78\x88\xAC\x08\xD7\xCD\xFB\xC2\xAE\x1A\xDF\xC9\x49\x14\xCD\xF2\xC6\xBA\x04\xD7\xAD\x44\xC5\x06\x9A\xC8\xD1\xB1\xC9\xCD\x1B\xC9\x70\xC4\xC8\x35\x01\xDA\xD1\x12\xDE\xBE\xD2\xBF\xA9\xC7\xCA\xA7\xA7\xC8\xBC\x36\xDE\xBC\xBC\xB4\x12\xD1\xA2\xCA\x46\xA0\xD2\x13\xDA\xBE\xF7\xC1\x52\x25\xDA\xCF\x27\xDE\xD2\x95\x1D\xD0\xB1\x98\x11\x27\x07\xCE\xE0\x23\xA2\x5D\xCC\xD4\x91\xC8\x13\xC0\x11\xB0\x50\xDA\xC3\x38\x1F\xD4\xDE\x9A\x41\x0C\x14\xD5\x0C\xA8\xB6\x64\xC0\xCE\xEA\xC9\xD5\xA6\xBC\xD5\x6B\xCE\xD5\x6D\xC3\xCE\x93\x1E\xD1\xDC\x91\xD1\x03\x14\xD6\x74\xC6\xD6\x76\xC3\xD3\xA1\xA5\xD3\xC1\xA6\xCF\x02\xC5\xD5\x78\xD0\xC8",
|
|
};
|
|
|
|
void XmlGetParserBuffer(vl::stream::MemoryStream& stream)
|
|
{
|
|
vl::stream::MemoryStream compressedStream;
|
|
for (vint i = 0; i < parserBufferRows; i++)
|
|
{
|
|
vint size = i == parserBufferRows - 1 ? parserBufferRemain : parserBufferBlock;
|
|
compressedStream.Write((void*)parserBuffer[i], size);
|
|
}
|
|
compressedStream.SeekFromBegin(0);
|
|
vl::stream::LzwDecoder decoder;
|
|
vl::stream::DecoderStream decoderStream(compressedStream, decoder);
|
|
vl::collections::Array<vl::vuint8_t> buffer(65536);
|
|
while (true)
|
|
{
|
|
vl::vint size = decoderStream.Read(&buffer[0], 65536);
|
|
if (size == 0) break;
|
|
stream.Write(&buffer[0], size);
|
|
}
|
|
stream.SeekFromBegin(0);
|
|
}
|
|
/***********************************************************************
|
|
Unescaping Function Foward Declarations
|
|
***********************************************************************/
|
|
|
|
extern void XmlMergeTextFragment(vl::collections::List<vl::Ptr<XmlNode>>& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
extern void XmlUnescapeAttributeValue(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
extern void XmlUnescapeCData(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
extern void XmlUnescapeComment(vl::parsing::ParsingToken& value, const vl::collections::List<vl::regex::RegexToken>& tokens);
|
|
|
|
/***********************************************************************
|
|
Parsing Tree Conversion Driver Implementation
|
|
***********************************************************************/
|
|
|
|
class XmlTreeConverter : public vl::parsing::ParsingTreeConverter
|
|
{
|
|
public:
|
|
using vl::parsing::ParsingTreeConverter::SetMember;
|
|
|
|
void Fill(vl::Ptr<XmlNode> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
}
|
|
|
|
void Fill(vl::Ptr<XmlText> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->content, obj->GetMember(L"content"), tokens);
|
|
}
|
|
|
|
void Fill(vl::Ptr<XmlCData> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
if(SetMember(tree->content, obj->GetMember(L"content"), tokens))
|
|
{
|
|
XmlUnescapeCData(tree->content, tokens);
|
|
}
|
|
}
|
|
|
|
void Fill(vl::Ptr<XmlAttribute> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->name, obj->GetMember(L"name"), tokens);
|
|
if(SetMember(tree->value, obj->GetMember(L"value"), tokens))
|
|
{
|
|
XmlUnescapeAttributeValue(tree->value, tokens);
|
|
}
|
|
}
|
|
|
|
void Fill(vl::Ptr<XmlComment> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
if(SetMember(tree->content, obj->GetMember(L"content"), tokens))
|
|
{
|
|
XmlUnescapeComment(tree->content, tokens);
|
|
}
|
|
}
|
|
|
|
void Fill(vl::Ptr<XmlElement> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->name, obj->GetMember(L"name"), tokens);
|
|
SetMember(tree->closingName, obj->GetMember(L"closingName"), tokens);
|
|
SetMember(tree->attributes, obj->GetMember(L"attributes"), tokens);
|
|
if(SetMember(tree->subNodes, obj->GetMember(L"subNodes"), tokens))
|
|
{
|
|
XmlMergeTextFragment(tree->subNodes, tokens);
|
|
}
|
|
}
|
|
|
|
void Fill(vl::Ptr<XmlInstruction> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->name, obj->GetMember(L"name"), tokens);
|
|
SetMember(tree->attributes, obj->GetMember(L"attributes"), tokens);
|
|
}
|
|
|
|
void Fill(vl::Ptr<XmlDocument> tree, vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)
|
|
{
|
|
SetMember(tree->prologs, obj->GetMember(L"prologs"), tokens);
|
|
SetMember(tree->rootElement, obj->GetMember(L"rootElement"), tokens);
|
|
}
|
|
|
|
vl::Ptr<vl::parsing::ParsingTreeCustomBase> ConvertClass(vl::Ptr<vl::parsing::ParsingTreeObject> obj, const TokenList& tokens)override
|
|
{
|
|
if(obj->GetType()==L"Text")
|
|
{
|
|
vl::Ptr<XmlText> tree = new XmlText;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<XmlNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"CData")
|
|
{
|
|
vl::Ptr<XmlCData> tree = new XmlCData;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<XmlNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Attribute")
|
|
{
|
|
vl::Ptr<XmlAttribute> tree = new XmlAttribute;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<XmlNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Comment")
|
|
{
|
|
vl::Ptr<XmlComment> tree = new XmlComment;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<XmlNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Element")
|
|
{
|
|
vl::Ptr<XmlElement> tree = new XmlElement;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<XmlNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Instruction")
|
|
{
|
|
vl::Ptr<XmlInstruction> tree = new XmlInstruction;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<XmlNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else if(obj->GetType()==L"Document")
|
|
{
|
|
vl::Ptr<XmlDocument> tree = new XmlDocument;
|
|
vl::collections::CopyFrom(tree->creatorRules, obj->GetCreatorRules());
|
|
Fill(tree, obj, tokens);
|
|
Fill(tree.Cast<XmlNode>(), obj, tokens);
|
|
return tree;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
vl::Ptr<vl::parsing::ParsingTreeCustomBase> XmlConvertParsingTreeNode(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
XmlTreeConverter converter;
|
|
vl::Ptr<vl::parsing::ParsingTreeCustomBase> tree;
|
|
converter.SetMember(tree, node, tokens);
|
|
return tree;
|
|
}
|
|
|
|
/***********************************************************************
|
|
Parsing Tree Conversion Implementation
|
|
***********************************************************************/
|
|
|
|
vl::Ptr<XmlText> XmlText::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlText>();
|
|
}
|
|
|
|
vl::Ptr<XmlCData> XmlCData::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlCData>();
|
|
}
|
|
|
|
vl::Ptr<XmlAttribute> XmlAttribute::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlAttribute>();
|
|
}
|
|
|
|
vl::Ptr<XmlComment> XmlComment::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlComment>();
|
|
}
|
|
|
|
vl::Ptr<XmlElement> XmlElement::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlElement>();
|
|
}
|
|
|
|
vl::Ptr<XmlInstruction> XmlInstruction::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlInstruction>();
|
|
}
|
|
|
|
vl::Ptr<XmlDocument> XmlDocument::Convert(vl::Ptr<vl::parsing::ParsingTreeNode> node, const vl::collections::List<vl::regex::RegexToken>& tokens)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, tokens).Cast<XmlDocument>();
|
|
}
|
|
|
|
/***********************************************************************
|
|
Parser Function
|
|
***********************************************************************/
|
|
|
|
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)
|
|
{
|
|
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
|
|
state.Reset(L"XDocument");
|
|
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
|
|
return node;
|
|
}
|
|
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseDocumentAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
|
|
{
|
|
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
|
|
return XmlParseDocumentAsParsingTreeNode(input, table, errors, codeIndex);
|
|
}
|
|
|
|
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)
|
|
{
|
|
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
|
|
state.Reset(L"XDocument");
|
|
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
|
|
if(node && errors.Count()==0)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, state.GetTokens()).Cast<XmlDocument>();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
vl::Ptr<XmlDocument> XmlParseDocument(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
|
|
{
|
|
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
|
|
return XmlParseDocument(input, table, errors, codeIndex);
|
|
}
|
|
|
|
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)
|
|
{
|
|
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
|
|
state.Reset(L"XElement");
|
|
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
|
|
return node;
|
|
}
|
|
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> XmlParseElementAsParsingTreeNode(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
|
|
{
|
|
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
|
|
return XmlParseElementAsParsingTreeNode(input, table, errors, codeIndex);
|
|
}
|
|
|
|
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)
|
|
{
|
|
vl::parsing::tabling::ParsingState state(input, table, codeIndex);
|
|
state.Reset(L"XElement");
|
|
vl::Ptr<vl::parsing::tabling::ParsingGeneralParser> parser=vl::parsing::tabling::CreateStrictParser(table);
|
|
vl::Ptr<vl::parsing::ParsingTreeNode> node=parser->Parse(state, errors);
|
|
if(node && errors.Count()==0)
|
|
{
|
|
return XmlConvertParsingTreeNode(node, state.GetTokens()).Cast<XmlElement>();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
vl::Ptr<XmlElement> XmlParseElement(const vl::WString& input, vl::Ptr<vl::parsing::tabling::ParsingTable> table, vl::vint codeIndex)
|
|
{
|
|
vl::collections::List<vl::Ptr<vl::parsing::ParsingError>> errors;
|
|
return XmlParseElement(input, table, errors, codeIndex);
|
|
}
|
|
|
|
/***********************************************************************
|
|
Table Generation
|
|
***********************************************************************/
|
|
|
|
vl::Ptr<vl::parsing::tabling::ParsingTable> XmlLoadTable()
|
|
{
|
|
vl::stream::MemoryStream stream;
|
|
XmlGetParserBuffer(stream);
|
|
vl::Ptr<vl::parsing::tabling::ParsingTable> table=new vl::parsing::tabling::ParsingTable(stream);
|
|
table->Initialize();
|
|
return table;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|