Cleanup: Removed unused files

This commit is contained in:
Paul Beckingham 2016-04-03 13:02:52 -04:00
parent b41b56c00c
commit 68ba48e85f
14 changed files with 2 additions and 1335 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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

View file

@ -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 ();
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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

View file

@ -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

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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>

View file

@ -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
View file

@ -3,9 +3,7 @@ all.log
classifier.t
composite.t
exclusion.t
grammar.t
interval.t
lexer.t
lr0.t
rules.t
util.t

View file

@ -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}

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////

View file

@ -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;
}
////////////////////////////////////////////////////////////////////////////////