// 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)); }
// Check for comma. If there, append to GlobalDynaBuf. static int pipe_comma(void) { int result; result = Input_accept_comma(); if (result) DYNABUF_APPEND(GlobalDynaBuf, ','); return result; }
// 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 }
// Append to GlobalDynaBuf while characters are legal for keywords. // Throws "missing string" error if none. // Returns number of characters added. int Input_append_keyword_to_global_dynabuf(void) { int length = 0; // add characters to buffer until an illegal one comes along while(BYTEFLAGS(GotByte) & CONTS_KEYWORD) { DYNABUF_APPEND(GlobalDynaBuf, GotByte); length++; GetByte(); } if(length == 0) Throw_error(exception_missing_string); return(length); }
// Read bytes and add to GlobalDynaBuf until the given terminator (or CHAR_EOS) // is found. Act upon single and double quotes by entering (and leaving) quote // mode as needed (So the terminator does not terminate when inside quotes). void Input_until_terminator(char terminator) { char byte = GotByte; do { // Terminator? Exit. EndOfStatement? Exit. if((byte == terminator) || (byte == CHAR_EOS)) return; // otherwise, append to GlobalDynaBuf and check for quotes DYNABUF_APPEND(GlobalDynaBuf, byte); if((byte == '"') || (byte == '\'')) { do { // Okay, read quoted stuff. GetQuotedByte();// throws error on EOS DYNABUF_APPEND(GlobalDynaBuf, GotByte); } while((GotByte != CHAR_EOS) && (GotByte != byte)); // on error, exit now, before calling GetByte() if(GotByte != byte) return; } byte = GetByte(); } while(TRUE); }
// 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); }
// 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; }
// Append string to buffer (without terminator) void DynaBuf_add_string(dynabuf_t* db, const char* string) { char byte; while((byte = *string++)) DYNABUF_APPEND(db, byte); }
// add char to buffer void DynaBuf_append(dynabuf_t* db, char byte) { DYNABUF_APPEND(db, byte); }