X-Git-Url: https://jxself.org/git/?p=zilutils.git;a=blobdiff_plain;f=zilasm%2Fmain.cpp;fp=zilasm%2Fmain.cpp;h=22b7e7145c09d8642fe8df92455ebae9b11d26ec;hp=0000000000000000000000000000000000000000;hb=82b0f84ab797141758929d16894d42e12ef79af7;hpb=37d32bd49e745a5c1686b6495f60172b24222361 diff --git a/zilasm/main.cpp b/zilasm/main.cpp new file mode 100644 index 0000000..22b7e71 --- /dev/null +++ b/zilasm/main.cpp @@ -0,0 +1,435 @@ +/* + * main.c + * + * Copyright (C) 2015 Alexander Andrejevic + * Copyright (C) 2015, 2019 Jason Self + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +#include +#include +#include +#include +extern "C" +{ +#include +} +#include +#include +#include +#include "config.h" +#include "header.h" +extern "C" +{ +#include "opcodes.h" +} +#include "parser.h" + +#include +#include +using namespace std; + +const int DEFAULT_ZVERSION = 6; + +enum +{ ZVERSION = 11, ZORKID, ZSERIAL }; + +enum +{ FAIL = -1, OK = 0, NEED_RESTART = 1 }; + +static struct option const long_options[] = { + {"help", no_argument, NULL, 'h'}, + {"version", no_argument, NULL, 'V'}, + {"output", required_argument, NULL, 'o'}, + {"zversion", required_argument, NULL, ZVERSION}, + {"zorkid", required_argument, NULL, ZORKID}, + {"serial", required_argument, NULL, ZSERIAL}, + {NULL, 0, NULL, 0} +}; + + +typedef struct +{ + int todo; +} Opcode_dict; + + +struct +{ + int zversion; /* 0 - 8 */ + int zorkid; /* 0 - 65535 */ + char zserial[7]; /* YYMMDD */ + Opcode_dict *opcode_dict; +} Config; + + +struct String_Table_Elem +{ + string value; // value in ASCII format + int index; +}; + + +class CMain +{ +public: + CMain (); + int assembly (); + void fill_config (void); + void get_arguments (int argc, char *argv[], char *envp[]); + + char *get_output_file_name (); +private: + char *m_output_file; + list < String_Table_Elem > m_string_table; + int m_code_size; + + + char *build_output_filename (const char basename[], const char *suffix); + void fill_zserial (void); + void new_file_suffix (char *result, size_t maxlen, const char *src, + const char *newsuffix); + + void output_code_section (); + + void parse_intarg (int *dest, const char name[], int min, int max, + int defval); + void parse_zserial (void); + void print_usage (int failed); + void print_version (); + void wrong_arg (const char *err, ...); + +}; + + +CMain::CMain ():m_output_file (NULL) +{ +} + +int +CMain::assembly () +{ + FILE *file = fopen (m_output_file, "wb"); + if (file) + { + program_header_reset (6); + int size = sizeof (Program_header); + + Program_header.mode = 0; + Program_header.release = 1; // game version + + int code_start_offset = 64; + Program_header.startPC = code_start_offset >> 2; + + m_code_size = 0; + ZMemblock *zmem_code = zmem_init (65536); + + /// write zero number of local variables + zmem_putbyte (zmem_code, 0); // number of local variables + ++m_code_size; + + // write instructions' codes + for (int i = 0; i < g_numberOfInstructions; ++i) + { + for (int j = 0; j < g_codes[i]->used_size; ++j) + { + zmem_putbyte (zmem_code, g_codes[i]->contents[j]); + ++m_code_size; + } + } + + if (m_code_size & 7) + m_code_size += 8 - (m_code_size & 7); + + Program_header.dynamic_size = 8; + + //Program_header.h_file_size = 33; //sizeof(Program_header) + zmb->used_size; + + //m_code_size = 8; + + Word stringTableOffset = m_code_size; + Program_header.H_STRINGS_OFFSET = (64 + stringTableOffset) >> 3; + + int stringTableSize = 64; + Program_header.h_file_size = + (code_start_offset + m_code_size + stringTableSize) >> 3; + ZMemblock *zmb = zmem_init (Program_header.h_file_size * 8); + + for (int i = 0; i < m_code_size; ++i) + zmem_putbyte (zmb, zmem_code->contents[i]); + + zmem_destroy (zmem_code); + + //zmem_putbyte(zmb, 0); // number of local variables + //zmem_putbyte(zmb, 141); // print addr command + + //Word offset = 0; + //zmem_putbyte(zmb, (offset >> 8) & 255); + //zmem_putbyte(zmb, offset & 255); + + //zmem_putbyte(zmb, 186); // quit command + + // output zeros until string table begins + while (zmb->used_size < stringTableOffset) + zmem_putbyte (zmb, 0); + // + //// fill string table with one string + //add_string_to_string_table("Hello, World!", zmb); + + outputToFile (&Program_header, file); + fwrite (zmb->contents, zmb->allocated_size, 1, file); + fclose (file); + } + + return OK; +} + + +char * +CMain::get_output_file_name () +{ + return m_output_file; +} + + +void +CMain::get_arguments (int argc, char *argv[], char *envp[]) +{ + int opt = 0; + while ((opt = getopt_long (argc, argv, "hVo:", long_options, NULL)) != -1) + { + switch (opt) + { + case 'h': + print_usage (0); + case 'V': + print_version (); + case 'o': + if (m_output_file) + wrong_arg ("Output file must be given once\n"); + m_output_file = optarg; + break; + case ZVERSION: + parse_intarg (&Config.zversion, "zversion", 1, 8, 1); + break; + case ZORKID: + parse_intarg (&Config.zorkid, "zorkid", 0, 0xFFFF, 0); + break; + case ZSERIAL: + parse_zserial (); + break; + default: + wrong_arg (0); + } + } + + int first_input_file = optind; + if (first_input_file >= argc) + wrong_arg ("Missing input file\n"); + if (!m_output_file) + m_output_file = build_output_filename (argv[first_input_file], ".dat"); + + // TODO: Everything :) + + + printf ("Input files:\n"); + for (int i = optind; i < argc; i++) + printf ("\t%s\n", argv[i]); + + printf ("Output file: %s\n\n", m_output_file); + + printf ("Config:\n" + "- ZVersion: %d\n" + "- ZorkID: %d\n" + "- ZSerial: %s\n", Config.zversion, Config.zorkid, Config.zserial); + +} + + +void +CMain::wrong_arg (const char *err, ...) +{ + if (err) + { + va_list ap; + va_start (ap, err); + vfprintf (stderr, err, ap); + va_end (ap); + } + fprintf (stderr, "Try `" PACKAGE_NAME " --help' for more information.\n"); + exit (1); +} + + +void +CMain::print_version () +{ + printf (PACKAGE_STRING "\n" + "License AGPLv3+: GNU AGPL version 3 or later\n" + "\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n"); + exit (0); +} + + +void +CMain::print_usage (int failed) +{ + printf ("Usage: " PACKAGE_NAME " [OPTION...] [FILES...]\n" + "\n" + "--version Display program version and exit\n" + "--help Display this help\n" + "\n" + "--zversion (accepts numbers 1 - 8, defaults to %d if not specified)\n" + "--zorkid (integer between 0 and 65535, defaults to 0 if not specified)\n" + "--serial (six characters of ASCII, defaults to current date\n" + " in the form YYMMDD if not specified)\n", + DEFAULT_ZVERSION); + exit (failed); +} + +void +CMain::fill_zserial (void) +{ + time_t t; + struct tm *timeinfo; + time (&t); + timeinfo = localtime (&t); + strftime (Config.zserial, sizeof (Config.zserial), "%y%m%d", timeinfo); +} + + +void +CMain::fill_config (void) +{ + bzero (&Config, sizeof (Config)); + Config.zversion = DEFAULT_ZVERSION; + fill_zserial (); +} + + +void +CMain::parse_intarg (int *dest, const char name[], int min, int max, + int defval) +{ + if (!optarg) + { + *dest = defval; + return; + } + int n = atoi (optarg); + if (n >= min && n <= max) + { + *dest = n; + return; + } + wrong_arg ("Wrong %s value %s, must be integer between %d and %d\n", + name, optarg, min, max); +} + + +void +CMain::parse_zserial (void) +{ + if (!optarg) + { + fill_zserial (); + return; + } + size_t n = strlen (optarg); + if (n == sizeof (Config.zserial) - 1) + { + char *p = optarg; + while (*p && isalnum (*p)) + p++; + if (!*p) + { /* ..optarg contains alphanumeric only? */ + strncpy (Config.zserial, optarg, sizeof (Config.zserial)); + return; + } + } + wrong_arg ("Wrong zserial value %s, must be 6 ascii characters\n", optarg); +} + + +void +CMain::new_file_suffix (char *result, size_t maxlen, const char *src, + const char *newsuffix) +{ + strncpy (result, src, maxlen); + char *p = strrchr (result, '.'); + if (p && strchr (p, '/')) + p = NULL; + if (p) + { + strncpy (p, newsuffix, maxlen - (p - result)); + } + else + { + strncat (result, newsuffix, maxlen); + } + result[maxlen] = 0; +} + + +char * +CMain::build_output_filename (const char basename[], const char *suffix) +{ + int n = strlen (basename) + strlen (suffix); + char *ofile = (char *) malloc (n + 1); /* todo!!! check for NULL. free. */ + new_file_suffix (ofile, n, basename, suffix); + return ofile; +} + + +int +init_assembly (void) +{ + /* TODO */ + return OK; +} + + +void +CMain::output_code_section () +{ + +} + + + +int +main (int argc, char *argv[], char *envp[]) +{ + CMain main; + + main.fill_config (); + main.get_arguments (argc, argv, envp); + init_opcodes (Config.zversion, 0); + + init_parser (); + + for (int i = optind; i < argc; i++) + parse_file (argv[i]); + main.assembly (); + + /* TODO! List global symbols */ + /* TODO! Find abbreviations */ + relase_parser (); + return 0; +}