diff --git a/include/chaiscript/language/chaiscript_algebraic.hpp b/include/chaiscript/language/chaiscript_algebraic.hpp index 0338a02..36516dd 100644 --- a/include/chaiscript/language/chaiscript_algebraic.hpp +++ b/include/chaiscript/language/chaiscript_algebraic.hpp @@ -7,6 +7,8 @@ #ifndef CHAISCRIPT_ALGEBRAIC_HPP_ #define CHAISCRIPT_ALGEBRAIC_HPP_ +#include "../utility/fnv1a.hpp" + #include namespace chaiscript @@ -51,76 +53,39 @@ namespace chaiscript static Opers to_operator(const std::string &t_str, bool t_is_unary = false) { - if (t_str == "==") - { - return Opers::equals; - } else if (t_str == "<") { - return Opers::less_than; - } else if (t_str == ">") { - return Opers::greater_than; - } else if (t_str == "<=") { - return Opers::less_than_equal; - } else if (t_str == ">=") { - return Opers::greater_than_equal; - } else if (t_str == "!=") { - return Opers::not_equal; - } else if (t_str == "=") { - return Opers::assign; - } else if (t_str == "++") { - return Opers::pre_increment; - } else if (t_str == "--") { - return Opers::pre_decrement; - } else if (t_str == "*=") { - return Opers::assign_product; - } else if (t_str == "+=") { - return Opers::assign_sum; - } else if (t_str == "-=") { - return Opers::assign_difference; - } else if (t_str == "&=") { - return Opers::assign_bitwise_and; - } else if (t_str == "|=") { - return Opers::assign_bitwise_or; - } else if (t_str == "<<=") { - return Opers::assign_shift_left; - } else if (t_str == ">>=") { - return Opers::assign_shift_right; - } else if (t_str == "%=") { - return Opers::assign_remainder; - } else if (t_str == "^=") { - return Opers::assign_bitwise_xor; - } else if (t_str == "<<") { - return Opers::shift_left; - } else if (t_str == ">>") { - return Opers::shift_right; - } else if (t_str == "%") { - return Opers::remainder; - } else if (t_str == "&") { - return Opers::bitwise_and; - } else if (t_str == "|") { - return Opers::bitwise_or; - } else if (t_str == "^") { - return Opers::bitwise_xor; - } else if (t_str == "~") { - return Opers::bitwise_complement; - } else if (t_str == "+") { - if (t_is_unary) { - return Opers::unary_plus; - } else { - return Opers::sum; - } - } else if (t_str == "-") { - if (t_is_unary) { - return Opers::unary_minus; - } else { - return Opers::difference; - } - } else if (t_str == "/") { - return Opers::quotient; - } else if (t_str == "*") { - return Opers::product; - } else { - return Opers::invalid; - } + const auto op_hash = utility::fnv1a_32(t_str.c_str()); + switch (op_hash) { + case utility::fnv1a_32("=="): { return Opers::equals; } + case utility::fnv1a_32("<"): { return Opers::less_than; } + case utility::fnv1a_32(">"): { return Opers::greater_than; } + case utility::fnv1a_32("<="): { return Opers::less_than_equal; } + case utility::fnv1a_32(">="): { return Opers::greater_than_equal; } + case utility::fnv1a_32("!="): { return Opers::not_equal; } + case utility::fnv1a_32("="): { return Opers::assign; } + case utility::fnv1a_32("++"): { return Opers::pre_increment; } + case utility::fnv1a_32("--"): { return Opers::pre_decrement; } + case utility::fnv1a_32("*="): { return Opers::assign_product; } + case utility::fnv1a_32("+="): { return Opers::assign_sum; } + case utility::fnv1a_32("-="): { return Opers::assign_difference; } + case utility::fnv1a_32("&="): { return Opers::assign_bitwise_and; } + case utility::fnv1a_32("|="): { return Opers::assign_bitwise_or; } + case utility::fnv1a_32("<<="): { return Opers::assign_shift_left; } + case utility::fnv1a_32(">>="): { return Opers::assign_shift_right; } + case utility::fnv1a_32("%="): { return Opers::assign_remainder; } + case utility::fnv1a_32("^="): { return Opers::assign_bitwise_xor; } + case utility::fnv1a_32("<<"): { return Opers::shift_left; } + case utility::fnv1a_32(">>"): { return Opers::shift_right; } + case utility::fnv1a_32("%"): { return Opers::remainder; } + case utility::fnv1a_32("&"): { return Opers::bitwise_and; } + case utility::fnv1a_32("|"): { return Opers::bitwise_or; } + case utility::fnv1a_32("^"): { return Opers::bitwise_xor; } + case utility::fnv1a_32("~"): { return Opers::bitwise_complement; } + case utility::fnv1a_32("+"): { return t_is_unary ? Opers::unary_plus : Opers::sum; } + case utility::fnv1a_32("-"): { return t_is_unary ? Opers::unary_minus : Opers::difference; } + case utility::fnv1a_32("/"): { return Opers::quotient; } + case utility::fnv1a_32("*"): { return Opers::product; } + default: { return Opers::invalid; } + } } }; diff --git a/include/chaiscript/language/chaiscript_parser.hpp b/include/chaiscript/language/chaiscript_parser.hpp index 10a6a4a..e693804 100644 --- a/include/chaiscript/language/chaiscript_parser.hpp +++ b/include/chaiscript/language/chaiscript_parser.hpp @@ -23,6 +23,7 @@ #include "chaiscript_common.hpp" #include "chaiscript_optimizer.hpp" #include "chaiscript_tracer.hpp" +#include "../utility/fnv1a.hpp" #if defined(CHAISCRIPT_UTF16_UTF32) #include @@ -225,10 +226,18 @@ namespace chaiscript return operators; } - static constexpr const char * const m_multiline_comment_begin = "/*"; - static constexpr const char * const m_multiline_comment_end = "*/"; - static constexpr const char * const m_singleline_comment = "//"; - static constexpr const char * const m_annotation = "#"; + static constexpr const char m_multiline_comment_begin[] = "/*"; + static constexpr const char m_multiline_comment_end[] = "*/"; + static constexpr const char m_singleline_comment[] = "//"; + static constexpr const char m_annotation[] = "#"; + static constexpr const char m_cr_lf[] = "\r\n"; + enum { + m_multiline_comment_begin_len = sizeof(m_multiline_comment_begin)-1 + ,m_multiline_comment_end_len = sizeof(m_multiline_comment_end)-1 + ,m_singleline_comment_len = sizeof(m_singleline_comment)-1 + ,m_annotation_len = sizeof(m_annotation)-1 + ,m_cr_lf_len = sizeof(m_cr_lf)-1 + }; const std::array, detail::max_alphabet> &m_alphabet = create_alphabet(); const std::vector> &m_operator_matches = create_operator_matches(); @@ -318,9 +327,10 @@ namespace chaiscript return static_cast(std::distance(m_pos, m_end)); } - char operator*() const { + const char& operator*() const { if (m_pos == m_end) { - return '\0'; + static const char ktmp ='\0'; + return ktmp; } else { return *m_pos; } @@ -428,20 +438,30 @@ namespace chaiscript } + /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace + #define Symbol_(t_s, len) \ + ( \ + m_position.remaining() >= len \ + ? std::memcmp(t_s, &(*m_position), len) == 0 \ + ? ((m_position += len),true) \ + :false \ + :false \ + ) + /// Skips any multi-line or single-line comment bool SkipComment() { - if (Symbol_(m_multiline_comment_begin)) { + if (Symbol_(m_multiline_comment_begin, m_multiline_comment_begin_len)) { while (m_position.has_more()) { - if (Symbol_(m_multiline_comment_end)) { + if (Symbol_(m_multiline_comment_end, m_multiline_comment_end_len)) { break; } else if (!Eol_()) { ++m_position; } } return true; - } else if (Symbol_(m_singleline_comment)) { + } else if (Symbol_(m_singleline_comment, m_singleline_comment_len)) { while (m_position.has_more()) { - if (Symbol_("\r\n")) { + if (Symbol_(m_cr_lf, m_cr_lf_len)) { m_position -= 2; break; } else if (Char_('\n')) { @@ -452,9 +472,9 @@ namespace chaiscript } } return true; - } else if (Symbol_(m_annotation)) { + } else if (Symbol_(m_annotation, m_annotation_len)) { while (m_position.has_more()) { - if (Symbol_("\r\n")) { + if (Symbol_(m_cr_lf, m_cr_lf_len)) { m_position -= 2; break; } else if (Char_('\n')) { @@ -833,74 +853,77 @@ namespace chaiscript const auto start = m_position; if (Id_()) { - const auto text = Position::str(start, m_position); + auto text = Position::str(start, m_position); + const auto text_hash = utility::fnv1a_32(text.c_str()); if (validate) { validate_object_name(text); } - if (text == "true") { - m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(true))); - } else if (text == "false") { - m_match_stack.push_back(make_node>(text, start.line, start.col, const_var(false))); - } else if (text == "Infinity") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::numeric_limits::infinity()))); - } else if (text == "NaN") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(std::numeric_limits::quiet_NaN()))); - } else if (text == "__LINE__") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(start.line))); - } else if (text == "__FILE__") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(m_filename))); - } else if (text == "__FUNC__") { - const std::string fun_name = [&]()->std::string{ + switch (text_hash) { + case utility::fnv1a_32("true"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, const_var(true))); + } break; + case utility::fnv1a_32("false"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, const_var(false))); + } break; + case utility::fnv1a_32("Infinity"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(std::numeric_limits::infinity()))); + } break; + case utility::fnv1a_32("NaN"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(std::numeric_limits::quiet_NaN()))); + } break; + case utility::fnv1a_32("__LINE__"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(start.line))); + } break; + case utility::fnv1a_32("__FILE__"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(m_filename))); + } break; + case utility::fnv1a_32("__FUNC__"): { + std::string fun_name = "NOT_IN_FUNCTION"; for (size_t idx = m_match_stack.size() - 1; idx > 0; --idx) { if (m_match_stack[idx-1]->identifier == AST_Node_Type::Id && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { - return m_match_stack[idx-1]->text; + fun_name = m_match_stack[idx-1]->text; } } - return "NOT_IN_FUNCTION"; - }(); - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(fun_name))); - } else if (text == "__CLASS__") { - const std::string fun_name = [&]()->std::string{ + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(fun_name))); + } break; + case utility::fnv1a_32("__CLASS__"): { + std::string fun_name = "NOT_IN_CLASS"; for (size_t idx = m_match_stack.size() - 1; idx > 1; --idx) { if (m_match_stack[idx-2]->identifier == AST_Node_Type::Id && m_match_stack[idx-1]->identifier == AST_Node_Type::Id && m_match_stack[idx-0]->identifier == AST_Node_Type::Arg_List) { - return m_match_stack[idx-2]->text; + fun_name = m_match_stack[idx-2]->text; } } - return "NOT_IN_CLASS"; - }(); - m_match_stack.push_back(make_node>(text, start.line, start.col, - const_var(fun_name))); - } else if (text == "_") { - m_match_stack.push_back(make_node>(text, start.line, start.col, - Boxed_Value(std::make_shared()))); - } else { - m_match_stack.push_back(make_node>( - [&]()->std::string{ - if (*start == '`') { - // 'escaped' literal, like an operator name - return Position::str(start+1, m_position-1); - } else { - return text; - } - }(), - start.line, start.col)); + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + const_var(fun_name))); + } break; + case utility::fnv1a_32("_"): { + m_match_stack.push_back(make_node>(std::move(text), start.line, start.col, + Boxed_Value(std::make_shared()))); + } break; + default: { + std::string val = std::move(text); + if (*start == '`') { + // 'escaped' literal, like an operator name + val = Position::str(start+1, m_position-1); + } + m_match_stack.push_back(make_node>(val, start.line, start.col)); + } break; } - return true; } else { return false; @@ -1330,25 +1353,6 @@ namespace chaiscript return retval; } - /// Reads a symbol group from input if it matches the parameter, without skipping initial whitespace - bool Symbol_(const char *t_s) { - const auto len = strlen(t_s); - - if (m_position.remaining() >= len) { - auto tmp = m_position; - for (size_t i = 0; i < len; ++i) { - if (*tmp != t_s[i]) { - return false; - } - ++tmp; - } - m_position = tmp; - return true; - } - - return false; - } - bool is_operator(const std::string &t_s) const { return std::any_of(m_operator_matches.begin(), m_operator_matches.end(), [t_s](const std::vector &opers) { @@ -1363,7 +1367,7 @@ namespace chaiscript bool Symbol(const char *t_s, const bool t_disallow_prevention=false) { SkipWS(); const auto start = m_position; - bool retval = Symbol_(t_s); + bool retval = Symbol_(t_s, std::strlen(t_s)); // ignore substring matches if (retval && m_position.has_more() && (t_disallow_prevention == false) && char_in_alphabet(*m_position,detail::symbol_alphabet)) { @@ -1382,7 +1386,7 @@ namespace chaiscript bool Eol_(const bool t_eos = false) { bool retval = false; - if (m_position.has_more() && (Symbol_("\r\n") || Char_('\n'))) { + if (m_position.has_more() && (Symbol_(m_cr_lf, m_cr_lf_len) || Char_('\n'))) { retval = true; //++m_position.line; m_position.col = 1; @@ -2523,9 +2527,20 @@ namespace chaiscript return m_match_stack.front(); } }; + template + constexpr const char ChaiScript_Parser::m_multiline_comment_begin[]; + template + constexpr const char ChaiScript_Parser::m_multiline_comment_end[]; + template + constexpr const char ChaiScript_Parser::m_singleline_comment[]; + template + constexpr const char ChaiScript_Parser::m_annotation[]; + template + constexpr const char ChaiScript_Parser::m_cr_lf[]; } } +#undef Symbol_ #if defined(CHAISCRIPT_MSVC) && defined(CHAISCRIPT_PUSHED_MIN_MAX) #undef CHAISCRIPT_PUSHED_MIN_MAX diff --git a/include/chaiscript/utility/fnv1a.hpp b/include/chaiscript/utility/fnv1a.hpp new file mode 100644 index 0000000..fcf9b1e --- /dev/null +++ b/include/chaiscript/utility/fnv1a.hpp @@ -0,0 +1,22 @@ +// This file is distributed under the BSD License. +// See "license.txt" for details. +// Copyright 2009-2012, Jonathan Turner (jonathan@emptycrate.com) +// Copyright 2009-2016, Jason Turner (jason@emptycrate.com) +// http://www.chaiscript.com + +#ifndef CHAISCRIPT_UTILITY_FNV1A_HPP_ +#define CHAISCRIPT_UTILITY_FNV1A_HPP_ + +#include + +namespace chaiscript +{ + namespace utility + { + static constexpr std::uint32_t fnv1a_32(const char *s, std::uint32_t h = 0x811c9dc5) { + return (*s == 0) ? h : fnv1a_32(s+1, ((h ^ (*s)) * 0x01000193)); + } + } +} + +#endif