mirror of
https://github.com/GothenburgBitFactory/timewarrior.git
synced 2025-07-07 20:06:39 +02:00
Cleanup: Removed unused files
This commit is contained in:
parent
b41b56c00c
commit
68ba48e85f
14 changed files with 2 additions and 1335 deletions
|
@ -61,5 +61,5 @@ set (CPACK_SOURCE_IGNORE_FILES "CMakeCache" "CMakeFiles" "CPackConfig" "CPackSo
|
|||
"_CPack_Packages" "cmake_install" "install_manifest" "Makefile$"
|
||||
"test" "package-config" "src/timew$" "src/libtimew.a"
|
||||
"src/commands/libcommands.a"
|
||||
"/\\\\.gitignore" "/\\\\.git/" "swp$" "src/gr$")
|
||||
"/\\\\.gitignore" "/\\\\.git/" "swp$")
|
||||
include (CPack)
|
||||
|
|
|
@ -11,10 +11,8 @@ set (timew_SRCS CLI.cpp CLI.h
|
|||
Datafile.cpp Datafile.h
|
||||
Exclusion.cpp Exclusion.h
|
||||
Extensions.cpp Extensions.h
|
||||
Grammar.cpp Grammar.h
|
||||
Interval.cpp Interval.h
|
||||
Lexer.cpp Lexer.h
|
||||
LR0.cpp LR0.h
|
||||
Rules.cpp Rules.h
|
||||
Timeline.cpp Timeline.h
|
||||
classifier.cpp
|
||||
|
@ -44,13 +42,10 @@ set (libshared_SRCS libshared/src/Args.cpp libshared/src/Args.h
|
|||
add_library (timew STATIC ${timew_SRCS})
|
||||
add_library (libshared STATIC ${libshared_SRCS})
|
||||
add_executable (timew_executable timew.cpp)
|
||||
add_executable (gr_executable gr.cpp)
|
||||
|
||||
target_link_libraries (timew_executable timew libshared commands timew libshared ${TIMEW_LIBRARIES})
|
||||
target_link_libraries (gr_executable timew libshared ${TIMEW_LIBRARIES})
|
||||
|
||||
set_property (TARGET timew_executable PROPERTY OUTPUT_NAME "timew")
|
||||
set_property (TARGET gr_executable PROPERTY OUTPUT_NAME "gr")
|
||||
|
||||
install (TARGETS timew_executable DESTINATION bin)
|
||||
|
||||
|
|
284
src/Grammar.cpp
284
src/Grammar.cpp
|
@ -1,284 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <Grammar.h>
|
||||
#include <Lexer.h>
|
||||
#include <shared.h>
|
||||
#include <format.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Grammar::loadFromFile (File& file)
|
||||
{
|
||||
if (! file.exists ())
|
||||
throw format ("Grammar file '{1}' not found.", file._data);
|
||||
|
||||
std::string contents;
|
||||
file.read (contents);
|
||||
loadFromString (contents);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Load and parse BNF.
|
||||
//
|
||||
// Syntax:
|
||||
// rule-name: alternate1-token1 alternate1-token2
|
||||
// alternate2-token1
|
||||
//
|
||||
// - Rules are aligned at left margin only, followed by a comma.
|
||||
// - Productions are indented and never at left margin.
|
||||
// - Blank line between rules.
|
||||
//
|
||||
// Details:
|
||||
// - Literals are always double-quoted.
|
||||
// - "*", "+" and "?" suffixes have POSIX semantics.
|
||||
// - "є" means empty set.
|
||||
// - Literal modifiers:
|
||||
// - :a Accept abbreviations
|
||||
// - :i Accept caseless match
|
||||
//
|
||||
void Grammar::loadFromString (const std::string& input)
|
||||
{
|
||||
std::string rule_name = "";
|
||||
|
||||
// This is a state machine. Read each line.
|
||||
for (auto& line : split (input, '\n'))
|
||||
{
|
||||
// Skip whole-line comments.
|
||||
if (line[0] == '#')
|
||||
continue;
|
||||
|
||||
// Eliminate inline comments.
|
||||
std::string::size_type hash = line.find ('#');
|
||||
if (hash != std::string::npos)
|
||||
line.resize (hash);
|
||||
|
||||
// Skip blank lines with no semantics.
|
||||
line = Lexer::trim (line);
|
||||
if (line == "" and rule_name == "")
|
||||
continue;
|
||||
|
||||
if (line != "")
|
||||
{
|
||||
int token_count = 0;
|
||||
|
||||
Lexer l (line);
|
||||
Lexer::Type type;
|
||||
std::string token;
|
||||
while (l.token (token, type))
|
||||
{
|
||||
++token_count;
|
||||
|
||||
if (token.back () == ':')
|
||||
{
|
||||
// Capture the Rule_name.
|
||||
rule_name = token.substr (0, token.size () - 1);
|
||||
|
||||
// If this is the first Rule, capture it as a starting point.
|
||||
if (_start == "")
|
||||
_start = rule_name;
|
||||
|
||||
_rules[rule_name] = Grammar::Rule ();
|
||||
token_count = 0;
|
||||
}
|
||||
else if (token.front () == ':')
|
||||
{
|
||||
// Decorate the most recent token, of the most recent Production,
|
||||
// of the current Rule.
|
||||
_rules[rule_name].back ().back ().decorate (token);
|
||||
}
|
||||
else
|
||||
{
|
||||
// If no Production was added yet, add one.
|
||||
if (token_count <= 1)
|
||||
_rules[rule_name].push_back (Grammar::Production ());
|
||||
|
||||
// Add the new Token to the most recent Production, of the current
|
||||
// Rule.
|
||||
_rules[rule_name].back ().push_back (Grammar::Token (token));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A blank line in the input ends the current rule definition.
|
||||
else
|
||||
rule_name = "";
|
||||
}
|
||||
|
||||
if (_debug)
|
||||
std::cout << dump () << "\n";
|
||||
|
||||
// Validate the parsed grammar.
|
||||
validate ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Grammar::start () const
|
||||
{
|
||||
return _start;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string> Grammar::rules () const
|
||||
{
|
||||
std::vector <std::string> results;
|
||||
for (const auto& rule : _rules)
|
||||
results.push_back (rule.first);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::string> Grammar::terminals () const
|
||||
{
|
||||
std::vector <std::string> results;
|
||||
for (const auto& rule : _rules)
|
||||
for (const auto& production : rule.second)
|
||||
for (const auto& token : production)
|
||||
if (_rules.find (token._token) == _rules.end ())
|
||||
results.push_back (token._token);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::vector <std::vector <std::string>> Grammar::augmented () const
|
||||
{
|
||||
std::vector <std::vector <std::string>> results {{"S", "-->", _start}};
|
||||
for (const auto& rule : _rules)
|
||||
for (const auto& production : rule.second)
|
||||
{
|
||||
std::vector <std::string> terms;
|
||||
terms.push_back (rule.first);
|
||||
terms.push_back ("-->");
|
||||
for (const auto& token : production)
|
||||
terms.push_back (token._token);
|
||||
|
||||
results.push_back (terms);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Grammar::debug (bool value)
|
||||
{
|
||||
_debug = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string Grammar::dump () const
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Grammar\n";
|
||||
for (const auto& rule : _rules)
|
||||
{
|
||||
// Indicate the start Rule.
|
||||
out << " " << (rule.first == _start ? "▶" : " ") << " " << rule.first << ": ";
|
||||
|
||||
int count = 0;
|
||||
for (const auto& production : rule.second)
|
||||
{
|
||||
if (count)
|
||||
out << "| ";
|
||||
|
||||
for (const auto& token : production)
|
||||
{
|
||||
out << token._token;
|
||||
if (token._decoration != "")
|
||||
out << " " << token._decoration;
|
||||
out << " ";
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void Grammar::validate () const
|
||||
{
|
||||
if (_start == "")
|
||||
throw std::string ("There are no rules defined.");
|
||||
|
||||
std::vector <std::string> allRules;
|
||||
std::vector <std::string> allTokens;
|
||||
std::vector <std::string> allLeftRecursive;
|
||||
|
||||
for (const auto& rule : _rules)
|
||||
{
|
||||
allRules.push_back (rule.first);
|
||||
|
||||
for (const auto& production : rule.second)
|
||||
{
|
||||
for (const auto& token : production)
|
||||
{
|
||||
if (token._token.front () != '"' and
|
||||
token._token.front () != '/')
|
||||
allTokens.push_back (token._token);
|
||||
|
||||
if (token._token == production[0]._token &&
|
||||
rule.first == production[0]._token &&
|
||||
production.size () == 1)
|
||||
allLeftRecursive.push_back (token._token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector <std::string> notUsed;
|
||||
std::vector <std::string> notDefined;
|
||||
listDiff (allRules, allTokens, notUsed, notDefined);
|
||||
|
||||
// Undefined value - these are definitions that appear in token, but are
|
||||
// not in _rules.
|
||||
for (const auto& nd : notDefined)
|
||||
if (nd != "є")
|
||||
throw format ("Definition '{1}' referenced, but not defined.", nd);
|
||||
|
||||
// Circular definitions - these are names in _rules that also appear as
|
||||
// the only token in any of the alternates for that definition.
|
||||
for (const auto& lr : allLeftRecursive)
|
||||
throw format ("Definition '{1}' is left recursive.", lr);
|
||||
|
||||
for (const auto& r : allRules)
|
||||
if (r[0] == '"' or
|
||||
r[0] == '/')
|
||||
throw format ("Definition '{1}' must not be a literal.");
|
||||
|
||||
// Unused definitions - these are names in _rules that are never
|
||||
// referenced as token.
|
||||
for (const auto& nu : notUsed)
|
||||
if (nu != _start)
|
||||
throw format ("Definition '{1}' is defined, but not referenced.", nu);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -1,78 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_GRAMMAR
|
||||
#define INCLUDED_GRAMMAR
|
||||
|
||||
#include <FS.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class Grammar
|
||||
{
|
||||
public:
|
||||
Grammar () = default;
|
||||
void loadFromFile (File&);
|
||||
void loadFromString (const std::string&);
|
||||
std::string start () const;
|
||||
std::vector <std::string> rules () const;
|
||||
std::vector <std::string> terminals () const;
|
||||
std::vector <std::vector <std::string>> augmented () const;
|
||||
void debug (bool);
|
||||
std::string dump () const;
|
||||
|
||||
protected:
|
||||
class Token
|
||||
{
|
||||
public:
|
||||
Token (const std::string& value) { _token = value; }
|
||||
void decorate (const std::string& value) { _decoration = value; }
|
||||
|
||||
std::string _token;
|
||||
std::string _decoration;
|
||||
};
|
||||
|
||||
class Production : public std::vector <Token>
|
||||
{
|
||||
};
|
||||
|
||||
class Rule : public std::vector <Production>
|
||||
{
|
||||
};
|
||||
|
||||
private:
|
||||
void validate () const;
|
||||
|
||||
private:
|
||||
// rule name rule
|
||||
// | |
|
||||
std::map <std::string, Grammar::Rule> _rules {};
|
||||
std::string _start {};
|
||||
bool _debug {false};
|
||||
};
|
||||
|
||||
#endif
|
489
src/LR0.cpp
489
src/LR0.cpp
|
@ -1,489 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <LR0.h>
|
||||
#include <Lexer.h>
|
||||
#include <Table.h>
|
||||
#include <Color.h>
|
||||
#include <shared.h>
|
||||
#include <format.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Given a grammar:
|
||||
// - Obtain the augmented grammar
|
||||
// - Create the first state from the first augmented grammar rule
|
||||
// - Expand the first state
|
||||
// - Recursively create and expand all the other states
|
||||
void LR0::initialize (const Grammar& grammar)
|
||||
{
|
||||
// Save important grammar information.
|
||||
_augmented = grammar.augmented ();
|
||||
_rules = grammar.rules ();
|
||||
_terminals = grammar.terminals ();
|
||||
|
||||
if (_debug)
|
||||
{
|
||||
std::cout << "Augmented Grammar\n";
|
||||
auto count = 0;
|
||||
for (const auto& item : _augmented)
|
||||
{
|
||||
std::cout << " [" << count++ << "]";
|
||||
for (const auto& term : item)
|
||||
std::cout << " " << term;
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
std::cout << "Rules\n";
|
||||
for (const auto& r : _rules)
|
||||
std::cout << " " << r << "\n";
|
||||
|
||||
std::cout << "\n";
|
||||
std::cout << "Terminals\n";
|
||||
for (const auto& t : _terminals)
|
||||
std::cout << " " << t << "\n";
|
||||
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
// Determine the parser states.
|
||||
States states;
|
||||
initializeFirstState (states);
|
||||
closeState (states, 0);
|
||||
if (_debug)
|
||||
std::cout << states.dump () << "\n";
|
||||
|
||||
// Construct the parser tables.
|
||||
createParseTable (states);
|
||||
if (_debug)
|
||||
std::cout << dump () << "\n";;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Collect a unique set of expected symbols from the closure. This is the set
|
||||
// of symbols where '● X' appears in an item.
|
||||
std::set <std::string> LR0::getExpectedSymbols (const Closure& closure) const
|
||||
{
|
||||
std::set <std::string> expected;
|
||||
for (auto& item : closure)
|
||||
if (! item.done ())
|
||||
expected.insert (item.next ());
|
||||
|
||||
return expected;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// The first state is юust the augmented grammar with the expected symbols all
|
||||
// at the first symbol of each rule, i.e. exactly what happens when an Item is
|
||||
// instantiated from a grammar rule.
|
||||
void LR0::initializeFirstState (States& states) const
|
||||
{
|
||||
LR0::Closure result;
|
||||
for (unsigned int r = 0; r < _augmented.size (); ++r)
|
||||
{
|
||||
Item item (_augmented[r]);
|
||||
item.setGrammarRuleIndex (r);
|
||||
result.push_back (item);
|
||||
}
|
||||
|
||||
states.push_back (result);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void LR0::closeState (States& states, const int state) const
|
||||
{
|
||||
// Obtain all the expected symbols for this state.
|
||||
auto expectedSymbols = getExpectedSymbols (states[state]);
|
||||
for (auto& expected : expectedSymbols)
|
||||
{
|
||||
// This will be the new state.
|
||||
Closure closure;
|
||||
|
||||
// Track additional symbols.
|
||||
std::set <std::string> seen;
|
||||
|
||||
// Find all the rules in this state that are expecting 'expected'.
|
||||
for (auto& item : states[state])
|
||||
{
|
||||
if (! item.done () &&
|
||||
item.next () == expected)
|
||||
{
|
||||
Item advanced (item);
|
||||
advanced.advance ();
|
||||
closure.push_back (advanced);
|
||||
|
||||
if (! advanced.done ())
|
||||
{
|
||||
auto nextSymbol = advanced.next ();
|
||||
if (seen.find (nextSymbol) == seen.end ())
|
||||
{
|
||||
for (unsigned int r = 0; r < _augmented.size (); ++r)
|
||||
{
|
||||
if (_augmented[r][0] == nextSymbol)
|
||||
{
|
||||
Item additional (_augmented[r]);
|
||||
additional.setGrammarRuleIndex (r);
|
||||
closure.push_back (additional);
|
||||
seen.insert (nextSymbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the new state is not already created.
|
||||
bool skip = false;
|
||||
for (auto& state : states)
|
||||
if (state[0] == closure[0])
|
||||
skip = true;
|
||||
|
||||
// Create the new state, and recurse to close it.
|
||||
if (! skip)
|
||||
{
|
||||
states.push_back (closure);
|
||||
closeState (states, states.size () - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void LR0::createParseTable (States& states)
|
||||
{
|
||||
// Add artificial end-point.
|
||||
_terminals.push_back ("$");
|
||||
|
||||
// First size the tables:
|
||||
// - Create a row for every state
|
||||
// - Create a column for every terminal in the _actions table
|
||||
// - Create a column for every rule in the _goto table
|
||||
for (unsigned int state = 0; state < states.size (); ++state)
|
||||
{
|
||||
// Create a column for every terminal.
|
||||
_actions.push_back ({});
|
||||
for (const auto& terminal : _terminals)
|
||||
_actions[state][terminal] = "";
|
||||
|
||||
_goto.push_back ({});
|
||||
for (const auto& rule : _rules)
|
||||
_goto[state][rule] = "";
|
||||
}
|
||||
|
||||
// Look for states with items that are done, and mark them as reductions, but
|
||||
// a reduction of grammar rule 0 is marked "acc".
|
||||
for (unsigned int state = 0; state < states.size (); ++state)
|
||||
for (unsigned int item = 0; item < states[state].size (); ++item)
|
||||
if (states[state][item].done ())
|
||||
{
|
||||
if (states[state][item]._grammarRule == 0)
|
||||
_actions[state]["$"] = "acc";
|
||||
else
|
||||
for (const auto& terminal : _terminals)
|
||||
_actions[state][terminal] = format ("r{1}", states[state][item]._grammarRule);
|
||||
}
|
||||
|
||||
// Look at all items in all states, and if the item is not done, find the
|
||||
// state with a matching, advanced, first item.
|
||||
for (unsigned int state = 0; state < states.size (); ++state)
|
||||
for (unsigned int item = 0; item < states[state].size (); ++item)
|
||||
if (! states[state][item].done ())
|
||||
{
|
||||
auto nextSymbol = states[state][item].next ();
|
||||
|
||||
Item advanced (states[state][item]);
|
||||
advanced.advance ();
|
||||
|
||||
for (unsigned int s = 0; s < states.size (); ++s)
|
||||
{
|
||||
if (states[s][0] == advanced)
|
||||
{
|
||||
if (std::find (_terminals.begin (), _terminals.end (), nextSymbol) != _terminals.end ())
|
||||
_actions[state][nextSymbol] = format ("s{1}", s);
|
||||
else
|
||||
_goto[state][nextSymbol] = format ("s{1}", s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// "Compilers. Principles, Techniques, and Tools", Aho/Sethi/Ullman. p219.
|
||||
//
|
||||
// set ip to point to the first symbol of w$
|
||||
// repeat forever begin
|
||||
// let s be the state on top of the stack
|
||||
// let a be the symbol pointed to by ip
|
||||
//
|
||||
// if action[s,a] = shift s' then begin
|
||||
// push a then s' on top of the stack
|
||||
// advance ip to the next input symbol
|
||||
// end
|
||||
//
|
||||
// else if action[s,a] = reduce A --> B then begin
|
||||
// pop 2 * [B] symbols off the stack
|
||||
// let s' be the state now at the top of the stack
|
||||
// push A, then goto[s',A] on top of the stack
|
||||
// output the production A --> B
|
||||
// end
|
||||
//
|
||||
// else if then begin
|
||||
// if action[s,a] = accept then begin
|
||||
// return
|
||||
// end
|
||||
// end
|
||||
//
|
||||
// else
|
||||
// error
|
||||
// end
|
||||
// end
|
||||
//
|
||||
void LR0::parse (const std::string& input)
|
||||
{
|
||||
// set ip to point to the first symbol of w$
|
||||
Lexer l (input);
|
||||
std::string token;
|
||||
Lexer::Type type;
|
||||
if (! l.token (token, type))
|
||||
{
|
||||
// TODO Error: Nothing to parse.
|
||||
std::cout << "# LR0::parse EOS\n";
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "# LR0::parse token '" << token << "' " << Lexer::typeToString (type) << "\n";
|
||||
|
||||
// repeat forever begin
|
||||
while (1)
|
||||
{
|
||||
// let s be the state on top of the stack
|
||||
// let token be the symbol pointed to by ip
|
||||
|
||||
// TODO Shift
|
||||
// if action[s,token] == shift s'
|
||||
// push token then s' on top of the stack
|
||||
// advance ip to the next input symbol
|
||||
// end
|
||||
if (0)
|
||||
{
|
||||
std::cout << "# LR0::parse shift\n";
|
||||
|
||||
if (! l.token (token, type))
|
||||
{
|
||||
// TODO Error: No more to parse.
|
||||
std::cout << "# LR0::parse unexpected EOS\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Reduce
|
||||
// else if action[s,token] == reduce A --> B
|
||||
// pop 2 * [B] symbols off the stack
|
||||
// let s' be the state now at the top of the stack
|
||||
// push A, then goto[s',A] on top of the stack
|
||||
// output the production A --> B
|
||||
else if (0)
|
||||
{
|
||||
std::cout << "# LR0::parse reduce\n";
|
||||
}
|
||||
|
||||
// TODO Accept
|
||||
// else if then begin
|
||||
// if action[s,token] == accept
|
||||
// return
|
||||
else if (0)
|
||||
{
|
||||
std::cout << "# LR0::parse accept\n";
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Error
|
||||
else
|
||||
{
|
||||
std::cout << "# LR0::parse error\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void LR0::debug (bool value)
|
||||
{
|
||||
_debug = value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// +-------+---------------+---------------+
|
||||
// | state | terminals $ | non-terminals |
|
||||
// +-------+--+--+--+--+---+----+-----+----+
|
||||
// | | | | | | | | | |
|
||||
// +-------+--+--+--+--+---+----+-----+----+
|
||||
// | | | | | | | | | |
|
||||
// +-------+--+--+--+--+---+----+-----+----+
|
||||
std::string LR0::dump () const
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "Parser Tables\n";
|
||||
|
||||
Table t;
|
||||
t.leftMargin (2);
|
||||
t.colorHeader (Color ("underline"));
|
||||
|
||||
// Add columns.
|
||||
t.add ("State", true);
|
||||
for (const auto& terminal : _terminals)
|
||||
t.add (terminal, true);
|
||||
|
||||
for (const auto& rule : _rules)
|
||||
t.add (rule, true);
|
||||
|
||||
// Add cells.
|
||||
for (unsigned int state = 0; state < _actions.size (); ++state)
|
||||
{
|
||||
int row = t.addRow ();
|
||||
int col = 0;
|
||||
t.set (row, col++, state);
|
||||
|
||||
for (const auto& terminal : _terminals)
|
||||
{
|
||||
auto data = _actions[state].at (terminal);
|
||||
Color color (data[0] == 'r' ? "rgb535 on rgb412" :
|
||||
data[0] == 's' ? "rgb045 on rgb015" :
|
||||
data[0] == 'a' ? "rgb154 on rgb031" :
|
||||
"");
|
||||
t.set (row, col++, data, color);
|
||||
}
|
||||
|
||||
for (const auto& rule : _rules)
|
||||
{
|
||||
auto data = _goto[state].at (rule);
|
||||
Color color (data != "" ? "rgb045 on rgb015" : "");
|
||||
t.set (row, col++, data, color);
|
||||
}
|
||||
}
|
||||
|
||||
out << t.render ();
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
LR0::Item::Item (const std::vector <std::string>& rule)
|
||||
: _rule (rule)
|
||||
, _cursor (2)
|
||||
, _grammarRule (-1)
|
||||
{
|
||||
if (_rule.size () == 3 && _rule[2] == "є")
|
||||
_rule.pop_back ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool LR0::Item::operator== (const Item& other)
|
||||
{
|
||||
if (_cursor != other._cursor ||
|
||||
_grammarRule != other._grammarRule ||
|
||||
_rule.size () != other._rule.size ())
|
||||
return false;
|
||||
|
||||
for (unsigned int i = 0; i < _rule.size () - 1; ++i)
|
||||
if (_rule[i] != other._rule[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void LR0::Item::setGrammarRuleIndex (const int rule)
|
||||
{
|
||||
_grammarRule = rule;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool LR0::Item::advance ()
|
||||
{
|
||||
if (_cursor >= _rule.size ())
|
||||
return false;
|
||||
|
||||
++_cursor;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
bool LR0::Item::done () const
|
||||
{
|
||||
return _cursor >= _rule.size ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string LR0::Item::next () const
|
||||
{
|
||||
return _rule[_cursor];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string LR0::Item::dump () const
|
||||
{
|
||||
std::stringstream out;
|
||||
|
||||
for (unsigned int i = 0; i < _rule.size (); ++i)
|
||||
{
|
||||
if (i)
|
||||
out << " ";
|
||||
|
||||
if (i == _cursor)
|
||||
out << "● ";
|
||||
|
||||
out << _rule[i];
|
||||
}
|
||||
|
||||
if (_cursor >= _rule.size ())
|
||||
out << " ●";
|
||||
|
||||
if (_grammarRule != -1)
|
||||
out << " [g" << _grammarRule << "]";
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
std::string LR0::States::dump () const
|
||||
{
|
||||
std::stringstream out;
|
||||
out << "States\n";
|
||||
|
||||
for (unsigned int state = 0; state < this->size (); ++state)
|
||||
{
|
||||
out << " State " << state << "\n";
|
||||
for (const auto& item : (*this)[state])
|
||||
out << " " << item.dump () << "\n";
|
||||
}
|
||||
|
||||
return out.str ();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
90
src/LR0.h
90
src/LR0.h
|
@ -1,90 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef INCLUDED_LR0
|
||||
#define INCLUDED_LR0
|
||||
|
||||
#include <Grammar.h>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
class LR0
|
||||
{
|
||||
public:
|
||||
void initialize (const Grammar&);
|
||||
void parse (const std::string&);
|
||||
void debug (bool);
|
||||
std::string dump () const;
|
||||
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
Item (const std::vector <std::string>&);
|
||||
bool operator== (const LR0::Item&);
|
||||
void setGrammarRuleIndex (const int);
|
||||
bool advance ();
|
||||
bool done () const;
|
||||
std::string next () const;
|
||||
std::string dump () const;
|
||||
|
||||
public:
|
||||
std::vector <std::string> _rule;
|
||||
unsigned int _cursor;
|
||||
int _grammarRule;
|
||||
};
|
||||
|
||||
class Closure : public std::vector <Item>
|
||||
{
|
||||
};
|
||||
|
||||
class States : public std::vector <Closure>
|
||||
{
|
||||
public:
|
||||
std::string dump () const;
|
||||
};
|
||||
|
||||
private:
|
||||
std::set <std::string> getExpectedSymbols (const Closure&) const;
|
||||
void initializeFirstState (States&) const;
|
||||
void closeState (States&, const int) const;
|
||||
void createParseTable (States&);
|
||||
|
||||
private:
|
||||
// Copy of the grammar details.
|
||||
std::vector <std::vector <std::string>> _augmented;
|
||||
std::vector <std::string> _rules;
|
||||
std::vector <std::string> _terminals;
|
||||
|
||||
// state column result
|
||||
// | | |
|
||||
std::vector <std::map <std::string, std::string>> _actions;
|
||||
std::vector <std::map <std::string, std::string>> _goto;
|
||||
|
||||
bool _debug {false};
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,33 +0,0 @@
|
|||
# Timewarrior grammar definition.
|
||||
|
||||
# Conventions:
|
||||
# - Literals are always double-quoted.
|
||||
# - "*", "+" and "?" suffixes have POSIX semantics.
|
||||
# - "є" means empty set.
|
||||
# - Lower-level primitives are barewords.
|
||||
# - Literal modifiers:
|
||||
# - :a Accept abbreviations
|
||||
# - :i Accept caseless match
|
||||
# - Blank line between rules.
|
||||
|
||||
# Left associative:
|
||||
# A -> A <op> B
|
||||
# B
|
||||
#
|
||||
# Right associative:
|
||||
# A -> B <op> A
|
||||
# B
|
||||
|
||||
cli: "start" :ai
|
||||
"stop" :ai
|
||||
"track" :ai
|
||||
help # Non-terminal, cannot contain є.
|
||||
є
|
||||
|
||||
help: "help" :ai topic
|
||||
"help" :ai
|
||||
|
||||
topic: "usage" :ai
|
||||
/dates?/ :ai
|
||||
/times?/ :ai
|
||||
|
113
src/gr.cpp
113
src/gr.cpp
|
@ -1,113 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <FS.h>
|
||||
#include <Grammar.h>
|
||||
#include <LR0.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void usage ()
|
||||
{
|
||||
std::cout << "\n"
|
||||
<< "Usage: gr [options] <grammar> [<args>]\n"
|
||||
<< "\n"
|
||||
<< "Options are:\n"
|
||||
<< " -h/--help Command usage\n"
|
||||
<< " -d/--debug Debug mode\n"
|
||||
<< "\n";
|
||||
exit (-1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int argc, char** argv)
|
||||
{
|
||||
// Process command line arguments
|
||||
std::string grammarFile = "";
|
||||
std::string commandLine = "";
|
||||
bool debug = false;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
if (argv[i][0] == '-')
|
||||
{
|
||||
if (!strcmp (argv[i], "-h")) usage ();
|
||||
else if (!strcmp (argv[i], "--help")) usage ();
|
||||
else if (!strcmp (argv[i], "-d")) debug = true;
|
||||
else if (!strcmp (argv[i], "--debug")) debug = true;
|
||||
else
|
||||
{
|
||||
std::cout << "Unrecognized option '" << argv[i] << "'" << std::endl;
|
||||
usage ();
|
||||
}
|
||||
}
|
||||
else if (grammarFile == "")
|
||||
{
|
||||
grammarFile = argv[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (commandLine != "")
|
||||
commandLine += " ";
|
||||
|
||||
commandLine += "'" + std::string (argv[i]) + "'";
|
||||
}
|
||||
}
|
||||
|
||||
// Display usage for incorrect command line.
|
||||
if (grammarFile == "")
|
||||
usage ();
|
||||
|
||||
try
|
||||
{
|
||||
File file (grammarFile);
|
||||
Grammar grammar;
|
||||
grammar.debug (debug);
|
||||
grammar.loadFromFile (file);
|
||||
|
||||
// Test commandLine against grammar.
|
||||
if (commandLine != "")
|
||||
{
|
||||
LR0 lr0;
|
||||
lr0.debug (debug);
|
||||
lr0.initialize (grammar);
|
||||
lr0.parse (commandLine);
|
||||
}
|
||||
}
|
||||
|
||||
catch (const std::string& error)
|
||||
{
|
||||
std::cout << error << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
|
@ -30,8 +30,6 @@
|
|||
#include <Rules.h>
|
||||
#include <Extensions.h>
|
||||
#include <Log.h>
|
||||
//#include <Grammar.h>
|
||||
//#include <LR0.h>
|
||||
#include <shared.h>
|
||||
#include <format.h>
|
||||
#include <FS.h>
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
# Timewarrior grammar definition.
|
||||
|
||||
# Conventions:
|
||||
# - Literals are always double-quoted.
|
||||
# - "*", "+" and "?" suffixes have POSIX semantics.
|
||||
# - "є" means empty set.
|
||||
# - Lower-level primitives are barewords.
|
||||
# - Literal modifiers:
|
||||
# - :a Accept abbreviations
|
||||
# - :i Accept caseless match
|
||||
# - Blank line between rules.
|
||||
|
||||
# Left associative:
|
||||
# A -> A <op> B
|
||||
# B
|
||||
#
|
||||
# Right associative:
|
||||
# A -> B <op> A
|
||||
# B
|
||||
|
||||
rule:
|
||||
config_rule
|
||||
exclusion_rule
|
||||
event_rule
|
||||
tag_rule
|
||||
|
||||
config_rule:
|
||||
"define" "configuration"
|
||||
|
||||
exclusion_rule:
|
||||
"define" "exclusions"
|
||||
|
||||
event_rule:
|
||||
"define" "rule"
|
||||
|
||||
tag_rule:
|
||||
"define" "tag"
|
||||
|
2
test/.gitignore
vendored
2
test/.gitignore
vendored
|
@ -3,9 +3,7 @@ all.log
|
|||
classifier.t
|
||||
composite.t
|
||||
exclusion.t
|
||||
grammar.t
|
||||
interval.t
|
||||
lexer.t
|
||||
lr0.t
|
||||
rules.t
|
||||
util.t
|
||||
|
|
|
@ -11,7 +11,7 @@ include_directories (${CMAKE_SOURCE_DIR}
|
|||
include_directories (${CMAKE_INSTALL_PREFIX}/include)
|
||||
link_directories(${CMAKE_INSTALL_PREFIX}/lib)
|
||||
|
||||
set (test_SRCS classifier.t composite.t exclusion.t grammar.t interval.t lexer.t lr0.t rules.t util.t)
|
||||
set (test_SRCS classifier.t composite.t exclusion.t interval.t lexer.t rules.t util.t)
|
||||
|
||||
add_custom_target (test ./run_all --verbose
|
||||
DEPENDS ${test_SRCS}
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <Grammar.h>
|
||||
#include <test.h>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void testBadGrammarFile (UnitTest& t, File& file)
|
||||
{
|
||||
try
|
||||
{
|
||||
Grammar g;
|
||||
g.loadFromFile (file);
|
||||
t.fail ("Grammar::loadFromFile accepted a bad file");
|
||||
}
|
||||
catch (std::string error)
|
||||
{
|
||||
t.diag (error);
|
||||
t.pass ("Grammar::loadFromFile rejected a bad file");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void testBadGrammar (UnitTest& t, const std::string& bnf)
|
||||
{
|
||||
try
|
||||
{
|
||||
Grammar g;
|
||||
g.loadFromString (bnf);
|
||||
t.fail ("Grammar::loadFromFile accepted a bad grammar");
|
||||
}
|
||||
catch (std::string error)
|
||||
{
|
||||
t.diag (error);
|
||||
t.pass ("Grammar::loadFromFile rejected a bad grammar");
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int, char**)
|
||||
{
|
||||
UnitTest t (20);
|
||||
|
||||
// Test loading from a missing file.
|
||||
File missing ("/tmp/does/not/exist");
|
||||
t.notok (missing.exists (), "Grammar file is recognized as missing");
|
||||
testBadGrammarFile (t, missing);
|
||||
|
||||
// Test error on parsing bad grammar.
|
||||
testBadGrammar (t, "");
|
||||
testBadGrammar (t, "# Comment\n"
|
||||
"# Comment\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"\n");
|
||||
|
||||
// Unreferenced rule 'two'.
|
||||
testBadGrammar (t, "one: \"foo\"\n"
|
||||
"\n"
|
||||
"two: \"bar\"\n");
|
||||
|
||||
// Undefined rule 'three'.
|
||||
testBadGrammar (t, "one: three\n"
|
||||
"\n"
|
||||
"two: \"foo\"\n");
|
||||
|
||||
// Test metadata access.
|
||||
Grammar g;
|
||||
g.loadFromString ("one: two\n"
|
||||
"\n"
|
||||
"two: three \"literal\"\n"
|
||||
" /regex/\n"
|
||||
"\n"
|
||||
"three: \"literal2\"\n");
|
||||
auto start = g.start ();
|
||||
auto rules = g.rules ();
|
||||
auto terminals = g.terminals ();
|
||||
auto augmented = g.augmented ();
|
||||
t.is (start, "one", "Located start rule");
|
||||
|
||||
t.is ((int)rules.size (), 3, "Found three rules");
|
||||
t.ok (std::find (rules.begin (), rules.end (), "one") != rules.end (), "Found rule 'one'");
|
||||
t.ok (std::find (rules.begin (), rules.end (), "two") != rules.end (), "Found rule 'two'");
|
||||
t.ok (std::find (rules.begin (), rules.end (), "three") != rules.end (), "Found rule 'three'");
|
||||
|
||||
t.ok (std::find (terminals.begin (), terminals.end (), "\"literal\"") != terminals.end (), "Found terminal '\"literal\"'");
|
||||
t.ok (std::find (terminals.begin (), terminals.end (), "/regex/") != terminals.end (), "Found terminal '/regex/'");
|
||||
t.ok (std::find (terminals.begin (), terminals.end (), "\"literal2\"") != terminals.end (), "Found terminal '\"literal2\"'");
|
||||
|
||||
t.is ((int)augmented.size (), 5, "augmented: 5 items");
|
||||
t.ok (augmented[0] == std::vector <std::string>{"S", "-->", "one"}, "augmented[0]: S --> one");
|
||||
t.ok (augmented[1] == std::vector <std::string>{"one", "-->", "two"}, "augmented[1]: one --> two");
|
||||
t.ok (augmented[2] == std::vector <std::string>{"three", "-->", "\"literal2\""}, "augmented[2]: three --> \"literal2\"");
|
||||
t.ok (augmented[3] == std::vector <std::string>{"two", "-->", "three", "\"literal\""}, "augmented[3]: two --> three \"literal\"");
|
||||
t.ok (augmented[4] == std::vector <std::string>{"two", "-->", "/regex/"}, "augmented[4]: two --> /regex/");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2015 - 2016, Paul Beckingham, Federico Hernandez.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included
|
||||
// in all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
//
|
||||
// http://www.opensource.org/licenses/mit-license.php
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <cmake.h>
|
||||
#include <LR0.h>
|
||||
#include <test.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
int main (int, char**)
|
||||
{
|
||||
UnitTest t (21);
|
||||
|
||||
// LR0::Item.
|
||||
LR0::Item item1 ({"E", "-->", "E", "*", "B"});
|
||||
t.is (item1.dump (), "E --> ● E * B", "E --> ● E * B");
|
||||
|
||||
t.ok (item1.advance (), "Item::advance true");
|
||||
t.is (item1.dump (), "E --> E ● * B", "E --> E ● * B");
|
||||
|
||||
t.ok (item1.advance (), "Item::advance true");
|
||||
t.is (item1.dump (), "E --> E * ● B", "E --> E * ● B");
|
||||
|
||||
t.notok (item1.done (), "Item::done false");
|
||||
t.ok (item1.advance (), "Item::advance true");
|
||||
t.ok (item1.done (), "Item::done true");
|
||||
t.is (item1.dump (), "E --> E * B ●", "E --> E * B ●");
|
||||
|
||||
t.notok (item1.advance (), "Item::advance false");
|
||||
|
||||
// LR0::Item special case for "A --> є".
|
||||
LR0::Item item2 ({"A", "-->", "є"});
|
||||
t.is (item2.dump (), "A --> ●", "A --> ●");
|
||||
t.notok (item2.advance (), "Item::advance false");
|
||||
t.ok (item2.done (), "Item::done true");
|
||||
|
||||
LR0::Item item3 ({"E", "-->", "E", "*", "B"});
|
||||
t.is (item3.next (), "E", "Item::next E");
|
||||
t.ok (item3.advance (), "Item::advance true");
|
||||
t.is (item3.next (), "*", "Item::next *");
|
||||
t.ok (item3.advance (), "Item::advance true");
|
||||
t.is (item3.next (), "B", "Item::next B");
|
||||
t.ok (item3.advance (), "Item::advance true");
|
||||
t.notok (item3.advance (), "Item::advance false");
|
||||
t.ok (item3.done (), "Item::done true");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
Loading…
Add table
Add a link
Reference in a new issue