Exemplo n.º 1
0
Arquivo: macro.c Projeto: lhz/acme
// This function is called from both macro definition and macro call.
// Terminate macro name and copy from internal_name to GlobalDynaBuf
// (because that's where Tree_hard_scan() looks for the search string).
// Then try to find macro and return whether it was created.
static int search_for_macro(struct rwnode **result, zone_t zone, int create)
{
    DynaBuf_append(internal_name, '\0');	// terminate macro name
    // now internal_name = macro_title SPC argument_specifiers NUL
    DYNABUF_CLEAR(GlobalDynaBuf);
    DynaBuf_add_string(GlobalDynaBuf, internal_name->buffer);
    DynaBuf_append(GlobalDynaBuf, '\0');
    return Tree_hard_scan(result, macro_forest, zone, create);
}
Exemplo n.º 2
0
// Try to read a condition into DynaBuf and store copy pointer in
// given loopcond_t structure.
// If no condition given, NULL is written to structure.
// Call with GotByte = first interesting character
static void store_condition(loopcond_t* condition, char terminator) {
	void*	node_body;

	// write line number
	condition->line = Input_now->line_number;
	// Check for empty condition
	if(GotByte == terminator) {
		// Write NULL condition, then return
		condition->body = NULL;
		return;
	}
	// Seems as if there really *is* a condition.
	// Read UNTIL/WHILE keyword
	if(Input_read_and_lower_keyword()) {
		// Search for new tree item
		if(!Tree_easy_scan(condkey_tree, &node_body, GlobalDynaBuf)) {
			Throw_error(exception_syntax);
			condition->body = NULL;
			return;
		}
		condition->type = (enum cond_key_t) node_body;
		// Write given condition into buffer
		SKIPSPACE();
		DYNABUF_CLEAR(GlobalDynaBuf);
		Input_until_terminator(terminator);
		DynaBuf_append(GlobalDynaBuf, CHAR_EOS);// ensure terminator
		condition->body = DynaBuf_get_copy(GlobalDynaBuf);
	}
	return;
}
Exemplo n.º 3
0
// Skip or store block (starting with next byte, so call directly after
// reading opening brace).
// If "Store" is TRUE, the block is read into GlobalDynaBuf, then a copy
// is made and a pointer to that is returned.
// If "Store" is FALSE, NULL is returned.
// After calling this function, GotByte holds '}'. Unless EOF was found first,
// but then a serious error would have been thrown.
char* Input_skip_or_store_block(bool store) {
	char	byte;
	int	depth	= 1;	// to find matching block end

	// prepare global dynamic buffer
	DYNABUF_CLEAR(GlobalDynaBuf);
	do {
		byte = GetByte();
		// if wanted, store
		if(store)
			DYNABUF_APPEND(GlobalDynaBuf, byte);
		// now check for some special characters
		switch(byte) {

			case CHAR_EOF:	// End-of-file in block? Sorry, no way.
			Throw_serious_error(exception_no_right_brace);

			case '"':	// Quotes? Okay, read quoted stuff.
			case '\'':
			do {
				GetQuotedByte();
				// if wanted, store
				if(store)
					DYNABUF_APPEND(GlobalDynaBuf, GotByte);
			} while((GotByte != CHAR_EOS) && (GotByte != byte));
			break;

			case CHAR_SOB:
			depth++;
			break;

			case CHAR_EOB:
			depth--;
			break;

		}
	} while(depth);
	// in case of skip, return now
	if(!store)
		return(NULL);
	// otherwise, prepare to return copy of block
	// add EOF, just to make sure block is never read too far
	DynaBuf_append(GlobalDynaBuf, CHAR_EOS);
	DynaBuf_append(GlobalDynaBuf, CHAR_EOF);
	// return pointer to copy
	return(DynaBuf_get_copy(GlobalDynaBuf));
}
Exemplo n.º 4
0
// Clear dynamic buffer, then append to it until an illegal (for a keyword)
// character is read. Zero-terminate the string. Return its length (without
// terminator).
// Zero lengths will produce a "missing string" error.
int Input_read_keyword(void) {
	int	length;

	DYNABUF_CLEAR(GlobalDynaBuf);
	length = Input_append_keyword_to_global_dynabuf();
	// add terminator to buffer (increments buffer's length counter)
	DynaBuf_append(GlobalDynaBuf, '\0');
	return(length);
}
Exemplo n.º 5
0
Arquivo: macro.c Projeto: lhz/acme
// Read macro zone and title. Title is read to GlobalDynaBuf and then copied
// over to internal_name DynaBuf, where ARG_SEPARATOR is added.
// In user_macro_name DynaBuf, the original name is reconstructed (even with
// LOCAL_PREFIX) so a copy can be linked to the resulting macro struct.
static zone_t get_zone_and_title(void)
{
    zone_t	macro_zone;

    Input_read_zone_and_keyword(&macro_zone);	// skips spaces before
    // now GotByte = illegal character after title
    // copy macro title to private dynabuf and add separator character
    DYNABUF_CLEAR(user_macro_name);
    DYNABUF_CLEAR(internal_name);
    if (macro_zone != ZONE_GLOBAL)
        DynaBuf_append(user_macro_name, LOCAL_PREFIX);
    DynaBuf_add_string(user_macro_name, GLOBALDYNABUF_CURRENT);
    DynaBuf_add_string(internal_name, GLOBALDYNABUF_CURRENT);
    DynaBuf_append(user_macro_name, '\0');
    DynaBuf_append(internal_name, ARG_SEPARATOR);
    SKIPSPACE();	// done here once so it's not necessary at two callers
    return macro_zone;
}
Exemplo n.º 6
0
// Try to read a file name. If "allow_library" is TRUE, library access by using
// <...> quoting is possible as well. The file name given in the assembler
// source code is converted from UNIX style to platform style.
// Returns whether error occurred (TRUE on error). Filename in GlobalDynaBuf.
// Errors are handled and reported, but caller should call
// Input_skip_remainder() then.
bool Input_read_filename(bool allow_library) {
	char	*lib_prefix,
		end_quote;

	DYNABUF_CLEAR(GlobalDynaBuf);
	SKIPSPACE();
	// check for library access
	if(GotByte == '<') {
		// if library access forbidden, complain
		if(allow_library == FALSE) {
			Throw_error("Writing to library not supported.");
			return(TRUE);
		}
		// read platform's lib prefix
		lib_prefix = PLATFORM_LIBPREFIX;
#ifndef NO_NEED_FOR_ENV_VAR
		// if lib prefix not set, complain
		if(lib_prefix == NULL) {
			Throw_error("\"ACME\" environment variable not found.");
			return(TRUE);
		}
#endif
		// copy lib path and set quoting char
		DynaBuf_add_string(GlobalDynaBuf, lib_prefix);
		end_quote = '>';
	} else {
		if(GotByte == '"')
			end_quote = '"';
		else {
			Throw_error("File name quotes not found (\"\" or <>).");
			return(TRUE);
		}
	}
	// read first character, complain if closing quote
	if(GetQuotedByte() == end_quote) {
		Throw_error("No file name given.");
		return(TRUE);
	}
	// read characters until closing quote (or EOS) is reached
	// append platform-converted characters to current string
	while((GotByte != CHAR_EOS) && (GotByte != end_quote)) {
		DYNABUF_APPEND(GlobalDynaBuf, PLATFORM_CONVERTPATHCHAR(GotByte));
		GetQuotedByte();
	}
	// on error, return
	if(GotByte == CHAR_EOS)
		return(TRUE);
	GetByte();	// fetch next to forget closing quote
	// terminate string
	DynaBuf_append(GlobalDynaBuf, '\0');	// add terminator
	return(FALSE);	// no error
}
Exemplo n.º 7
0
// fix name of anonymous forward label (held in DynaBuf, NOT TERMINATED!) so it
// references the *next* anonymous forward label definition. The tricky bit is,
// each name length would need its own counter. But hey, ACME's real quick in
// finding labels, so I'll just abuse the label system to store those counters.
struct label_t *Label_fix_forward_name(void)
{
	struct label_t	*counter_label;
	unsigned long	number;

