Beispiel #1
0
// Looping assembly ("!for"). Has to be re-entrant.
static enum eos_t PO_for(void) {// Now GotByte = illegal char
	input_t		loop_input,
			*outer_input;
	result_t	loop_counter;
	intval_t	maximum;
	char*		loop_body;// pointer to loop's body block
	label_t*	label;
	zone_t		zone;
	int		force_bit,
			loop_start;// line number of "!for" pseudo opcode

	if(Input_read_zone_and_keyword(&zone) == 0)	// skips spaces before
		return(SKIP_REMAINDER);
	// Now GotByte = illegal char
	force_bit = Input_get_force_bit();	// skips spaces after
	label = Label_find(zone, force_bit);
	if(Input_accept_comma() == FALSE) {
		Throw_error(exception_syntax);
		return(SKIP_REMAINDER);
	}
	maximum = ALU_defined_int();
	if(maximum < 0)
		Throw_serious_error("Loop count is negative.");
	if(GotByte != CHAR_SOB)
		Throw_serious_error(exception_no_left_brace);
	// remember line number of loop pseudo opcode
	loop_start = Input_now->line_number;
	// read loop body into DynaBuf and get copy
	loop_body = Input_skip_or_store_block(TRUE);	// changes line number!
	// switching input makes us lose GotByte. But we know it's '}' anyway!
	// set up new input
	loop_input = *Input_now;// copy current input structure into new
	loop_input.source_is_ram = TRUE;	// set new byte source
	// remember old input
	outer_input = Input_now;
	// activate new input
	// (not yet useable; pointer and line number are still missing)
	Input_now = &loop_input;
	// init counter
	loop_counter.flags = MVALUE_DEFINED | MVALUE_EXISTS;
	loop_counter.val.intval = 0;
	// if count == 0, skip loop
	if(maximum) {
		do {
			loop_counter.val.intval++;// increment counter
			Label_set_value(label, &loop_counter, TRUE);
			parse_ram_block(loop_start, loop_body);
		} while(loop_counter.val.intval < maximum);
	} else
		Label_set_value(label, &loop_counter, TRUE);
	// Free memory
	free(loop_body);
	// restore previous input:
	Input_now = outer_input;
	// GotByte of OuterInput would be '}' (if it would still exist)
	GetByte();	// fetch next byte
	return(ENSURE_EOS);
}
Beispiel #2
0
// Parse or skip a block. Returns whether block's '}' terminator was missing.
// Afterwards: GotByte = '}'
static bool skip_or_parse_block(bool parse) {
	if(!parse) {
		Input_skip_or_store_block(FALSE);
		return(FALSE);
	}
	// if block was correctly terminated, return FALSE
	Parse_until_eob_or_eof();
	// if block isn't correctly terminated, complain and exit
	if(GotByte != CHAR_EOB)
		Throw_serious_error(exception_no_right_brace);
	return(FALSE);
}
Beispiel #3
0
// Looping assembly ("!do"). Has to be re-entrant.
static enum eos_t PO_do(void) {	// Now GotByte = illegal char
	loopcond_t	condition1,
			condition2;
	input_t		loop_input,
			*outer_input;
	char*		loop_body;
	bool		go_on;
	int		loop_start;// line number of loop pseudo opcode

	// Read head condition to buffer
	SKIPSPACE();
	store_condition(&condition1, CHAR_SOB);
	if(GotByte != CHAR_SOB)
		Throw_serious_error(exception_no_left_brace);
	// Remember line number of loop body,
	// then read block and get copy
	loop_start = Input_now->line_number;
	loop_body = Input_skip_or_store_block(TRUE);	// changes line number!
	// now GotByte = '}'
	NEXTANDSKIPSPACE();// Now GotByte = first non-blank char after block
	// Read tail condition to buffer
	store_condition(&condition2, CHAR_EOS);
	// now GotByte = CHAR_EOS
	// set up new input
	loop_input = *Input_now;// copy current input structure into new
	loop_input.source_is_ram = TRUE;	// set new byte source
	// remember old input
	outer_input = Input_now;
	// activate new input (not useable yet, as pointer and
	// line number are not yet set up)
	Input_now = &loop_input;
	do {
		// Check head condition
		go_on = check_condition(&condition1);
		if(go_on) {
			parse_ram_block(loop_start, loop_body);
			// Check tail condition
			go_on = check_condition(&condition2);
		}
	} while(go_on);
	// Free memory
	free(condition1.body);
	free(loop_body);
	free(condition2.body);
	// restore previous input:
	Input_now = outer_input;
	GotByte = CHAR_EOS;	// CAUTION! Very ugly kluge.
	// But by switching input, we lost the outer input's GotByte. We know
	// it was CHAR_EOS. We could just call GetByte() to get real input, but
	// then the main loop could choke on unexpected bytes. So we pretend
	// that we got the outer input's GotByte value magically back.
	return(AT_EOS_ANYWAY);
}
Beispiel #4
0
// Macro definition ("!macro").
static enum eos_t PO_macro(void) {// Now GotByte = illegal char
	// In first pass, parse. In all other passes, skip.
	if(pass_count == 0)
		Macro_parse_definition();	// now GotByte = '}'
	else {
		// skip until CHAR_SOB ('{') is found.
		// no need to check for end-of-statement, because such an
		// error would already have been detected in first pass.
		// for the same reason, there is no need to check for quotes.
		while(GotByte != CHAR_SOB)
			GetByte();
		Input_skip_or_store_block(FALSE);	// now GotByte = '}'
	}
	GetByte();	// Proceed with next character
	return(ENSURE_EOS);
}
Beispiel #5
0
Datei: macro.c Projekt: 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
}