mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-23 07:05:36 +03:00
299 lines
6.9 KiB
C++
299 lines
6.9 KiB
C++
/* Copyright (C) 2021 MariaDB Corporation.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License
|
|
as published by the Free Software Foundation; version 2 of
|
|
the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#pragma once
|
|
|
|
#include "conststring.h"
|
|
|
|
namespace genericparser
|
|
{
|
|
using utils::ConstString;
|
|
|
|
class Tokenizer
|
|
{
|
|
protected:
|
|
const char* mStr;
|
|
const char* mEnd;
|
|
|
|
public:
|
|
explicit Tokenizer(const char* str, size_t length) : mStr(str), mEnd(str + length)
|
|
{
|
|
}
|
|
size_t length() const
|
|
{
|
|
return mEnd - mStr;
|
|
}
|
|
const char* ptr() const
|
|
{
|
|
return mStr;
|
|
}
|
|
bool isSpace() const
|
|
{
|
|
return mStr < mEnd && mStr[0] == ' ';
|
|
}
|
|
bool isDigit() const
|
|
{
|
|
return mStr < mEnd && mStr[0] >= '0' && mStr[0] <= '9';
|
|
}
|
|
bool isChar(char chr) const
|
|
{
|
|
return mStr < mEnd && mStr[0] == chr;
|
|
}
|
|
bool isAnyCharOf(char chr0, char chr1)
|
|
{
|
|
return mStr < mEnd && (mStr[0] == chr0 || mStr[0] == chr1);
|
|
}
|
|
|
|
ConstString tokenSpaces()
|
|
{
|
|
if (!isSpace())
|
|
return ConstString(nullptr, 0);
|
|
const char* start = mStr;
|
|
for (; isSpace(); mStr++)
|
|
{
|
|
}
|
|
return ConstString(start, mStr - start);
|
|
}
|
|
ConstString tokenDigits()
|
|
{
|
|
if (!isDigit())
|
|
return ConstString(nullptr, 0);
|
|
const char* start = mStr;
|
|
for (; isDigit(); mStr++)
|
|
{
|
|
}
|
|
return ConstString(start, mStr - start);
|
|
}
|
|
ConstString tokenChar(char chr)
|
|
{
|
|
if (!isChar(chr))
|
|
return ConstString(nullptr, 0);
|
|
return ConstString(mStr++, 1);
|
|
}
|
|
ConstString tokenAnyCharOf(char chr0, char chr1)
|
|
{
|
|
if (!isAnyCharOf(chr0, chr1))
|
|
return ConstString(nullptr, 0);
|
|
return ConstString(mStr++, 1);
|
|
}
|
|
};
|
|
|
|
class Parser : public Tokenizer
|
|
{
|
|
protected:
|
|
bool mSyntaxError;
|
|
|
|
public:
|
|
explicit Parser(const char* str, size_t length) : Tokenizer(str, length), mSyntaxError(false)
|
|
{
|
|
}
|
|
explicit Parser(const std::string& str) : Parser(str.data(), str.length())
|
|
{
|
|
}
|
|
Parser& skipLeadingSpaces()
|
|
{
|
|
tokenSpaces();
|
|
return *this;
|
|
}
|
|
bool syntaxError() const
|
|
{
|
|
return mSyntaxError;
|
|
}
|
|
bool setSyntaxError()
|
|
{
|
|
mSyntaxError = true;
|
|
return false;
|
|
}
|
|
const char* tokStart() const
|
|
{
|
|
return mStr;
|
|
}
|
|
const ConstString tokStartConstString() const
|
|
{
|
|
return ConstString(mStr, 0);
|
|
}
|
|
|
|
// A helper class template to set the parser syntax error
|
|
// if A returned isNull() after parsing.
|
|
|
|
template <class A>
|
|
class SetSyntaxErrorOnNull : public A
|
|
{
|
|
public:
|
|
SetSyntaxErrorOnNull(Parser* p) : A(p)
|
|
{
|
|
if (A::isNull())
|
|
p->setSyntaxError();
|
|
}
|
|
};
|
|
|
|
// A helper class template for a rule in the form: <res> := [ <a> ]
|
|
|
|
template <class A>
|
|
class Opt : public A
|
|
{
|
|
public:
|
|
explicit Opt(const A& rhs) : A(rhs)
|
|
{
|
|
}
|
|
explicit Opt(Parser* p) : A(p)
|
|
{
|
|
if (A::isNull() && !p->syntaxError())
|
|
A::operator=(A::empty(p));
|
|
}
|
|
};
|
|
|
|
// Letters in the class template names below mean:
|
|
// U - unused - the result class does not have the source class inside
|
|
// D - derive - the result class derives from the source class
|
|
// M - member - the result class adds the source class as a member
|
|
|
|
// M - mandatory - this part is required during parse time
|
|
// O - optional - this part is optional during parse time
|
|
|
|
// A helper class template for a rule in the form: <res> := <a> <b>
|
|
// i.e. both parts are mandatory at parse time
|
|
// The value of <a> is not important, and is created
|
|
// only temporary on the stack.
|
|
// Only the value of <b> is important.
|
|
// Example:
|
|
// <period> <unsigned integer>
|
|
|
|
template <class A, class B>
|
|
class UD2MM : public B
|
|
{
|
|
public:
|
|
explicit UD2MM(Parser* p) : B(A(p).isNull() ? B() : SetSyntaxErrorOnNull<B>(p))
|
|
{
|
|
}
|
|
explicit UD2MM(const B& b) : B(b)
|
|
{
|
|
}
|
|
explicit UD2MM() : B()
|
|
{
|
|
}
|
|
bool isNull() const
|
|
{
|
|
return B::isNull();
|
|
}
|
|
};
|
|
|
|
// A helper class template for a rule in the form: <res> := <a> <b>
|
|
// i.e. both parts are mandatory at parse time.
|
|
template <class A, class B>
|
|
class DD2MM : public A, public B
|
|
{
|
|
public:
|
|
// Sets syntax error if <a> was not followed by <b>
|
|
explicit DD2MM(Parser* p) : A(p), B(A::isNull() ? B() : SetSyntaxErrorOnNull<B>(p))
|
|
{
|
|
}
|
|
explicit DD2MM(const A& a, const B& b) : A(b), B(b)
|
|
{
|
|
}
|
|
};
|
|
|
|
// A helper class template for a rule in the form: <res> := <a> [ <b> ]
|
|
// i.e. <a> is mandatory, <b> is optional at parse time.
|
|
template <class A, class B>
|
|
class DD2MO : public A, public B
|
|
{
|
|
public:
|
|
explicit DD2MO(Parser* p) : A(p), B(A::isNull() ? B() : B(p))
|
|
{
|
|
}
|
|
explicit DD2MO(const A& a, const B& b) : A(a), B(b)
|
|
{
|
|
}
|
|
};
|
|
|
|
// A helper class template for a rule in the form: <res> := <a> [ <b> ]
|
|
// i.e. <a> is mandatory, <b> is optional at parse time.
|
|
// The value of <a> is not important and is not included
|
|
// into the target class, e.g.
|
|
// <period> [ <unsigned integer> ]
|
|
template <class A, class B>
|
|
class UD2MO : public B
|
|
{
|
|
public:
|
|
explicit UD2MO(Parser* p) : B(A(p).isNull() ? B() : B(p))
|
|
{
|
|
}
|
|
explicit UD2MO(const B& b) : B(b)
|
|
{
|
|
}
|
|
explicit UD2MO() : B()
|
|
{
|
|
}
|
|
};
|
|
|
|
// A helper class template for a rule in the form: <res> := <a> [ <b> ]
|
|
// i.e. <a> is mandatory, <b> is optional at parse time.
|
|
// The result class derives from "A".
|
|
// The result class puts "B" as a member.
|
|
template <class A, class B>
|
|
class DM2MO : public A
|
|
{
|
|
protected:
|
|
B mB;
|
|
|
|
public:
|
|
explicit DM2MO(Parser* p) : A(p), mB(A::isNull() ? B() : B(p))
|
|
{
|
|
}
|
|
};
|
|
|
|
// A helper class template for a rule in the form: <res> := [ <a> ] <b>
|
|
// i.e. <a> is optional, <b> is mandatory at parse time.
|
|
template <class A, class B>
|
|
class DD2OM : public Opt<A>, public B
|
|
{
|
|
public:
|
|
explicit DD2OM(Parser* p) : Opt<A>(p), B(p)
|
|
{
|
|
if (B::isNull())
|
|
p->setSyntaxError();
|
|
}
|
|
explicit DD2OM() : Opt<A>(A())
|
|
{
|
|
}
|
|
explicit DD2OM(const A& a, const B& b) : Opt<A>(a), B(b)
|
|
{
|
|
}
|
|
};
|
|
|
|
// A helper class template for a rule in the form: <res> := a | b
|
|
template <class Container, class A, class B>
|
|
class Choice2 : public Container
|
|
{
|
|
public:
|
|
explicit Choice2(const A& a) : Container(a)
|
|
{
|
|
}
|
|
explicit Choice2(const B& b) : Container(b)
|
|
{
|
|
}
|
|
explicit Choice2(Parser* p) : Container(A(p))
|
|
{
|
|
if (Container::isNull() && !p->syntaxError())
|
|
*this = Choice2(B(p));
|
|
}
|
|
};
|
|
};
|
|
|
|
} // namespace genericparser
|