Added ability to define multiple functions (without parameters) and
[zilutils.git] / zilasm / main.cpp
1 /*
2  * main.c
3  *
4  * Copyright (C) 2015 Alexander Andrejevic <theflash AT sdf DOT lonestar DOT org>
5  * Copyright (C) 2015, 2019, 2020 Jason Self <j@jxself.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Affero General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Affero General Public License for more details.
16  *
17  * You should have received a copy of the GNU Affero General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>
19  *
20  * SPDX-License-Identifier: AGPL-3.0-or-later
21  */
22 //
23 //#include <stdio.h>
24 //#include <stdlib.h>
25 //#include <stdarg.h>
26 //#include <string.h>
27 //#include <string>
28 //#include <list>
29 //#include <stack>
30 //#include <list>
31 //#include <vector>
32 //using namespace std;
33 //
34 //
35 //extern "C"
36 //{
37 //#include <strings.h>
38 //}
39 //#include <getopt.h>
40 //#include <time.h>
41 //#include <ctype.h>
42 //#include "config.h"
43 //#include "header.h"
44 //extern "C"
45 //{
46 //#include "opcodes.h"
47 //}
48 //#include "directives.h"
49 //#include "parser.h"
50 //#include "compiler.h"
51
52
53 #include "include_all.h"
54
55 const int DEFAULT_ZVERSION = 6;
56
57 enum
58 { ZVERSION = 11, ZORKID, ZSERIAL };
59
60
61
62 static struct option const long_options[] = {
63   {"help", no_argument, NULL, 'h'},
64   {"version", no_argument, NULL, 'V'},
65   {"output", required_argument, NULL, 'o'},
66   {"zversion", required_argument, NULL, ZVERSION},
67   {"zorkid", required_argument, NULL, ZORKID},
68   {"serial", required_argument, NULL, ZSERIAL},
69   {NULL, 0, NULL, 0}
70 };
71
72
73
74
75
76
77
78
79
80
81 struct
82 {
83         int zversion;                   /* 0 - 8     */
84         int zorkid;                     /* 0 - 65535 */
85         char zserial[7];                /* YYMMDD    */
86         Opcode_dict *opcode_dict;
87 } Config;
88
89 void
90 CCompiler::get_arguments (int argc, char *argv[], char *envp[])
91 {
92   int opt = 0;
93   while ((opt = getopt_long (argc, argv, "hVo:", long_options, NULL)) != -1)
94     {
95       switch (opt)
96         {
97         case 'h':
98           print_usage (0);
99         case 'V':
100           print_version ();
101         case 'o':
102           if (m_output_file)
103             wrong_arg ("Output file must be given once\n");
104           m_output_file = optarg;
105           break;
106         case ZVERSION:
107           parse_intarg (&Config.zversion, "zversion", 1, 8, 1);
108           break;
109         case ZORKID:
110           parse_intarg (&Config.zorkid, "zorkid", 0, 0xFFFF, 0);
111           break;
112         case ZSERIAL:
113           parse_zserial ();
114           break;
115         default:
116           wrong_arg (0);
117         }
118     }
119
120   int first_input_file = optind;
121   if (first_input_file >= argc)
122     wrong_arg ("Missing input file\n");
123   if (!m_output_file)
124     m_output_file = build_output_filename (argv[first_input_file], ".dat");
125
126   // TODO: Everything :)
127
128
129   printf ("Input files:\n");
130   for (int i = optind; i < argc; i++)
131     printf ("\t%s\n", argv[i]);
132
133   printf ("Output file: %s\n\n", m_output_file);
134
135   printf ("Config:\n"
136           "- ZVersion: %d\n"
137           "- ZorkID:   %d\n"
138           "- ZSerial:  %s\n", Config.zversion, Config.zorkid, Config.zserial);
139
140 }
141
142
143 void
144 CCompiler::wrong_arg (const char *err, ...)
145 {
146   if (err)
147     {
148       va_list ap;
149       va_start (ap, err);
150       vfprintf (stderr, err, ap);
151       va_end (ap);
152     }
153   fprintf (stderr, "Try `" PACKAGE_NAME " --help' for more information.\n");
154   exit (1);
155 }
156
157
158 void
159 CCompiler::print_version ()
160 {
161   printf (PACKAGE_STRING "\n"
162           "License AGPLv3+: GNU AGPL version 3 or later\n"
163           "<http://gnu.org/licenses/agpl.html>\n"
164           "This is free software: you are free to change and redistribute it.\n"
165           "There is NO WARRANTY, to the extent permitted by law.\n");
166   exit (0);
167 }
168
169
170 void
171 CCompiler::print_usage (int failed)
172 {
173   printf ("Usage: " PACKAGE_NAME " [OPTION...] [FILES...]\n"
174           "\n"
175           "--version  Display program version and exit\n"
176           "--help     Display this help\n"
177           "\n"
178           "--zversion (accepts numbers 1 - 8, defaults to %d if not specified)\n"
179           "--zorkid   (integer between 0 and 65535, defaults to 0 if not specified)\n"
180           "--serial   (six characters of ASCII, defaults to current date\n"
181           "            in the form YYMMDD if not specified)\n",
182           DEFAULT_ZVERSION);
183   exit (failed);
184 }
185
186 void
187 CCompiler::fill_zserial (void)
188 {
189   time_t t;
190   struct tm *timeinfo;
191   time (&t);
192   timeinfo = localtime (&t);
193   strftime (Config.zserial, sizeof (Config.zserial), "%y%m%d", timeinfo);
194 }
195
196
197 void
198 CCompiler::fill_config (void)
199 {
200   bzero (&Config, sizeof (Config));
201   Config.zversion = DEFAULT_ZVERSION;
202   fill_zserial ();
203 }
204
205
206 void
207 CCompiler::parse_intarg (int *dest, const char name[], int min, int max,
208                      int defval)
209 {
210   if (!optarg)
211     {
212       *dest = defval;
213       return;
214     }
215   int n = atoi (optarg);
216   if (n >= min && n <= max)
217     {
218       *dest = n;
219       return;
220     }
221   wrong_arg ("Wrong %s value %s, must be integer between %d and %d\n",
222              name, optarg, min, max);
223 }
224
225
226 void
227 CCompiler::parse_zserial (void)
228 {
229   if (!optarg)
230     {
231       fill_zserial ();
232       return;
233     }
234   size_t n = strlen (optarg);
235   if (n == sizeof (Config.zserial) - 1)
236     {
237       char *p = optarg;
238       while (*p && isalnum (*p))
239         p++;
240       if (!*p)
241         {                       /* ..optarg contains alphanumeric only? */
242           strncpy (Config.zserial, optarg, sizeof (Config.zserial));
243           return;
244         }
245     }
246   wrong_arg ("Wrong zserial value %s, must be 6 ascii characters\n", optarg);
247 }
248
249
250 void
251 CCompiler::new_file_suffix (char *result, size_t maxlen, const char *src,
252                         const char *newsuffix)
253 {
254   strncpy (result, src, maxlen);
255   char *p = strrchr (result, '.');
256   if (p && strchr (p, '/'))
257     p = NULL;
258   if (p)
259     {
260       strncpy (p, newsuffix, maxlen - (p - result));
261     }
262   else
263     {
264       strncat (result, newsuffix, maxlen);
265     }
266   result[maxlen] = 0;
267 }
268
269
270 char *
271 CCompiler::build_output_filename (const char basename[], const char *suffix)
272 {
273   int n = strlen (basename) + strlen (suffix);
274   char *ofile = (char *) malloc (n + 1);        /* todo!!! check for NULL. free. */
275   new_file_suffix (ofile, n, basename, suffix);
276   return ofile;
277 }
278
279
280 int
281 init_assembly (void)
282 {
283   /* TODO */
284   return OK;
285 }
286
287
288 void
289 CCompiler::output_code_section ()
290 {
291
292 }
293
294
295 int
296 main (int argc, char *argv[], char *envp[])
297 {
298   CCompiler compiler;
299
300   compiler.fill_config ();
301   compiler.get_arguments (argc, argv, envp);
302   init_opcodes (Config.zversion, 0);
303
304   
305         //for (int i = optind; i < argc; i++)
306         //      parse_file(argv[i]);
307   
308   string file_name = argv[optind];
309   Parsing_Context pc;
310
311 #ifdef WIN32
312   char delimeter = '\\';
313 #else
314   char delimeter = '/';
315 #endif
316
317   if (file_name.rfind(delimeter) == string::npos)
318   {
319           pc.current_directory = "";
320           pc.current_file_name = file_name;
321   }
322   else
323   {
324           pc.current_directory = file_name.substr(0, file_name.rfind(delimeter)+1);
325           pc.current_file_name = file_name.substr(file_name.rfind(delimeter)+1);
326   }
327   g_parsing_contexts.push(pc);
328
329   compiler.parser.parse_file();// argv[optind]);
330   if ( !compiler.parser.have_errors())
331         compiler.assembly ();
332
333   /* TODO! List global symbols */
334   /* TODO! Find abbreviations */
335   //relase_parser ();
336   return 0;
337 }