summaryrefslogtreecommitdiff
path: root/lib/parse_plural.h
diff options
context:
space:
mode:
Diffstat (limited to 'lib/parse_plural.h')
-rw-r--r--lib/parse_plural.h173
1 files changed, 82 insertions, 91 deletions
diff --git a/lib/parse_plural.h b/lib/parse_plural.h
index d3473821..2b78de89 100644
--- a/lib/parse_plural.h
+++ b/lib/parse_plural.h
@@ -1,7 +1,7 @@
// **************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) ZenJu (zenju AT gmx DOT de) - All Rights Reserved *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
#ifndef PARSE_PLURAL_H_INCLUDED
@@ -12,7 +12,6 @@
#include <functional>
#include <zen/string_base.h>
-
//http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html
//http://translate.sourceforge.net/wiki/l10n/pluralforms
/*
@@ -50,9 +49,9 @@ multiplicative-expression:
multiplicative-expression % pm-expression
pm-expression:
- N
- Number
- ( Expression )
+ variable-number-n-expression
+ constant-number-expression
+ ( expression )
*/
@@ -71,58 +70,55 @@ struct Expr : public Expression
template <class StlOp>
struct BinaryExp : public Expr<typename StlOp::result_type>
{
- typedef const Expr<typename StlOp::first_argument_type> SourceExp;
+ typedef const Expr<typename StlOp::first_argument_type > ExpLhs;
+ typedef const Expr<typename StlOp::second_argument_type> ExpRhs;
- BinaryExp(const SourceExp& lhs, const SourceExp& rhs, StlOp biop) : lhs_(lhs), rhs_(rhs), biop_(biop) {}
+ BinaryExp(const ExpLhs& lhs, const ExpRhs& rhs, StlOp biop) : lhs_(lhs), rhs_(rhs), biop_(biop) {}
virtual typename StlOp::result_type eval() const { return biop_(lhs_.eval(), rhs_.eval()); }
- const SourceExp& lhs_;
- const SourceExp& rhs_;
+ const ExpLhs& lhs_;
+ const ExpRhs& rhs_;
StlOp biop_;
};
-template <class StlOp>
-inline
+template <class StlOp> inline
BinaryExp<StlOp> makeBiExp(const Expression& lhs, const Expression& rhs, StlOp biop) //throw std::bad_cast
{
- return BinaryExp<StlOp>(dynamic_cast<const Expr<typename StlOp::first_argument_type >&>(lhs),
- dynamic_cast<const Expr<typename StlOp::second_argument_type>&>(rhs), biop);
+ return BinaryExp<StlOp>(dynamic_cast<const Expr<typename StlOp::first_argument_type >&>(lhs), //throw std::bad_cast
+ dynamic_cast<const Expr<typename StlOp::second_argument_type>&>(rhs), biop); //
}
-template <class Out>
-struct TernaryExp : public Out
+template <class T>
+struct TernaryExp : public Expr<T>
{
- TernaryExp(const Expr<bool>& ifExp, const Out& thenExp, const Out& elseExp) : ifExp_(ifExp), thenExp_(thenExp), elseExp_(elseExp) {}
- virtual typename Out::ValueType eval() const { return ifExp_.eval() ? thenExp_.eval() : elseExp_.eval(); }
+ TernaryExp(const Expr<bool>& ifExp, const Expr<T>& thenExp, const Expr<T>& elseExp) : ifExp_(ifExp), thenExp_(thenExp), elseExp_(elseExp) {}
+ virtual typename Expr<T>::ValueType eval() const { return ifExp_.eval() ? thenExp_.eval() : elseExp_.eval(); }
const Expr<bool>& ifExp_;
- const Out& thenExp_;
- const Out& elseExp_;
+ const Expr<T>& thenExp_;
+ const Expr<T>& elseExp_;
};
-struct LiteralNumberEx : public Expr<int>
+struct ConstNumberExp : public Expr<int>
{
- LiteralNumberEx(int n) : n_(n) {}
+ ConstNumberExp(int n) : n_(n) {}
virtual int eval() const { return n_; }
int n_;
};
-struct NumberN : public Expr<int>
+struct VariableNumberNExp : public Expr<int>
{
- NumberN(int& n) : n_(n) {}
+ VariableNumberNExp(int& n) : n_(n) {}
virtual int eval() const { return n_; }
int& n_;
};
-typedef zen::Zbase<char> Wstring;
-
-
class PluralForm
{
public:
struct ParsingError {};
//.po format,e.g.: (n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
- PluralForm(const Wstring& phrase) : n_(0)
+ PluralForm(const std::string& phrase) : n_(0)
{
Parser(phrase, //in
expr, n_, dump); //out
@@ -148,8 +144,8 @@ private:
TK_GREATER,
TK_GREATER_EQUAL,
TK_MODULUS,
- TK_N,
- TK_NUMBER,
+ TK_VARIABLE_N,
+ TK_CONST_NUMBER,
TK_BRACKET_LEFT,
TK_BRACKET_RIGHT,
TK_END
@@ -158,13 +154,13 @@ private:
Token(Type t) : type(t), number(0) {}
Type type;
- int number; //if type == TK_NUMBER
+ int number; //if type == TK_CONST_NUMBER
};
class Scanner
{
public:
- Scanner(const Wstring& phrase) : stream(phrase), pos(stream.begin())
+ Scanner(const std::string& phrase) : stream(phrase), pos(stream.begin())
{
tokens.push_back(std::make_pair("?" , Token::TK_TERNARY_QUEST));
tokens.push_back(std::make_pair(":" , Token::TK_TERNARY_COLON));
@@ -177,8 +173,8 @@ private:
tokens.push_back(std::make_pair(">=", Token::TK_GREATER_EQUAL));
tokens.push_back(std::make_pair(">" , Token::TK_GREATER ));
tokens.push_back(std::make_pair("%" , Token::TK_MODULUS ));
- tokens.push_back(std::make_pair("n" , Token::TK_N ));
- tokens.push_back(std::make_pair("N" , Token::TK_N ));
+ tokens.push_back(std::make_pair("n" , Token::TK_VARIABLE_N ));
+ tokens.push_back(std::make_pair("N" , Token::TK_VARIABLE_N ));
tokens.push_back(std::make_pair("(" , Token::TK_BRACKET_LEFT ));
tokens.push_back(std::make_pair(")" , Token::TK_BRACKET_RIGHT));
}
@@ -188,21 +184,22 @@ private:
//skip whitespace
pos = std::find_if(pos, stream.end(), [](char c) { return !zen::isWhiteSpace(c); });
- if (pos == stream.end()) return Token(Token::TK_END);
+ if (pos == stream.end())
+ return Token::TK_END;
- for (TokenList::const_iterator i = tokens.begin(); i != tokens.end(); ++i)
- if (startsWith(i->first))
+ for (auto iter = tokens.begin(); iter != tokens.end(); ++iter)
+ if (startsWith(iter->first))
{
- pos += i->first.size();
- return Token(i->second);
+ pos += iter->first.size();
+ return Token(iter->second);
}
- Wstring::const_iterator digitEnd = std::find_if(pos, stream.end(), [](char c) { return !zen::isDigit(c); });
- int digitCount = digitEnd - pos;
+ auto digitEnd = std::find_if(pos, stream.end(), [](char c) { return !zen::isDigit(c); });
+ ptrdiff_t digitCount = digitEnd - pos;
if (digitCount != 0)
{
- Token out(Token::TK_NUMBER);
- out.number = zen::stringTo<int>(Wstring(&*pos, digitCount));
+ Token out(Token::TK_CONST_NUMBER);
+ out.number = zen::stringTo<int>(std::string(&*pos, digitCount));
pos += digitCount;
return out;
}
@@ -211,25 +208,25 @@ private:
}
private:
- bool startsWith(const Wstring& prefix) const
+ bool startsWith(const std::string& prefix) const
{
if (stream.end() - pos < static_cast<ptrdiff_t>(prefix.size()))
return false;
return std::equal(prefix.begin(), prefix.end(), pos);
}
- typedef std::vector<std::pair<Wstring, Token::Type> > TokenList;
+ typedef std::vector<std::pair<std::string, Token::Type> > TokenList;
TokenList tokens;
- const Wstring stream;
- Wstring::const_iterator pos;
+ const std::string stream;
+ std::string::const_iterator pos;
};
class Parser
{
public:
- Parser(const Wstring& phrase, //in
+ Parser(const std::string& phrase, //in
const Expr<int>*& expr, int& n, PluralForm::DumpList& dump) : //out
scn(phrase),
tk(scn.nextToken()),
@@ -238,8 +235,8 @@ private:
{
try
{
- const Expression& e = parse();
- expr = &dynamic_cast<const Expr<int>&>(e);
+ const Expression& e = parse(); //throw std::bad_cast, ParsingError
+ expr = &dynamic_cast<const Expr<int>&>(e); //
}
catch (std::bad_cast&) { throw ParsingError(); }
@@ -250,14 +247,14 @@ private:
void nextToken() { tk = scn.nextToken(); }
const Token& token() const { return tk; }
- void consumeToken(Token::Type t)
+ void consumeToken(Token::Type t) //throw ParsingError
{
if (token().type != t)
throw ParsingError();
nextToken();
}
- const Expression& parse() { return parseConditional(); };
+ const Expression& parse() { return parseConditional(); }; //throw std::bad_cast, ParsingError
const Expression& parseConditional()
{
@@ -270,9 +267,9 @@ private:
consumeToken(Token::TK_TERNARY_COLON);
const Expression& elseEx = parse(); //
- return manageObj(TernaryExp<Expr<int> >(dynamic_cast<const Expr<bool>&>(e),
- dynamic_cast<const Expr<int>&>(thenEx),
- dynamic_cast<const Expr<int>&>(elseEx)));
+ return manageObj(TernaryExp<int>(dynamic_cast<const Expr<bool>&>(e), //
+ dynamic_cast<const Expr<int>&>(thenEx), //throw std::bad_cast
+ dynamic_cast<const Expr<int>&>(elseEx))); //
}
return e;
}
@@ -280,29 +277,25 @@ private:
const Expression& parseLogicalOr()
{
const Expression* e = &parseLogicalAnd();
- for (;;) //associativity: ->
- if (token().type == Token::TK_OR)
- {
- nextToken();
- const Expression& rhs = parseLogicalAnd();
- e = &manageObj(makeBiExp(*e, rhs, std::logical_or<bool>()));
- }
- else break;
+ while (token().type == Token::TK_OR) //associativity: ->
+ {
+ nextToken();
+ const Expression& rhs = parseLogicalAnd();
+ e = &manageObj(makeBiExp(*e, rhs, std::logical_or<bool>())); //throw std::bad_cast
+ }
return *e;
}
const Expression& parseLogicalAnd()
{
const Expression* e = &parseEquality();
- for (;;) //associativity: ->
- if (token().type == Token::TK_AND)
- {
- nextToken();
- const Expression& rhs = parseEquality();
+ while (token().type == Token::TK_AND) //associativity: ->
+ {
+ nextToken();
+ const Expression& rhs = parseEquality();
- e = &manageObj(makeBiExp(*e, rhs, std::logical_and<bool>()));
- }
- else break;
+ e = &manageObj(makeBiExp(*e, rhs, std::logical_and<bool>())); //throw std::bad_cast
+ }
return *e;
}
@@ -316,8 +309,8 @@ private:
nextToken();
const Expression& rhs = parseRelational();
- if (t == Token::TK_EQUAL) return manageObj(makeBiExp(e, rhs, std::equal_to <int>()));
- if (t == Token::TK_NOT_EQUAL) return manageObj(makeBiExp(e, rhs, std::not_equal_to<int>()));
+ if (t == Token::TK_EQUAL) return manageObj(makeBiExp(e, rhs, std::equal_to <int>())); //throw std::bad_cast
+ if (t == Token::TK_NOT_EQUAL) return manageObj(makeBiExp(e, rhs, std::not_equal_to<int>())); //
}
return e;
}
@@ -335,10 +328,10 @@ private:
nextToken();
const Expression& rhs = parseMultiplicative();
- if (t == Token::TK_LESS) return manageObj(makeBiExp(e, rhs, std::less <int>()));
- if (t == Token::TK_LESS_EQUAL) return manageObj(makeBiExp(e, rhs, std::less_equal <int>()));
- if (t == Token::TK_GREATER) return manageObj(makeBiExp(e, rhs, std::greater <int>()));
- if (t == Token::TK_GREATER_EQUAL) return manageObj(makeBiExp(e, rhs, std::greater_equal<int>()));
+ if (t == Token::TK_LESS) return manageObj(makeBiExp(e, rhs, std::less <int>())); //
+ if (t == Token::TK_LESS_EQUAL) return manageObj(makeBiExp(e, rhs, std::less_equal <int>())); //throw std::bad_cast
+ if (t == Token::TK_GREATER) return manageObj(makeBiExp(e, rhs, std::greater <int>())); //
+ if (t == Token::TK_GREATER_EQUAL) return manageObj(makeBiExp(e, rhs, std::greater_equal<int>())); //
}
return e;
}
@@ -347,35 +340,33 @@ private:
{
const Expression* e = &parsePrimary();
- for (;;) //associativity: ->
- if (token().type == Token::TK_MODULUS)
- {
- nextToken();
- const Expression& rhs = parsePrimary();
+ while (token().type == Token::TK_MODULUS) //associativity: ->
+ {
+ nextToken();
+ const Expression& rhs = parsePrimary();
- //"compile-time" check: n % 0
- const LiteralNumberEx* literal = dynamic_cast<const LiteralNumberEx*>(&rhs);
- if (literal && literal->eval() == 0)
+ //"compile-time" check: n % 0
+ if (auto literal = dynamic_cast<const ConstNumberExp*>(&rhs))
+ if (literal->eval() == 0)
throw ParsingError();
- e = &manageObj(makeBiExp(*e, rhs, std::modulus<int>()));
- }
- else break;
+ e = &manageObj(makeBiExp(*e, rhs, std::modulus<int>())); //throw std::bad_cast
+ }
return *e;
}
const Expression& parsePrimary()
{
- if (token().type == Token::TK_N)
+ if (token().type == Token::TK_VARIABLE_N)
{
nextToken();
- return manageObj(NumberN(n_));
+ return manageObj(VariableNumberNExp(n_));
}
- else if (token().type == Token::TK_NUMBER)
+ else if (token().type == Token::TK_CONST_NUMBER)
{
const int number = token().number;
nextToken();
- return manageObj(LiteralNumberEx(number));
+ return manageObj(ConstNumberExp(number));
}
else if (token().type == Token::TK_BRACKET_LEFT)
{
bgstack15