Ответ 1
Я спросил мистера Суини по электронной почте и получил этот ответ:
Код С++ использует классы шаблонов, которые я написал, которые реализуют комбинаторы парсеров. Идея состоит в том, чтобы начать с некоторых основных синтаксических анализаторов, таких как литералы, где PLit < 'A' > анализирует литеральный символ "A", PAny < > анализирует любой символ, но терпит неудачу, если в конце сбоя PEof завершается с ошибкой, если мы не в конце файла и т.д. И затем мы объединяем их в произвольные деревья с помощью комбинаторов, таких как PAnd, которые анализируют a тогда b, и преуспевают только в том случае, если оба успешно - иначе он терпит неудачу с точкой разбора без движения. И если это удастся, результатом будет структура, содержащая два поля: одна для результата a и одна для результата b. И так далее.
Реализация путаница в С++ по ряду причин, в том числе, что шаблоны не поддерживают произвольные переменные параметры, и без первоклассных lambdas мы не можем легко обрабатывать результаты inline с помощью синтаксического анализатора.
Вот некоторые фрагменты кода шаблона, из которых вы, вероятно, можете выяснить детали фреймворка.
// Parses a literal item.
UBOOL LiteralEvaluate (UClass* C,class FParseInBase& In,class FParseOutBase& Out)
{
FParseInMark M(In);
NNode* e = In.GetNextSource();
if (e && e->IsA(C))
{
Out.Callback(e);
return 1;
}
M.Restore(In);
return 0;
}
// Optional item of the specified type.
template <class U> struct Optional
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
U::Evaluate(In,Out);
return 1;
}
};
// Ignore items by absorbing them; retains boolean logic but not callback.
template <class T> struct Ignore
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
return T::Evaluate(In,GIgnore);
}
};
// Zero or more items of the specified type.
template <class T> struct ZeroOrMore
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
while (T::Evaluate(In,Out));
return 1;
}
};
// One or more items of the specified type.
template <class T> struct OneOrMore
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
for( INT i=0; T::Evaluate(In,Out); i++ );
return i>0;
}
};
// Always fails.
struct RFalse
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
return 0;
}
};
// Always succeeds.
struct RTrue
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
return 1;
}
};
// Parses the first matching items of the specified subtypes of T.
template <class A,class B=RFalse,class C=RFalse,class D=RFalse > struct Or
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
return A::Evaluate(In,Out) || B::Evaluate(In,Out) || C::Evaluate(In,Out) || D::Evaluate(In,Out);
}
};
// Parses all the specified items.
template <class A,class B=RTrue,class C=RTrue,class D=RTrue> struct And
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
FParseInMark Mark(In);
Conjunction<NNode> Q;
if( A::Evaluate(In,Q) && B::Evaluate(In,Q) && C::Evaluate(In,Q) && D::Evaluate(In,Q) )
{
Q.Forward(Out);
return 1;
}
Mark.Restore(In);
return 0;
}
};
// A separated list.
template <class A,class B> class SeparatedList : public Or<And<A,B,SeparatedList>,A> {};
// Integer comparison.
template <INT A,INT B> struct IsAtLeast
{
static UBOOL Evaluate (class FParseInBase& In,FParseOutBase& Out)
{
return A>=B;
}
};
Этот Test.ae был экспериментальным языком сценариев, который я применял в 1999-2001 годах, - тогда эта цветовая схема была модной, клянусь.: -)
Показанный код определяет метаданные для языковых конструкций. Язык прошел долгий путь вниз по пути Smalltalk "все является объектом", касаясь первоклассных метаклассов и связанных с ними проблем, но я в конечном итоге отказался от него, когда я познакомился с работами расширенного типа в Haskell, Cayenne, Coq и других языки.
В настоящее время -
Я не являюсь поклонником реализации парсеров или компиляторов на С++, поскольку код, как правило, раздувается на 70-80% по сравнению с аналогичной реализацией на современном функциональном языке, таком как Haskell. Для более подробного ознакомления с комбинаторами парсеров Haskell - получившаяся в результате простота и прямота является образцовой, и это делается строго и безопасно.