src/main.cxx

changeset 73
1ee9b312dc18
parent 72
03e4d9db3fd9
equal deleted inserted replaced
72:03e4d9db3fd9 73:1ee9b312dc18
1 /* 1 /*
2 * botc source code 2 Copyright (c) 2013-2014, Santeri Piippo
3 * Copyright (C) 2012 Santeri `Dusk` Piippo 3 All rights reserved.
4 * All rights reserved. 4
5 * 5 Redistribution and use in source and binary forms, with or without
6 * Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are met:
7 * modification, are permitted provided that the following conditions are met: 7
8 * 8 * Redistributions of source code must retain the above copyright
9 * 1. Redistributions of source code must retain the above copyright notice, 9 notice, this list of conditions and the following disclaimer.
10 * this list of conditions and the following disclaimer. 10
11 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * Redistributions in binary form must reproduce the above copyright
12 * this list of conditions and the following disclaimer in the documentation 12 notice, this list of conditions and the following disclaimer in the
13 * and/or other materials provided with the distribution. 13 documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the developer nor the names of its contributors may 14
15 * be used to endorse or promote products derived from this software without 15 * Neither the name of the <organization> nor the
16 * specific prior written permission. 16 names of its contributors may be used to endorse or promote products
17 * 4. Redistributions in any form must be accompanied by information on how to 17 derived from this software without specific prior written permission.
18 * obtain complete source code for the software and any accompanying 18
19 * software that uses the software. The source code must either be included 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * in the distribution or be available for no more than the cost of 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * distribution plus a nominal fee, and must be freely redistributable 21 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * under reasonable conditions. For an executable file, complete source 22 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
23 * code means the source code for all modules it contains. It does not 23 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * include source code for modules or files that typically accompany the 24 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * major components of the operating system on which the executable file 25 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * runs. 26 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * 27 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 */
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include "main.h" 31 #include "main.h"
46
47 #include "str.h"
48 #include "scriptreader.h" 32 #include "scriptreader.h"
49 #include "objwriter.h" 33 #include "object_writer.h"
50 #include "events.h" 34 #include "events.h"
51 #include "commands.h" 35 #include "commands.h"
52 #include "stringtable.h" 36 #include "stringtable.h"
53 #include "variables.h" 37 #include "variables.h"
54 #include "containers.h" 38 #include "containers.h"
55 #include "databuffer.h" 39 #include "data_buffer.h"
56
57 #include "bots.h" 40 #include "bots.h"
58 #include "botcommands.h" 41 #include "object_writer.h"
42 #include "parser.h"
59 43
60 // List of keywords 44 // List of keywords
61 const string_list g_Keywords = { 45 const string_list g_Keywords =
46 {
62 "bool", 47 "bool",
63 "break", 48 "break",
64 "case", 49 "case",
65 "continue", 50 "continue",
66 "const", 51 "const",
78 "state", 63 "state",
79 "switch", 64 "switch",
80 "str" 65 "str"
81 "void", 66 "void",
82 "while", 67 "while",
83 68
84 // These ones aren't implemented yet but I plan to do so, thus they are 69 // These ones aren't implemented yet but I plan to do so, thus they are
85 // reserved. Also serves as a to-do list of sorts for me. >:F 70 // reserved. Also serves as a to-do list of sorts for me. >:F
86 "enum", // Would enum actually be useful? I think so. 71 "enum", // Would enum actually be useful? I think so.
87 "func", // Would function support need external support from zandronum? 72 "func", // Would function support need external support from zandronum?
88 "return", 73 "return",
89 }; 74 };
90 75
91 // databuffer global variable 76 // databuffer global variable
92 int g_NextMark = 0; 77 int g_NextMark = 0;
93 78
94 int main (int argc, char** argv) { 79 int main (int argc, char** argv)
80 {
95 // Intepret command-line parameters: 81 // Intepret command-line parameters:
96 // -l: list commands 82 // -l: list commands
97 // I guess there should be a better way to do this. 83 // I guess there should be a better way to do this.
98 if (argc == 2 && !strcmp (argv[1], "-l")) { 84 if (argc == 2 && !strcmp (argv[1], "-l"))
99 ReadCommands (); 85 {
86 ReadCommands();
100 printf ("Begin list of commands:\n"); 87 printf ("Begin list of commands:\n");
101 printf ("------------------------------------------------------\n"); 88 printf ("------------------------------------------------------\n");
102 89
103 CommandDef* comm; 90 CommandDef* comm;
104 ITERATE_COMMANDS (comm) 91 ITERATE_COMMANDS (comm)
105 print ("%1\n", GetCommandPrototype (comm)); 92 print ("%1\n", GetCommandPrototype (comm));
106 93
107 printf ("------------------------------------------------------\n"); 94 printf ("------------------------------------------------------\n");
108 printf ("End of command list\n"); 95 printf ("End of command list\n");
109 exit (0); 96 exit (0);
110 } 97 }
111 98
112 // Print header 99 // Print header
113 string header; 100 string header;
114 string headerline; 101 string headerline;
115 header = format ("%1 version %2.%3", APPNAME, VERSION_MAJOR, VERSION_MINOR); 102 header = format ("%1 version %2.%3", APPNAME, VERSION_MAJOR, VERSION_MINOR);
116 103
117 for (int i = 0; i < (header.len() / 2) - 1; ++i) 104 for (int i = 0; i < (header.len() / 2) - 1; ++i)
118 headerline += "-="; 105 headerline += "-=";
119 106
120 headerline += '-'; 107 headerline += '-';
121 print ("%1\n%2\n", header, headerline); 108 print ("%1\n%2\n", header, headerline);
122 109
123 if (argc < 2) { 110 if (argc < 2)
111 {
124 fprintf (stderr, "usage: %s <infile> [outfile] # compiles botscript\n", argv[0]); 112 fprintf (stderr, "usage: %s <infile> [outfile] # compiles botscript\n", argv[0]);
125 fprintf (stderr, " %s -l # lists commands\n", argv[0]); 113 fprintf (stderr, " %s -l # lists commands\n", argv[0]);
126 exit (1); 114 exit (1);
127 } 115 }
128 116
129 // A word should always be exactly 4 bytes. The above list command
130 // doesn't need it, but the rest of the program does.
131 if (sizeof (word) != 4)
132 error ("%s expects a word (uint32_t) to be 4 bytes in size, is %d\n",
133 APPNAME, sizeof (word));
134
135 string outfile; 117 string outfile;
118
136 if (argc < 3) 119 if (argc < 3)
137 outfile = ObjectFileName (argv[1]); 120 outfile = ObjectFileName (argv[1]);
138 else 121 else
139 outfile = argv[2]; 122 outfile = argv[2];
140 123
141 // If we'd end up writing into an existing file, 124 // If we'd end up writing into an existing file,
142 // ask the user if we want to overwrite it 125 // ask the user if we want to overwrite it
143 if (fexists (outfile)) { 126 if (fexists (outfile))
127 {
144 // Additional warning if the paths are the same 128 // Additional warning if the paths are the same
145 string warning; 129 string warning;
146 #ifdef FILE_CASEINSENSITIVE 130 #ifdef FILE_CASEINSENSITIVE
147 if (!outfile.icompare (argv[1])) 131
132 if (+outfile == +string (argv[1]))
148 #else 133 #else
149 if (!outfile.compare (argv[1])) 134 if (outfile == argv[1])
150 #endif 135 #endif
151 { 136 {
152 warning = "\nWARNING: Output file is the same as the input file. "; 137 warning = "\nWARNING: Output file is the same as the input file. ";
153 warning += "Answering yes here will destroy the source!\n"; 138 warning += "Answering yes here will destroy the source!\n";
154 warning += "Continue nevertheless?"; 139 warning += "Continue nevertheless?";
155 } 140 }
141
156 printf ("output file `%s` already exists! overwrite?%s (y/n) ", outfile.chars(), warning.chars()); 142 printf ("output file `%s` already exists! overwrite?%s (y/n) ", outfile.chars(), warning.chars());
157 143
158 char ans; 144 char ans;
159 fgets (&ans, 2, stdin); 145 fgets (&ans, 1, stdin);
160 if (ans != 'y') { 146
147 if (ans != 'y')
148 {
161 printf ("abort\n"); 149 printf ("abort\n");
162 exit (1); 150 exit (1);
163 } 151 }
164 } 152 }
165 153
166 // Read definitions 154 // Read definitions
167 printf ("Reading definitions...\n"); 155 printf ("Reading definitions...\n");
168 ReadEvents (); 156 ReadEvents();
169 ReadCommands (); 157 ReadCommands();
170 158
171 // Prepare reader and writer 159 // Prepare reader and writer
172 ScriptReader* r = new ScriptReader (argv[1]); 160 botscript_parser* r = new botscript_parser;
173 ObjWriter* w = new ObjWriter (outfile); 161 object_writer* w = new object_writer;
174 162
175 // We're set, begin parsing :) 163 // We're set, begin parsing :)
176 printf ("Parsing script...\n"); 164 printf ("Parsing script...\n");
177 r->ParseBotScript (w); 165 r->parse_botscript (argv[1], w);
178 printf ("Script parsed successfully.\n"); 166 printf ("Script parsed successfully.\n");
179 167
180 // Parse done, print statistics and write to file 168 // Parse done, print statistics and write to file
181 unsigned int globalcount = g_GlobalVariables.size(); 169 int globalcount = g_GlobalVariables.size();
182 unsigned int stringcount = num_strings_in_table (); 170 int stringcount = num_strings_in_table();
183 int NumMarks = w->MainBuffer->CountMarks (); 171 int NumMarks = w->MainBuffer->count_marks();
184 int NumRefs = w->MainBuffer->CountReferences (); 172 int NumRefs = w->MainBuffer->count_references();
185 printf ("%u / %u strings written\n", stringcount, MAX_LIST_STRINGS); 173 print ("%1 / %2 strings written\n", stringcount, MAX_LIST_STRINGS);
186 printf ("%u / %u global variables\n", globalcount, MAX_SCRIPT_VARIABLES); 174 print ("%1 / %2 global variables\n", globalcount, MAX_SCRIPT_VARIABLES);
187 printf ("%d / %d bytecode marks\n", NumMarks, MAX_MARKS); 175 print ("%1 / %2 bytecode marks\n", NumMarks, MAX_MARKS); // TODO: nuke
188 printf ("%d / %d bytecode references\n", NumRefs, MAX_MARKS); 176 print ("%1 / %2 bytecode references\n", NumRefs, MAX_MARKS); // TODO: nuke
189 printf ("%d / %d events\n", g_NumEvents, MAX_NUM_EVENTS); 177 print ("%1 / %2 events\n", g_NumEvents, MAX_NUM_EVENTS);
190 printf ("%d state%s\n", g_NumStates, PLURAL (g_NumStates)); 178 print ("%1 state%s1\n", g_NumStates);
191 179
192 w->WriteToFile (); 180 w->write_to_file (outfile);
193 181
194 // Clear out the junk 182 // Clear out the junk
195 delete r; 183 delete r;
196 delete w; 184 delete w;
197 185
198 // Done! 186 // Done!
199 exit (0); 187 exit (0);
200 } 188 }
201 189
202 // ============================================================================ 190 // ============================================================================
203 // Utility functions 191 // Utility functions
204 192
205 // ============================================================================ 193 // ============================================================================
206 // Does the given file exist? 194 // Does the given file exist?
207 bool fexists (string path) { 195 bool fexists (string path)
208 if (FILE* test = fopen (path, "r")) { 196 {
197 if (FILE* test = fopen (path, "r"))
198 {
209 fclose (test); 199 fclose (test);
210 return true; 200 return true;
211 } 201 }
212 202
213 return false; 203 return false;
214 } 204 }
215 205
216 // ============================================================================ 206 // ============================================================================
217 // Generic error 207 // Generic error
218 void error (const char* text, ...) { 208 void error (const char* text, ...)
209 {
219 va_list va; 210 va_list va;
220 va_start (va, text); 211 va_start (va, text);
221 fprintf (stderr, "error: "); 212 fprintf (stderr, "error: ");
222 vfprintf (stderr, text, va); 213 vfprintf (stderr, text, va);
223 va_end (va); 214 va_end (va);
224 exit (1); 215 exit (1);
225 } 216 }
226 217
227 // ============================================================================ 218 // ============================================================================
228 // Mutates given filename to an object filename 219 // Mutates given filename to an object filename
229 string ObjectFileName (string s) { 220 string ObjectFileName (string s)
221 {
230 // Locate the extension and chop it out 222 // Locate the extension and chop it out
231 int extdot = s.last ("."); 223 int extdot = s.last (".");
232 224
233 if (extdot >= s.len() - 4) 225 if (extdot >= s.len() - 4)
234 s -= (s.len() - extdot); 226 s -= (s.len() - extdot);
235 227
236 s += ".o"; 228 s += ".o";
237 return s; 229 return s;
238 } 230 }
239 231
240 // ============================================================================ 232 // ============================================================================
241 // Is the given argument a reserved keyword? 233 // Is the given argument a reserved keyword?
242 bool IsKeyword (string s) { 234 bool IsKeyword (string s)
243 for (unsigned int u = 0; u < NumKeywords (); u++) 235 {
236 for (int u = 0; u < NumKeywords(); u++)
244 if (s.to_uppercase() == g_Keywords[u].to_uppercase()) 237 if (s.to_uppercase() == g_Keywords[u].to_uppercase())
245 return true; 238 return true;
239
246 return false; 240 return false;
247 } 241 }
248 242
249 unsigned int NumKeywords () { 243 int NumKeywords()
244 {
250 return sizeof (g_Keywords) / sizeof (const char*); 245 return sizeof (g_Keywords) / sizeof (const char*);
251 } 246 }
252 247
253 // ============================================================================ 248 // ============================================================================
254 type_e GetTypeByName (string t) { 249 type_e GetTypeByName (string t)
250 {
255 t = t.to_lowercase(); 251 t = t.to_lowercase();
256 return (t == "int") ? TYPE_INT : 252 return (t == "int") ? TYPE_INT :
257 (t == "str") ? TYPE_STRING : 253 (t == "str") ? TYPE_STRING :
258 (t == "void") ? TYPE_VOID : 254 (t == "void") ? TYPE_VOID :
259 (t == "bool") ? TYPE_BOOL : 255 (t == "bool") ? TYPE_BOOL :
261 } 257 }
262 258
263 259
264 // ============================================================================ 260 // ============================================================================
265 // Inverse operation - type name by value 261 // Inverse operation - type name by value
266 string GetTypeName (type_e type) { 262 string GetTypeName (type_e type)
267 switch (type) { 263 {
264 switch (type)
265 {
268 case TYPE_INT: return "int"; break; 266 case TYPE_INT: return "int"; break;
267
269 case TYPE_STRING: return "str"; break; 268 case TYPE_STRING: return "str"; break;
269
270 case TYPE_VOID: return "void"; break; 270 case TYPE_VOID: return "void"; break;
271
271 case TYPE_BOOL: return "bool"; break; 272 case TYPE_BOOL: return "bool"; break;
273
272 case TYPE_UNKNOWN: return "???"; break; 274 case TYPE_UNKNOWN: return "???"; break;
273 } 275 }
274 276
275 return ""; 277 return "";
276 } 278 }

mercurial