You've already forked mariadb-columnstore-engine
							
							
				mirror of
				https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
				synced 2025-11-03 17:13:17 +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
 |