-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvotes.y
204 lines (166 loc) · 5.07 KB
/
votes.y
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
%define api.prefix {v}
%parse-param {const char* filename}
%parse-param {std::vector<panachage::Vote*>* votes}
%parse-param {std::vector<panachage::partylist*> lists}
%parse-param {bool create_new_lists}
%{
#include <vector>
#include "yacc_tools.h"
#include "candidate.hpp"
#include "full_list.cpp"
#include "partial_list.cpp"
#include "free_list.cpp"
using panachage::partylist;
using panachage::Vote;
using panachage::candidate;
extern int vlex();
typedef std::vector<Vote *> *yy_votes_param;
typedef std::vector<partylist *> yy_lists_param;
inline void verror(const char *filename, yy_votes_param votes, yy_lists_param lists, bool create_new_lists, char const *s)
{
yacc_error(filename, s, "vote", yyin, yylineno, yycolumn, yyleng, yytext);
}
partylist *yy_listById(yy_lists_param &lists, partylist::id_type id, bool create_new_lists)
{
partylist *plist = nullptr;
for (partylist *i : lists)
{
if (i->id == id)
{
plist = i;
break;
}
}
if (!plist && create_new_lists)
{
plist = new partylist(id, std::to_string(id));
lists.push_back(plist);
return plist;
}
return plist;
}
void catch_bad_list_id(const char *filename, yy_votes_param votes, yy_lists_param lists, partylist::id_type id)
{
std::string s = "no list of id: ";
s += std::to_string(id);
verror(filename, votes, lists, false, s.c_str());
}
inline void yy_lst_init(candidate::id_type *cand_list, int id)
{
*cand_list = id;
}
inline void yy_lst_append(candidate::id_type *cand_list, int id)
{
// ew.
for (int i = 0; i < YY_MAX_CANDS; i++)
{
if (!cand_list[i])
{
cand_list[i] = id;
break;
}
}
}
void make_new_copied_vote(yy_votes_param votes, Vote *v, int copies)
{
v->setCopies(copies);
v->setLnParsed(yylineno);
votes->push_back(v);
}
inline void make_new_vote(yy_votes_param votes, Vote *v)
{
v->setLnParsed(yylineno);
votes->push_back(v);
}
%}
%code requires {
#include "vote.hpp"
#include "partylist.cpp"
#include "lex_utils.h"
namespace panachage {
std::vector<Vote *> *parseVoteFile(const char *filename, std::vector<Vote *> *votes, std::vector<partylist *> lists, bool create_new_lists = false);
void parseSingleVote(const char *input, std::vector<partylist *> lists);
}
}
%define parse.error verbose
%union {
int i;
panachage::Vote* v;
panachage::candidate::id_type cl[YY_MAX_CANDS];
panachage::partylist* pl;
}
%token full 102 // f
%token partial 112 // p
%token blank 98 // b
%token star 42 // *
%token sep 124 // |
%token numsep 44 // ,
%token <i> vnumber
%type <pl> partylist
%type <v> vote
%type <cl> numbers
%start start
%%
start : parcel
| start parcel
;
parcel : vnumber star vote { make_new_copied_vote(votes, $3, $1); }
| vote { make_new_vote(votes, $1); }
;
vote : full sep partylist { $$ = new panachage::FullListVote($3); }
| partial sep partylist sep numbers { $$ = new panachage::PartialListVote($3, $5); }
| partial sep partylist sep numbers sep numbers { $$ = new panachage::PartialListVote($3, $5, $7); }
| blank sep numbers { $$ = new panachage::FreeVote($3); }
;
partylist : vnumber { $$ = yy_listById(lists, $1, create_new_lists);
if (!$$) catch_bad_list_id(filename, votes, lists, $1);
}
;
numbers : vnumber { yy_lst_init($$, $1); }
| numbers numsep vnumber { yy_lst_append($$, $3); }
;
%%
namespace panachage {
void displayAllCandidates(std::vector<partylist *> lists);
std::vector<Vote *> *parseVoteFile(const char *filename, std::vector<Vote *> *votes, std::vector<partylist *> lists, bool create_new_lists)
{
RESET_BUFFER;
yyin = fopen(filename, "r");
if (!yy_doesFileExist(filename, yyin))
return votes;
vparse(filename, votes, lists, create_new_lists);
fclose(yyin);
return votes;
}
void parseSingleVote(const char *input, std::vector<partylist *> lists)
{
std::vector<Vote *> votes;
const char *temp_filename = "tempparsedoc.txt";
yyin = fopen(temp_filename, "w");
fputs(input, yyin);
fclose(yyin);
parseVoteFile(temp_filename, &votes, lists);
if (votes.size() == 0)
{
std::cout << "No (valid) votes could be parsed." << std::endl;
}
else if (votes.size() == 1)
{
Vote *vote = votes.front();
if (vote->validate())
{
vote->count(lists);
displayAllCandidates(lists);
}
else
{
std::cout << "That vote is invalid." << std::endl;
}
}
else
{
std::cout << "Try parsing again with only one vote." << std::endl;
}
remove(temp_filename);
}
}