/* top level functions for gpasm Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 James Bowman, Craig Franklin This file is part of gputils. gputils is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. gputils 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 General Public License for more details. You should have received a copy of the GNU General Public License along with gputils; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "stdhdr.h" #include "libgputils.h" #include "gpasm.h" #include "gperror.h" #include "scan.h" #include "deps.h" #include "directive.h" #include "lst.h" #include "cod.h" #include "processor.h" #include "coff.h" struct gpasm_state state; static gp_boolean cmd_processor = false; static char *processor_name = NULL; int yyparse(void); extern int yydebug; #define GET_OPTIONS "?D:I:a:cde:ghilLmMno:p:qr:uvw:y" static struct option longopts[] = { { "define", 1, 0, 'D' }, { "include", 1, 0, 'I' }, { "hex-format", 1, 0, 'a' }, { "object", 0, 0, 'c' }, { "debug", 0, 0, 'd' }, { "expand", 1, 0, 'e' }, { "debug-info", 0, 0, 'g' }, { "help", 0, 0, 'h' }, { "ignore-case", 0, 0, 'i' }, { "list-chips", 0, 0, 'l' }, { "force-list", 0, 0, 'L' }, { "dump", 0, 0, 'm' }, { "deps", 0, 0, 'M' }, { "dos", 0, 0, 'n' }, { "output", 1, 0, 'o' }, { "processor", 1, 0, 'p' }, { "quiet", 0, 0, 'q' }, { "radix", 1, 0, 'r' }, { "absolute", 0, 0, 'u' }, { "version", 0, 0, 'v' }, { "warning", 1, 0, 'w' }, { "extended", 0, 0, 'y' }, { 0, 0, 0, 0 } }; void init(void) { gp_init(); /* restore gpasm to its initialized state */ state.mode = absolute; state.extended_pic16e = false; state.radix = 16; state.hex_format = inhx32; state.case_insensitive = false; state.quiet = false; state.use_absolute_path = false; state.error_level = 0; state.debug_info = false; state.path_num = 0; state.cmd_line.radix = false; state.cmd_line.hex_format = false; state.cmd_line.error_level = false; state.cmd_line.macro_expand = false; state.cmd_line.processor = false; state.cmd_line.lst_force = false; state.pass = 0; state.org = 0; state.dos_newlines = false; state.memory_dump = false; state.found_config = false; state.found_devid = false; state.found_idlocs = false; state.maxram = (MAX_RAM - 1); state.codfile = normal; state.depfile = suppress; state.hexfile = normal; state.lstfile = normal; state.objfile = suppress; state.num.errors = 0; state.num.warnings = 0; state.num.messages = 0; state.num.warnings_suppressed = 0; state.num.messages_suppressed = 0; state.processor = no_processor; state.processor_chosen = 0; state.cod.enabled = false; state.dep.enabled = false; state.lst.enabled = false; state.obj.enabled = false; state.obj.object = NULL; state.obj.section = NULL; state.obj.symbol_num = 0; state.obj.section_num = 0; state.astack = NULL; state.next_state = state_nochange; return; } void add_path(char *path) { if(state.path_num < MAX_PATHS) { state.paths[state.path_num++] = strdup(path); } else { fprintf(stderr, "too many -I paths\n"); exit(1); } } static void show_usage(void) { printf("Usage: gpasm [options] file\n"); printf("Options: [defaults in brackets after descriptions]\n"); printf(" -a FMT, --hex-format FMT Select hex file format. [inhx32]\n"); printf(" -c, --object Output relocatable object.\n"); printf(" -d, --debug Output debug messages.\n"); printf(" -D SYM=VAL, --define SYM=VAL Define SYM with value VAL.\n"); printf(" -e [ON|OFF], --expand [ON|OFF] Macro expansion.\n"); printf(" -g, --debug-info Use debug directives for COFF.\n"); printf(" -h, --help Show this usage message.\n"); printf(" -i, --ignore-case Case insensitive.\n"); printf(" -I DIR, --include DIR Specify include directory.\n"); printf(" -l, --list-chips List supported processors.\n"); printf(" -L, --force-list Ignore nolist directives.\n"); printf(" -m, --dump Memory dump.\n"); printf(" -M, --deps Output dependency file.\n"); #ifndef HAVE_DOS_BASED_FILE_SYSTEM printf(" -n, --dos Use DOS newlines in hex file.\n"); #endif printf(" -o FILE, --output FILE Alternate name of output file.\n"); printf(" -p PROC, --processor PROC Select processor.\n"); printf(" -q, --quiet Quiet.\n"); printf(" -r RADIX, --radix RADIX Select radix. [hex]\n"); printf(" -u, --absolute Use absolute pathes. \n"); printf(" -v, --version Show version.\n"); printf(" -w [0|1|2], --warning [0|1|2] Set message level. [0]\n"); printf(" -y, --extended Enable 18xx extended mode.\n"); printf("\n"); #ifdef USE_DEFAULT_PATHS if (gp_header_path) { printf("Default header file path %s\n", gp_header_path); } else { printf("Default header file path NOT SET\n"); } printf("\n"); #endif printf("Report bugs to:\n"); printf("%s\n", PACKAGE_BUGREPORT); exit(0); } void process_args( int argc, char *argv[]) { extern char *optarg; extern int optind; int c; gp_boolean usage = false; char *pc; /* Scan through the options for the -i flag. It must be set before the defines are read */ while ((c = getopt_long(argc, argv, GET_OPTIONS, longopts, 0)) != EOF) { switch (c) { case 'i': state.case_insensitive = true; break; } } /* reset the getopt_long index for the next call */ optind = 1; /* initalize the defines table for command line arguments */ state.stDefines = push_symbol_table(NULL, state.case_insensitive); while ((c = getopt_long(argc, argv, GET_OPTIONS, longopts, 0)) != EOF) { switch (c) { case '?': case 'h': usage = true; break; case 'a': select_hexformat(optarg); state.cmd_line.hex_format = true; break; case 'c': state.mode = relocatable; state.codfile = suppress; state.hexfile = suppress; state.lstfile = normal; state.objfile = normal; break; case 'd': gp_debug_disable = false; break; case 'D': if ((optarg != NULL) && (strlen(optarg) > 0)) { struct symbol *sym; char *lhs, *rhs; lhs = strdup(optarg); rhs = strchr(lhs, '='); if (rhs != NULL) { *rhs = '\0'; /* Terminate the left-hand side */ rhs++; /* right-hand side begins after the '=' */ } sym = get_symbol(state.stDefines, lhs); if (sym == NULL) sym = add_symbol(state.stDefines, lhs); if (rhs) annotate_symbol(sym, rhs); } break; case 'e': select_expand(optarg); state.cmd_line.macro_expand = true; break; case 'g': state.debug_info = true; break; case 'I': add_path(optarg); break; case 'i': state.case_insensitive = true; break; case 'L': state.cmd_line.lst_force = true; break; case 'l': gp_dump_processor_list(true, 0); exit(0); break; case 'M': state.depfile = normal; break; case 'm': state.memory_dump = true; break; case 'n': #ifndef HAVE_DOS_BASED_FILE_SYSTEM state.dos_newlines = true; #endif break; case 'o': strncpy(state.hexfilename, optarg, sizeof(state.hexfilename)); strncpy(state.basefilename, optarg, sizeof(state.basefilename)); pc = strrchr(state.basefilename, '.'); if (pc) *pc = 0; break; case 'p': cmd_processor = true; processor_name = optarg; break; case 'q': state.quiet = true; break; case 'r': select_radix(optarg); state.cmd_line.radix = true; break; case 'u': state.use_absolute_path = true; break; case 'w': select_errorlevel(atoi(optarg)); state.cmd_line.error_level = true; break; case 'y': state.extended_pic16e = true; break; case 'v': fprintf(stderr, "%s\n", GPASM_VERSION_STRING); exit(0); } if (usage) break; } if ((optind + 1) == argc) state.srcfilename = argv[optind]; else usage = true; if (usage) { show_usage(); } /* Add the header path to the include paths list last, so that the user specified directories are searched first */ if (gp_header_path) { add_path(gp_header_path); } if (state.use_absolute_path) { state.srcfilename = gp_absolute_path(state.srcfilename); } } int assemble(void) { char *pc; struct symbol_table *cmd_defines; /* store the command line defines to restore on second pass */ cmd_defines = state.stDefines; state.c_memory = state.i_memory = i_memory_create(); if(state.basefilename[0] == '\0') { strncpy(state.basefilename, state.srcfilename, sizeof(state.basefilename)); pc = strrchr(state.basefilename, '.'); if (pc) *pc = 0; } /* Builtins are always case insensitive */ state.stBuiltin = push_symbol_table(NULL, true); state.stDirective = state.stBuiltin; state.stMacros = push_symbol_table(NULL, state.case_insensitive); state.stTop = state.stGlobal = push_symbol_table(NULL, state.case_insensitive); state.stTopDefines = state.stDefines = push_symbol_table(cmd_defines, state.case_insensitive); opcode_init(0); /* the tables are built, select the processor if -p was used */ if (cmd_processor) { select_processor(processor_name); state.cmd_line.processor = true; } state.pass = 1; open_src(state.srcfilename, 0); yyparse(); state.pass++; state.org = 0; state.cblock = 0; /* clean out defines for second pass */ state.stTopDefines = state.stDefines = push_symbol_table(cmd_defines, state.case_insensitive); if (!state.cmd_line.radix) state.radix = 16; state.obj.symbol_num = 0; state.obj.section_num = 0; state.found_config = false; state.found_devid = false; state.found_idlocs = false; coff_init(); cod_init(); deps_init(); lst_init(); open_src(state.srcfilename, 0); if (!gp_debug_disable) { yydebug = 1; } else { yydebug = 0; } yyparse(); assert(state.pass == 2); pop_symbol_table(state.stBuiltin); hex_init(); if(state.memory_dump) print_i_memory(state.i_memory, state.device.class == PROC_CLASS_PIC16E ? 1 : 0); /* Maybe produce a symbol table */ if (state.lst.symboltable) { lst_throw(); /* Start symbol table on a fresh page */ lst_symbol_table(state.stGlobal); lst_defines_table(state.stDefines); } /* Maybe produce a memory map */ if ((state.mode == absolute) && (state.lst.memorymap)) { lst_memory_map(state.i_memory); } /* Finish off the object, dependency, listing, and symbol files*/ coff_close_file(); deps_close(); lst_close(); if (state.processor_info) cod_close_file(); free_files(); if ((state.num.errors > 0) || (gp_num_errors > 0)) return EXIT_FAILURE; else return EXIT_SUCCESS; }