2012-02-27 21:14:46 +00:00
|
|
|
// ACME - a crossassembler for producing 6502/65c02/65816 code.
|
2014-03-10 00:17:10 +00:00
|
|
|
// Copyright (C) 1998-2014 Marco Baye
|
2012-02-27 21:14:46 +00:00
|
|
|
// Have a look at "acme.c" for further info
|
|
|
|
//
|
|
|
|
// Section stuff
|
|
|
|
#include "config.h"
|
|
|
|
#include "dynabuf.h"
|
|
|
|
#include "global.h"
|
|
|
|
#include "input.h"
|
|
|
|
#include "tree.h"
|
|
|
|
#include "section.h"
|
|
|
|
|
|
|
|
|
|
|
|
// Constants
|
|
|
|
static const char type_zone[] = "Zone";
|
|
|
|
static const char s_subzone[] = "subzone";
|
|
|
|
#define s_zone (s_subzone + 3) // Yes, I know I'm sick
|
|
|
|
static char untitled[] = "<untitled>";
|
|
|
|
// ...is actually constant, but flagging it "const" results in heap of warnings
|
|
|
|
|
|
|
|
// fake section structure (for error msgs before any real section is in use)
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct section initial_section = {
|
2012-02-27 21:14:46 +00:00
|
|
|
0, // zone value
|
|
|
|
"during", // "type" => normally "zone Title" or
|
|
|
|
"init", // "title" => "macro test", now "during init"
|
|
|
|
FALSE, // no, title was not malloc'd
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Variables
|
2014-03-11 12:07:11 +00:00
|
|
|
struct section *Section_now = &initial_section; // current section
|
|
|
|
static struct section outer_section; // outermost section struct
|
2012-02-27 21:14:46 +00:00
|
|
|
static zone_t zone_max; // Highest zone number yet
|
|
|
|
|
|
|
|
// Write given info into given zone structure and activate it
|
2014-03-11 12:07:11 +00:00
|
|
|
void Section_new_zone(struct section *section, const char *type, char *title, int allocated)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
section->zone = ++zone_max;
|
|
|
|
section->type = type;
|
|
|
|
section->title = title;
|
|
|
|
section->allocated = allocated;
|
|
|
|
// activate new section
|
|
|
|
Section_now = section;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tidy up: If necessary, release section title.
|
|
|
|
// Warning - the state of the component "Allocd" may have
|
|
|
|
// changed in the meantime, so don't rely on a local variable.
|
2014-03-11 12:07:11 +00:00
|
|
|
void Section_finalize(struct section *section)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
if (section->allocated)
|
|
|
|
free(section->title);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Switch to new zone ("!zone" or "!zn"). Has to be re-entrant.
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_zone(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2014-03-11 12:07:11 +00:00
|
|
|
struct section entry_values; // buffer for outer zone
|
|
|
|
char *new_title;
|
|
|
|
int allocated;
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
// remember everything about current structure
|
|
|
|
entry_values = *Section_now;
|
|
|
|
// set default values in case there is no valid title
|
|
|
|
new_title = untitled;
|
|
|
|
allocated = FALSE;
|
|
|
|
// Check whether a zone title is given. If yes and it can be read,
|
|
|
|
// get copy, remember pointer and remember to free it later on.
|
|
|
|
if (BYTEFLAGS(GotByte) & CONTS_KEYWORD) {
|
|
|
|
// Because we know of one character for sure,
|
|
|
|
// there's no need to check the return value.
|
|
|
|
Input_read_keyword();
|
|
|
|
new_title = DynaBuf_get_copy(GlobalDynaBuf);
|
|
|
|
allocated = TRUE;
|
|
|
|
}
|
|
|
|
// setup new section
|
|
|
|
// section type is "subzone", just in case a block follows
|
|
|
|
Section_new_zone(Section_now, "Subzone", new_title, allocated);
|
|
|
|
if (Parse_optional_block()) {
|
|
|
|
// Block has been parsed, so it was a SUBzone.
|
|
|
|
Section_finalize(Section_now); // end inner zone
|
|
|
|
*Section_now = entry_values; // restore entry values
|
|
|
|
} else {
|
|
|
|
// no block found, so it's a normal zone change
|
|
|
|
Section_finalize(&entry_values); // end outer zone
|
|
|
|
Section_now->type = type_zone; // change type to "zone"
|
|
|
|
}
|
|
|
|
return ENSURE_EOS;
|
|
|
|
}
|
|
|
|
|
2014-03-10 00:17:10 +00:00
|
|
|
// "!subzone" or "!sz" pseudo opcode (now obsolete)
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum eos PO_subzone(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2014-03-10 00:17:10 +00:00
|
|
|
Throw_error("\"!subzone {}\" is obsolete; use \"!zone {}\" instead.");
|
2012-02-27 21:14:46 +00:00
|
|
|
// call "!zone" instead
|
|
|
|
return PO_zone();
|
|
|
|
}
|
|
|
|
|
|
|
|
// predefined stuff
|
2014-11-24 14:52:05 +00:00
|
|
|
static struct ronode pseudo_opcodes[] = {
|
2012-02-27 21:14:46 +00:00
|
|
|
PREDEFNODE(s_zone, PO_zone),
|
|
|
|
PREDEFNODE("zn", PO_zone),
|
|
|
|
PREDEFNODE(s_subzone, PO_subzone),
|
|
|
|
PREDEFLAST("sz", PO_subzone),
|
|
|
|
// ^^^^ this marks the last element
|
|
|
|
};
|
|
|
|
|
|
|
|
// register pseudo opcodes
|
|
|
|
void Section_init(void)
|
|
|
|
{
|
|
|
|
Tree_add_table(&pseudo_opcode_tree, pseudo_opcodes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup outermost section
|
|
|
|
void Section_passinit(void)
|
|
|
|
{
|
|
|
|
zone_max = ZONE_GLOBAL; // will be incremented by next line
|
|
|
|
Section_new_zone(&outer_section, type_zone, untitled, FALSE);
|
|
|
|
}
|