	// terminate name, find "counter" label and read value
	DynaBuf_append(GlobalDynaBuf, '\0');
	counter_label = Label_find(Section_now->zone, 0);
	// make sure it gets reset to zero in each new pass
	if (counter_label->pass != pass_count) {
		counter_label->pass = pass_count;
		counter_label->result.val.intval = 0;
	}
	number = (unsigned long) counter_label->result.val.intval;
	// now append to the name to make it unique
	GlobalDynaBuf->size--;	// forget terminator, we want to append
	do {
		DYNABUF_APPEND(GlobalDynaBuf, 'a' + (number & 15));
		number >>= 4;
	} while (number);
	DynaBuf_append(GlobalDynaBuf, '\0');
	return counter_label;
}
Exemplo n.º 8
0
// show user-defined message
static enum eos_t throw_string(const char prefix[], void (*fn)(const char*)) {
	result_t	result;

	DYNABUF_CLEAR(user_message);
	DynaBuf_add_string(user_message, prefix);
	do {
		if(GotByte == '"') {
			// parse string
			GetQuotedByte();	// read initial character
			// send characters until closing quote is reached
			while(GotByte && (GotByte != '"')) {
				DYNABUF_APPEND(user_message, GotByte);
				GetQuotedByte();
			}
			if(GotByte == CHAR_EOS)
				return(AT_EOS_ANYWAY);
			// after closing quote, proceed with next char
			GetByte();
		} else {
			// parse value
			ALU_any_result(&result);
			if(result.flags & MVALUE_IS_FP) {
				// floating point
				if(result.flags & MVALUE_DEFINED)
					DynaBuf_add_double(
						user_message,
						result.val.fpval);
				else
					DynaBuf_add_string(
						user_message,
						"<UNDEFINED FLOAT>");
			} else {
				// integer
				if(result.flags & MVALUE_DEFINED)
					DynaBuf_add_signed_long(
						user_message,
						result.val.intval);
				else
					DynaBuf_add_string(
						user_message,
						"<UNDEFINED INT>");
			}
		}
	} while(Input_accept_comma());
	DynaBuf_append(user_message, '\0');
	fn(user_message->buffer);
	return(ENSURE_EOS);
}
Exemplo n.º 9
0
Arquivo: acme.c Projeto: Jedzia/acm3
// copy string to DynaBuf
static void keyword_to_dynabuf(const char keyword[]) {
	DYNABUF_CLEAR(GlobalDynaBuf);
	DynaBuf_add_string(GlobalDynaBuf, keyword);
	DynaBuf_append(GlobalDynaBuf, '\0');
	DynaBuf_to_lower(GlobalDynaBuf, GlobalDynaBuf);// convert to lower case
}
Exemplo n.º 10
0
Arquivo: macro.c Projeto: lhz/acme
// Parse macro call ("+MACROTITLE"). Has to be re-entrant.
void Macro_parse_call(void)	// Now GotByte = dot or first char of macro name
{
    char		local_gotbyte;
    struct symbol	*symbol;
    struct section	new_section,
                *outer_section;
    struct input	new_input,
                  *outer_input;
    struct macro	*actual_macro;
    struct rwnode	*macro_node,
                 *symbol_node;
    zone_t		macro_zone,
                symbol_zone;
    int		arg_count	= 0;

    // Enter deeper nesting level
    // Quit program if recursion too deep.
    if (--macro_recursions_left < 0)
        Throw_serious_error("Too deeply nested. Recursive macro calls?");
    macro_zone = get_zone_and_title();
    // now GotByte = first non-space after title
    // internal_name = MacroTitle ARG_SEPARATOR (grows to signature)
    // Accept n>=0 comma-separated arguments before CHAR_EOS.
    // Valid argument formats are:
    // EXPRESSION (everything that does NOT start with '~'
    // ~.LOCAL_LABEL_BY_REFERENCE
    // ~GLOBAL_LABEL_BY_REFERENCE
    // now GotByte = non-space
    if (GotByte != CHAR_EOS) {	// any at all?
        do {
            // if arg table cannot take another element, enlarge
            if (argtable_size <= arg_count)
                enlarge_arg_table();
            // Decide whether call-by-reference or call-by-value
            // In both cases, GlobalDynaBuf may be used.
            if (GotByte == REFERENCE_CHAR) {
                // read call-by-reference arg
                DynaBuf_append(internal_name, ARGTYPE_NUM_REF);
                GetByte();	// skip '~' character
                Input_read_zone_and_keyword(&symbol_zone);
                // GotByte = illegal char
                arg_table[arg_count].symbol = symbol_find(symbol_zone, 0);
            } else {
                // read call-by-value arg
                DynaBuf_append(internal_name, ARGTYPE_NUM_VAL);
                ALU_any_result(&(arg_table[arg_count].result));
            }
            ++arg_count;
        } while (Input_accept_comma());
    }
    // now arg_table contains the arguments
    // now GlobalDynaBuf = unused
    // check for "unknown macro"
    // Search for macro. Do not create if not found.
    search_for_macro(&macro_node, macro_zone, FALSE);
    if (macro_node == NULL) {
        Throw_error("Macro not defined (or wrong signature).");
        Input_skip_remainder();
    } else {
        // make macro_node point to the macro struct
        actual_macro = macro_node->body;
        local_gotbyte = GotByte;	// CAUTION - ugly kluge
        // set up new input
        new_input.original_filename = actual_macro->def_filename;
        new_input.line_number = actual_macro->def_line_number;
        new_input.source_is_ram = TRUE;
        new_input.state = INPUTSTATE_NORMAL;	// FIXME - fix others!
        new_input.src.ram_ptr = actual_macro->parameter_list;
        // remember old input
        outer_input = Input_now;
        // activate new input
        Input_now = &new_input;
        // remember old section
        outer_section = Section_now;
        // start new section (with new zone)
        // FALSE = title mustn't be freed
        Section_new_zone(&new_section, "Macro", actual_macro->original_name, FALSE);
        GetByte();	// fetch first byte of parameter list
        // assign arguments
        if (GotByte != CHAR_EOS) {	// any at all?
            arg_count = 0;
            do {
                // Decide whether call-by-reference
                // or call-by-value
                // In both cases, GlobalDynaBuf may be used.
                if (GotByte == REFERENCE_CHAR) {
                    // assign call-by-reference arg
                    GetByte();	// skip '~' character
                    Input_read_zone_and_keyword(&symbol_zone);
                    if ((Tree_hard_scan(&symbol_node, symbols_forest, symbol_zone, TRUE) == FALSE)
                            && (pass_count == 0))
                        Throw_error("Macro parameter twice.");
                    symbol_node->body = arg_table[arg_count].symbol;
                } else {
                    // assign call-by-value arg
                    Input_read_zone_and_keyword(&symbol_zone);
                    symbol = symbol_find(symbol_zone, 0);
// FIXME - add a possibility to symbol_find to make it possible to find out
// whether symbol was just created. Then check for the same error message here
// as above ("Macro parameter twice.").
                    symbol->result = arg_table[arg_count].result;
                }
                ++arg_count;
            } while (Input_accept_comma());
        }
        // and now, finally, parse the actual macro body
        Input_now->state = INPUTSTATE_NORMAL;	// FIXME - fix others!
// maybe call parse_ram_block(actual_macro->def_line_number, actual_macro->body)
        Input_now->src.ram_ptr = actual_macro->body;
        Parse_until_eob_or_eof();
        if (GotByte != CHAR_EOB)
            Bug_found("IllegalBlockTerminator", GotByte);
        // end section (free title memory, if needed)
        Section_finalize(&new_section);
        // restore previous section
        Section_now = outer_section;
        // restore previous input:
        Input_now = outer_input;
        // restore old Gotbyte context
        GotByte = local_gotbyte;	// CAUTION - ugly kluge
        Input_ensure_EOS();
    }
    ++macro_recursions_left;	// leave this nesting level
}
Exemplo n.º 11
0
Arquivo: macro.c Projeto: lhz/acme
// This function is only called during the first pass, so there's no need to
// check whether to skip the definition or not.
// Return with GotByte = '}'
void Macro_parse_definition(void)	// Now GotByte = illegal char after "!macro"
{
    char		*formal_parameters;
    struct rwnode	*macro_node;
    struct macro	*new_macro;
    zone_t		macro_zone	= get_zone_and_title();

    // now GotByte = first non-space after title
    DYNABUF_CLEAR(GlobalDynaBuf);	// prepare to hold formal parameters
    // GlobalDynaBuf = "" (will hold formal parameter list)
    // user_macro_name = [LOCAL_PREFIX] MacroTitle NUL
    // internal_name = MacroTitle ARG_SEPARATOR (grows to signature)
    // Accept n>=0 comma-separated formal parameters before CHAR_SOB ('{').
    // Valid argument formats are:
    // .LOCAL_LABEL_BY_VALUE
    // ~.LOCAL_LABEL_BY_REFERENCE
    // GLOBAL_LABEL_BY_VALUE	global args are very uncommon,
    // ~GLOBAL_LABEL_BY_REFERENCE	but not forbidden
    // now GotByte = non-space
    if (GotByte != CHAR_SOB) {	// any at all?
        do {
            // handle call-by-reference character ('~')
            if (GotByte != REFERENCE_CHAR) {
                DynaBuf_append(internal_name, ARGTYPE_NUM_VAL);
            } else {
                DynaBuf_append(internal_name, ARGTYPE_NUM_REF);
                DynaBuf_append(GlobalDynaBuf, REFERENCE_CHAR);
                GetByte();
            }
            // handle prefix for local symbols (LOCAL_PREFIX, normally '.')
            if (GotByte == LOCAL_PREFIX) {
                DynaBuf_append(GlobalDynaBuf, LOCAL_PREFIX);
                GetByte();
            }
            // handle symbol name
            Input_append_keyword_to_global_dynabuf();
        } while (pipe_comma());
        // ensure CHAR_SOB ('{')
        if (GotByte != CHAR_SOB)
            Throw_serious_error(exception_no_left_brace);
    }
    DynaBuf_append(GlobalDynaBuf, CHAR_EOS);	// terminate param list
    // now GlobalDynaBuf = comma-separated parameter list without spaces,
    // but terminated with CHAR_EOS.
    formal_parameters = DynaBuf_get_copy(GlobalDynaBuf);
    // now GlobalDynaBuf = unused
    // Reading the macro body would change the line number. To have correct
    // error messages, we're checking for "macro twice" *now*.
    // Search for macro. Create if not found.
    // But if found, complain (macro twice).
    if (search_for_macro(&macro_node, macro_zone, TRUE) == FALSE)
        report_redefinition(macro_node);	// quits with serious error
    // Create new macro struct and set it up. Finally we'll read the body.
    new_macro = safe_malloc(sizeof(*new_macro));
    new_macro->def_line_number = Input_now->line_number;
    new_macro->def_filename = get_string_copy(Input_now->original_filename);
    new_macro->original_name = get_string_copy(user_macro_name->buffer);
    new_macro->parameter_list = formal_parameters;
    new_macro->body = Input_skip_or_store_block(TRUE);	// changes LineNumber
    macro_node->body = new_macro;	// link macro struct to tree node
    // and that about sums it up
}