-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmain.cpp
121 lines (113 loc) · 4.14 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// LICENSE
// This software is free for use and redistribution while including this
// license notice, unless:
// 1. is used for commercial or non-personal purposes, or
// 2. used for a product which includes or associated with a blockchain or other
// decentralized database technology, or
// 3. used for a product which includes or associated with the issuance or use
// of cryptographic or electronic currencies/coins/tokens.
// On all of the mentioned cases, an explicit and written permission is required
// from the Author (Ohad Asor).
// Contact [email protected] for requesting a permission. This license may be
// modified over time by the Author.
// CSV parser tutorial - part 10
//
// In this part we use a tgf tool to generate a parser from a TGF file.
//
// This is usefull when you want to avoid parsing TGF to read your grammar every
// time you start your program. tgf tool converts TGF to a programatically
// created grammar and wraps it into a parser struct.
//
// We have moved the TGF grammar from previous part into a separate csv.tgf file
//
// Now we can run the tgf tool with "csv.tgf" filename as a first argument,
// a command "gen" as a second argument and we can use the --name option with
// argument "csv_parser" to name the struct.
// And we redirect the output to a desired header file:
//
// tgf csv.tgf gen --name csv_parser > csv_parser.generated.h
//
// Generated parser has a similar API as library's parser struct.
// Additionally it provides size_t id(const basic_string<C>&) method to get id
// of a nonterminal.
#include <optional>
#include <limits>
// include the generated header file instead of using the generic parser
#include "csv_parser.generated.h"
#ifdef min
# undef min
#endif
#ifdef max
# undef max
#endif
using namespace std;
using namespace idni;
// Renamed csv_parser to csv_reader. csv_reader now uses csv_parser to parse
// input and it takes care of the traversal and extraction of values.
struct csv_reader {
typedef variant<bool, int_t, string> value;
typedef vector<value> row;
typedef vector<row> rows;
// use csv_parser from the header file with a generated parser
csv_parser p;
// get_rows now takes the string input and returns errors as refs
optional<rows> get_rows(const string& input) {
auto res = p.parse(input.c_str(), input.size());
if (!res.found) {
cerr << res.parse_error << '\n';
return {};
}
rows r;
auto get_int = [&res](const auto& n) -> value {
auto i = res.get_terminals_to_int(n);
if (!i) return cerr
<< "out of range, allowed range is from: "
<< numeric_limits<int_t>::min() << " to: "
<< numeric_limits<int_t>::max() << '\n', false;
return i.value();
};
auto cb_enter = [&r, &get_int, &res, this](const auto& n) {
if (!n->first.nt()) return;
// generated csv_parser contains enum containing all
// nonterminals from the grammar with their id values.
// These can be used to compare with result of call
// to literal's method n()
auto id = n->first.n();
if (id == csv_parser::row) r.emplace_back();
else if (id == csv_parser::integer)
r.back().push_back(get_int(n));
else if (id == csv_parser::str)
r.back().push_back(res.get_terminals(n));
else if (id == csv_parser::nullvalue)
r.back().push_back(true);
};
res.get_forest()->traverse(cb_enter);
return r;
}
};
ostream& operator<<(ostream& os, const csv_reader::value& v) {
if (holds_alternative<int_t>(v)) os << get<int_t>(v);
else if (holds_alternative<bool>(v)) os << "NULL";
else os << get<string>(v);
return os;
}
int main() {
cout << "CSV parser. Use comma separated values of string, "
<< "integer or NULL. Use a new line to separate rows. "
<< "Enter a CSV and use Ctrl-D to start parsing\n";
// use csv_reader
csv_reader csv;
istreambuf_iterator<char> begin(cin), end;
string input(begin, end);
cout << "entered: `" << input << "`\n";
// call csv_reader's get_rows to parse the input and get rows w/ values
optional<csv_reader::rows> rsopt = csv.get_rows(input);
if (!rsopt) return 1;
for (const csv_reader::row& r : rsopt.value()) {
cout << "parsed row: ";
for (size_t i = 0; i != r.size(); ++i)
cout << (i ? ", " : "") << r[i];
cout << '\n';
}
return 0;
}