996
|
1 // main.cpp
|
|
2
|
|
3 #include "lib.h"
|
|
4 #include "Thread.h"
|
|
5 #include "Board.h"
|
|
6 #include "interactive.h"
|
|
7
|
|
8 using namespace std;
|
|
9
|
|
10 void parseAllArguments(int argc, char * argv[]);
|
|
11 void parseArgument(string const & arg);
|
|
12 bool hasPrefix(string const & subject, string const & prefix);
|
|
13 void parseInput(map<string, Board> & globals);
|
|
14 void parseFile(ifstream & file, map<string, Board> & globals);
|
|
15 void parseField(ifstream & file, list<string> & field, string & line);
|
|
16 string parseHeader(string const & line);
|
|
17
|
|
18 int main(int argc, char * argv[])
|
|
19 {
|
|
20 int result = 0;
|
|
21 try
|
|
22 {
|
|
23 parseAllArguments(argc, argv);
|
|
24 map<string, Board> globals;
|
|
25 parseInput(globals);
|
|
26
|
|
27 Thread program;
|
|
28 map<string, Board>::iterator mainPos = globals.find("main");
|
|
29 if (mainPos != globals.end())
|
|
30 {
|
|
31 program.reset(mainPos->second, &globals);
|
|
32 }
|
|
33 else
|
|
34 {
|
|
35 throw InternalException("Crash: No 'main' function found");
|
|
36 }
|
|
37 if (args::isBatch)
|
|
38 {
|
|
39 program.go();
|
|
40 }
|
|
41 else
|
|
42 {
|
|
43 runInteractive(program);
|
|
44 }
|
|
45 }
|
|
46 catch(ArgumentException & error)
|
|
47 {
|
|
48 cerr << "Argument Error: " << error.what() << endl;
|
|
49 cerr << "Usage: " << argv[0] << " [--batch] [--interactive] " << endl
|
|
50 << " [--input=<file>] [--output=<file>] <sourcefile> " << endl
|
|
51 << " [<sourcefile> [...]]" << endl << endl;
|
|
52
|
|
53 cerr << "--batch Runs in batch mode. The interpreted program will run" << endl
|
|
54 << " silently to completion." << endl;
|
|
55
|
|
56 cerr << "--interactive Runs in interactive mode. A step by step readout of the" << endl
|
|
57 << " interpreted program is displayed with debugging controls." << endl
|
|
58 << " If the run is interactive, then input and output must both"
|
|
59 << " be bound to files." << endl;
|
|
60
|
|
61 cerr << "--input=<file> Sets standard input of the interpreted program to <file>." << endl
|
|
62 << " Default is the outer program's standard input." << endl;
|
|
63
|
|
64 cerr << "--ouput=<file> Sets standard output of the interpreted program to <file>" << endl
|
|
65 << " Default is the outer program's standard output." << endl;
|
|
66
|
|
67 result = 2;
|
|
68 }
|
|
69 catch(std::exception & error)
|
|
70 {
|
|
71 cerr << "Internal Error: " << error.what() << endl;
|
|
72 result = 1;
|
|
73 }
|
|
74 return result;
|
|
75 }
|
|
76
|
|
77 void parseAllArguments(int argc, char * argv[])
|
|
78 {
|
|
79 for (int i = 1; i < argc; ++i)
|
|
80 {
|
|
81 parseArgument(argv[i]);
|
|
82 }
|
|
83 if (!(args::isBatch) && (args::output == NULL || args::input == NULL))
|
|
84 {
|
|
85 throw ArgumentException("If the run is interactive, then input and output must both be bound to files.");
|
|
86 }
|
|
87 else if (args::sourceFiles.empty())
|
|
88 {
|
|
89 throw ArgumentException("No source files to interpret.");
|
|
90 }
|
|
91
|
|
92 if (args::output == NULL)
|
|
93 {
|
|
94 args::output = &cout;
|
|
95 }
|
|
96 if (args::input == NULL)
|
|
97 {
|
|
98 args::input = &cin;
|
|
99 }
|
|
100 }
|
|
101
|
|
102 void parseArgument(string const & arg)
|
|
103 {
|
|
104 static const string batchFlag = "--batch";
|
|
105 static const string interactiveFlag = "--interactive";
|
|
106 static const string inputPrefix = "--input=";
|
|
107 static const string outputPrefix = "--output=";
|
|
108
|
|
109 static ifstream input;
|
|
110 static ofstream output;
|
|
111 if (arg == batchFlag)
|
|
112 {
|
|
113 args::isBatch = true;
|
|
114 }
|
|
115 else if (arg == interactiveFlag)
|
|
116 {
|
|
117 args::isBatch = false;
|
|
118 }
|
|
119 else if (hasPrefix(arg, inputPrefix))
|
|
120 {
|
|
121 if (args::input == NULL)
|
|
122 {
|
|
123 input.open(arg.substr(inputPrefix.size()).c_str(), ios::in);
|
|
124 if (!input)
|
|
125 {
|
|
126 throw ArgumentException("Failed to open '--input' file: "
|
|
127 + arg.substr(inputPrefix.size()));
|
|
128 }
|
|
129 args::input = &input;
|
|
130 }
|
|
131 else
|
|
132 {
|
|
133 throw ArgumentException("Only one '--input' file is allowed: " + arg);
|
|
134 }
|
|
135 }
|
|
136 else if (hasPrefix(arg, outputPrefix))
|
|
137 {
|
|
138 if (args::output == NULL)
|
|
139 {
|
|
140 output.open(arg.substr(outputPrefix.size()).c_str(),
|
|
141 ios::out | ios::trunc);
|
|
142 if (!output)
|
|
143 {
|
|
144 throw ArgumentException("Failed to open '--output' file: "
|
|
145 + arg.substr(outputPrefix.size()));
|
|
146 }
|
|
147 args::output = &output;
|
|
148 }
|
|
149 else
|
|
150 {
|
|
151 throw ArgumentException("Only one '--output' file is allowed: " + arg);
|
|
152 }
|
|
153 }
|
|
154 else
|
|
155 {
|
|
156 // This must be a source filename.
|
|
157 args::sourceFiles.push_back(arg);
|
|
158 }
|
|
159 }
|
|
160
|
|
161 bool hasPrefix(string const & subject, string const & prefix)
|
|
162 {
|
|
163 return subject.compare(0, prefix.size(), prefix) == 0;
|
|
164 }
|
|
165
|
|
166 void parseInput(map<string, Board> & globals)
|
|
167 {
|
|
168 list<string>::iterator pos = args::sourceFiles.begin();
|
|
169 list<string>::iterator limit = args::sourceFiles.end();
|
|
170 for (; pos != limit; ++pos)
|
|
171 {
|
|
172 ifstream source(pos->c_str(), ios::in);
|
|
173 if (!source)
|
|
174 {
|
|
175 throw ArgumentException("Failed to open source file: " + *pos);
|
|
176 }
|
|
177 parseFile(source, globals);
|
|
178 }
|
|
179 }
|
|
180
|
|
181 void parseFile(ifstream & file, map<string, Board> & globals)
|
|
182 {
|
|
183 list<string> field;
|
|
184 string line;
|
|
185 string name;
|
|
186 parseField(file, field, line);
|
|
187 while (file)
|
|
188 {
|
|
189 field.clear();
|
|
190 field.push_back(line);
|
|
191 name = parseHeader(line);
|
|
192 parseField(file, field, line);
|
|
193 if (name != "")
|
|
194 {
|
|
195 globals[name].reset(name, field);
|
|
196 }
|
|
197 }
|
|
198 }
|
|
199
|
|
200 void parseField(ifstream & file, list<string> & field, string & line)
|
|
201 {
|
|
202 getline(file, line);
|
|
203 while (file && line[0] != '$')
|
|
204 {
|
|
205 field.push_back(line);
|
|
206 getline(file, line);
|
|
207 }
|
|
208 }
|
|
209
|
|
210 string parseHeader(string const & line)
|
|
211 {
|
|
212 string result;
|
|
213 size_t first = line.find('\'');
|
|
214 if (first != string::npos)
|
|
215 {
|
|
216 size_t second = line.find('\'', first + 1);
|
|
217 if (second != string::npos)
|
|
218 {
|
|
219 result = line.substr(first + 1, second - (first + 1));
|
|
220 }
|
|
221 }
|
|
222 return result;
|
|
223 }
|