Skip to content

Commit

Permalink
use of boost program options and static compilation
Browse files Browse the repository at this point in the history
  • Loading branch information
jose-rZM committed Feb 3, 2025
1 parent 04aeebf commit d91c807
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 110 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
CXX = clang++
CXXFLAGS = -std=c++20 -O -Wall -Wextra -Wpedantic -Wshadow -Wold-style-cast -Wunused -Wcast-align -Wnull-dereference -Wconversion -fstrict-aliasing -fsanitize=address -fsanitize=undefined -fsanitize=leak
CXXFLAGS = -std=c++20 -O3
SRC_DIR = src
HPP_DIR = include
OBJ_DIR = out

all: program

program: $(OBJ_DIR)/main.o $(OBJ_DIR)/ll1_parser.o $(OBJ_DIR)/symbol_table.o $(OBJ_DIR)/lexer.o $(OBJ_DIR)/grammar.o
$(CXX) $(CXXFLAGS) -o ll1 $^
$(CXX) $(CXXFLAGS) -o ll1 $^ /usr/lib/libboost_regex.a /usr/lib/libboost_program_options.a

$(OBJ_DIR)/main.o: $(SRC_DIR)/main.cpp $(HPP_DIR)/grammar.hpp $(OBJ_DIR)/ll1_parser.o
$(CXX) $(CXXFLAGS) -c $< -o $@
Expand Down
16 changes: 9 additions & 7 deletions include/ll1_parser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,24 @@ class LL1Parser {
* @param gr Grammar object to parse with.
* @param text_file Name of the file containing input to parse.
*/
LL1Parser(Grammar gr, std::string text_file);
LL1Parser(Grammar gr, std::string text_file, bool table_format = true);

/**
* @brief Constructs an LL1Parser with a grammar file and an input file.
*
* @param grammar_file Path to the grammar file.
* @param text_file Name of the file containing input to parse.
*/
LL1Parser(const std::string& grammar_file, std::string text_file);
LL1Parser(const std::string& grammar_file, std::string text_file,
bool table_format = true);

/**
* @brief Constructs an LL1Parser with a grammar file.
*
* @param grammar_file Path to the grammar file.
*/
explicit LL1Parser(const std::string& grammar_file);
explicit LL1Parser(const std::string& grammar_file,
bool table_format = true);

/**
* @brief Parses an input string or file using the LL(1) parsing algorithm.
Expand Down Expand Up @@ -70,11 +72,8 @@ class LL1Parser {
* @brief Print the LL(1) parsing table to standard output.
*
* Displays the LL(1) table for debugging and analysis.
* @param old Set to true to use the old format when printing the table.
* The old format is ideal when the grammar is large and does not fit well into
* the table generated.
*/
void PrintTable(bool old);
void PrintTable();

/**
* @brief Prints the remaining symbols in the parsing stack after the
Expand Down Expand Up @@ -259,4 +258,7 @@ class LL1Parser {

/// @brief Path to the input text file to be parsed.
std::string text_file_;

/// @brief True if new format is used when printing the table
bool print_table_format_{true};
};
15 changes: 8 additions & 7 deletions include/tabulate.hpp
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -892,8 +892,8 @@ union max_align_t {
struct Unknown;

Unknown (*variant_UNIQUE(_))(Unknown);
Unknown* Unknown::*variant_UNIQUE(_);
Unknown (Unknown::*variant_UNIQUE(_))(Unknown);
Unknown* Unknown::* variant_UNIQUE(_);
Unknown (Unknown::* variant_UNIQUE(_))(Unknown);

struct_t<Unknown (*)(Unknown)> variant_UNIQUE(_);
struct_t<Unknown * Unknown::*> variant_UNIQUE(_);
Expand Down Expand Up @@ -3164,7 +3164,8 @@ using std::swap;
#define optional_is_default = default;
#else
#define optional_is_default \
{}
{ \
}
#endif

#if optional_HAVE(CONSTEXPR_14)
Expand Down Expand Up @@ -3316,8 +3317,8 @@ struct is_nothrow_swappable {
}

template <typename T>
static auto
test(int /*unused*/) -> std::integral_constant<bool, satisfies<T>()> {}
static auto test(int /*unused*/)
-> std::integral_constant<bool, satisfies<T>()> {}

template <typename> static auto test(...) -> std::false_type;
};
Expand Down Expand Up @@ -3406,8 +3407,8 @@ union max_align_t {
struct Unknown;

Unknown (*optional_UNIQUE(_))(Unknown);
Unknown* Unknown::*optional_UNIQUE(_);
Unknown (Unknown::*optional_UNIQUE(_))(Unknown);
Unknown* Unknown::* optional_UNIQUE(_);
Unknown (Unknown::* optional_UNIQUE(_))(Unknown);

struct_t<Unknown (*)(Unknown)> optional_UNIQUE(_);
struct_t<Unknown * Unknown::*> optional_UNIQUE(_);
Expand Down
33 changes: 19 additions & 14 deletions src/ll1_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,32 @@
#include "../include/symbol_table.hpp"
#include "../include/tabulate.hpp"

LL1Parser::LL1Parser(Grammar gr, std::string text_file)
: gr_(std::move(gr)), text_file_(std::move(text_file)) {
LL1Parser::LL1Parser(Grammar gr, std::string text_file, bool table_format)
: gr_(std::move(gr)), text_file_(std::move(text_file)),
print_table_format_(table_format) {
if (!CreateLL1Table()) {
gr_.Debug();
PrintTable(true);
PrintTable();
throw GrammarError("Grammar provided is not LL1.");
}
}

LL1Parser::LL1Parser(const std::string& grammar_file, std::string text_file)
: gr_(grammar_file), text_file_(std::move(text_file)) {
LL1Parser::LL1Parser(const std::string& grammar_file, std::string text_file,
bool table_format)
: gr_(grammar_file), text_file_(std::move(text_file)),
print_table_format_(table_format) {
if (!CreateLL1Table()) {
gr_.Debug();
PrintTable(true);
PrintTable();
throw GrammarError("Grammar provided is not LL1.");
}
}

LL1Parser::LL1Parser(const std::string& grammar_file) : gr_(grammar_file) {
LL1Parser::LL1Parser(const std::string& grammar_file, bool table_format)
: gr_(grammar_file), print_table_format_(table_format) {
if (!CreateLL1Table()) {
gr_.Debug();
PrintTable(true);
PrintTable();
throw GrammarError("Grammar provided is not LL1.");
}
}
Expand Down Expand Up @@ -198,8 +202,8 @@ LL1Parser::PredictionSymbols(const std::string& antecedent,
return hd;
}

void LL1Parser::PrintTable(bool old = false) {
if (old) {
void LL1Parser::PrintTable() {
if (print_table_format_) {
PrintTableUsingTabulate();
return;
}
Expand Down Expand Up @@ -243,7 +247,10 @@ void LL1Parser::PrintTableUsingTabulate() {
}

auto& header_row = table.add_row(headers);
header_row.format().font_align(FontAlign::center).font_color(Color::yellow).font_style({FontStyle::bold});
header_row.format()
.font_align(FontAlign::center)
.font_color(Color::yellow)
.font_style({FontStyle::bold});

for (const auto& outerPair : ll1_t_) {
const std::string& nonTerminal = outerPair.first;
Expand Down Expand Up @@ -276,9 +283,7 @@ void LL1Parser::PrintTableUsingTabulate() {
}
}
}
table.format()
.font_align({FontAlign::center})
;
table.format().font_align({FontAlign::center});
table.column(0).format().font_color(Color::cyan);
std::cout << table << std::endl;
}
Expand Down
152 changes: 72 additions & 80 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#ifndef _WIN32
#include <getopt.h>
#endif
#include <boost/program_options.hpp>
#include <fstream>
#include <iostream>
#include <ostream>
#include <string>

#include "../include/ll1_parser.hpp"
namespace po = boost::program_options;

int PrintFileToStdout(const std::string& filename) {
std::ifstream file(filename);
Expand All @@ -20,119 +22,109 @@ int PrintFileToStdout(const std::string& filename) {
return 0;
}

void ShowUsage(const char* program_name) {
void ShowUsage(const char* program_name, const po::options_description& desc) {
std::cout << "Usage: " << program_name
<< " <grammar_filename> [<text_filename>] [-v] [-h]\n";
std::cout << "Options:\n";
std::cout << " -h Show this help message\n";
std::cout << " -v Enable verbose mode: print ll1 table, input "
"file and parser stack trace\n";
std::cout << " <grammar_filename> Path to the grammar file\n";
std::cout << " <text_filename> Path to the text file to be parsed "
"(optional)\n";
<< " <grammar_filename> [<text_filename>] [options]\n"
<< desc;
}

int main(int argc, char* argv[]) {
std::string grammar_filename, text_filename;
bool verbose_mode = false;
std::string table_format = "new";

#ifndef _WIN32
int opt;
while ((opt = getopt(argc, argv, "hv")) != -1) {
switch (opt) {
case 'h':
ShowUsage(argv[0]);
return 0;
case 'v':
verbose_mode = true;
break;
default:
std::cerr
<< "ll1: Invalid option. Use 'll1 -h' for usage information.\n";
return 1;
}
}
// Configure command line options
po::options_description desc("Options");
desc.add_options()("help,h", "Show help message")(
"verbose,v", po::bool_switch(&verbose_mode),
"Enable verbose mode with new table format")(
"format", po::value<std::string>(),
"Set table format (old/new), implies verbose mode")(
"grammar", po::value<std::string>(&grammar_filename)->required(),
"Grammar file")("text", po::value<std::string>(&text_filename),
"Text file to parse");

if (argc - optind < 1 || argc - optind > 2) {
std::cerr << "ll1: Incorrect number of arguments. Use 'll1 -h' for "
"usage information.\n";
return 1;
}
po::positional_options_description pos;
pos.add("grammar", 1);
pos.add("text", 1);

grammar_filename = argv[optind];
if (optind + 1 < argc) {
text_filename = argv[optind + 1];
}
#else
if (argc < 2) {
show_usage(argv[0]);
return 1;
}
try {
po::variables_map vm;
po::store(po::command_line_parser(argc, argv)
.options(desc)
.positional(pos)
.run(),
vm);

for (int i = 1; i < argc; ++i) {
std::string arg = argv[i];
if (arg == "-h") {
show_usage(argv[0]);
if (vm.count("help")) {
ShowUsage(argv[0], desc);
return 0;
} else if (arg == "-v") {
}

po::notify(vm);
if (vm.count("format")) {
verbose_mode = true;
} else if (grammar_filename.empty()) {
grammar_filename = arg;
} else {
text_filename = arg;
table_format = vm["format"].as<std::string>();
if (table_format != "old" && table_format != "new") {
throw std::runtime_error(
"Invalid format - must be 'old' or 'new'");
}
} else if (vm.count("verbose")) {
if (table_format.empty())
table_format = "new";
}

} catch (const std::exception& e) {
std::cerr << "Error: " << e.what() << "\n\n";
ShowUsage(argv[0], desc);
return 1;
}
#endif
std::ifstream grammar_file_check(grammar_filename);
if (!grammar_file_check) {
std::cerr << "ll1: Grammar file '" << grammar_filename
<< "' does not exist or cannot be opened.\n";
if (!std::ifstream(grammar_filename)) {
std::cerr << "Error: Grammar file '" << grammar_filename
<< "' not found\n";
return 1;
}

try {
LL1Parser ll1_p{grammar_filename, text_filename};
LL1Parser parser{grammar_filename, text_filename,
table_format == "new"};
std::cout << "Grammar is LL(1)\n";

if (verbose_mode) {
std::cout << "-----------------------------------------------\n";
std::cout << "LL1 Table (Verbose Mode):\n";
ll1_p.PrintTable(true);
std::cout << "-----------------------------------------------\n";
std::cout << "\n--------------------------------\n"
<< "LL1 Table (" << table_format << " format):\n";
parser.PrintTable();

if (!text_filename.empty()) {
std::cout << "Input (Verbose Mode):\n";
std::cout << "\n--------------------------------\n"
<< "Input content:\n";
if (PrintFileToStdout(text_filename)) {
std::cerr << "Error: File does not exist.\n";
return 1;
throw std::runtime_error("Text file not found");
}
std::cout
<< "-----------------------------------------------\n";
}
std::cout << "--------------------------------\n\n";
}

if (!text_filename.empty()) {
std::ifstream file(text_filename);
if (!file) {
std::cerr << "ll1: File does not exist.\n";
return 1;
}
if (file.peek() == std::ifstream::traits_type::eof()) {
std::cerr << "ll1: File is empty.\n";
return 1;
}
if (ll1_p.Parse()) {
std::cout << "Parsing was successful.\n";
if (verbose_mode) {
ll1_p.PrintStackTrace();
}
if (!file)
throw std::runtime_error("Text file not found");
if (file.peek() == EOF)
throw std::runtime_error("Text file is empty");

if (parser.Parse()) {
std::cout << "Parsing successful\n";
if (verbose_mode)
parser.PrintStackTrace();
} else {
std::cerr << "Parsing encountered an error.\n";
ll1_p.PrintStackTrace();
ll1_p.PrintSymbolHist();
std::cerr << "Parsing failed\n";
parser.PrintStackTrace();
parser.PrintSymbolHist();
return 1;
}
}
} catch (const std::exception& e) {
std::cerr << "ll1: " << e.what() << "\n";
std::cerr << "Error: " << e.what() << "\n";
return 1;
}

Expand Down

0 comments on commit d91c807

Please sign in to comment.