|
|
@@ -83,18 +83,76 @@ |
|
|
|
else FAIL_ON_COND_(true, ED_PP_UNKNOWN) |
|
|
|
|
|
|
|
/* |
|
|
|
Preprocess a single source line (source, length) into a normalized ASMLine. |
|
|
|
Return whether the given character is a valid label character. |
|
|
|
*/ |
|
|
|
static inline bool is_valid_label_char(char c, bool first) |
|
|
|
{ |
|
|
|
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || |
|
|
|
(!first && c >= '0' && c <= '9') || c == '_'; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
Preprocess a single source line for labels. |
|
|
|
|
|
|
|
Return the index of first non-whitespace non-label character. *head_ptr is |
|
|
|
updated to the first label in sequence, and *tail_ptr to the last. Both |
|
|
|
will be set to NULL if the line doesn't contain labels. |
|
|
|
*/ |
|
|
|
static size_t read_labels( |
|
|
|
const char *source, size_t length, ASMLine **head_ptr, ASMLine **tail_ptr) |
|
|
|
{ |
|
|
|
size_t start = 0, i, nexti; |
|
|
|
while (start < length && (source[start] == ' ' || source[start] == '\t')) |
|
|
|
start++; |
|
|
|
|
|
|
|
i = start; |
|
|
|
while (i < length && is_valid_label_char(source[i], i == start)) |
|
|
|
i++; |
|
|
|
|
|
|
|
if (i == start || i == length || source[i] != ':') { |
|
|
|
*head_ptr = NULL; |
|
|
|
*tail_ptr = NULL; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
ASMLine *line = malloc(sizeof(ASMLine)); |
|
|
|
if (!line) |
|
|
|
OUT_OF_MEMORY() |
|
|
|
|
|
|
|
line->data = malloc(sizeof(char) * (i - start + 1)); |
|
|
|
if (!line->data) |
|
|
|
OUT_OF_MEMORY() |
|
|
|
|
|
|
|
*Only* the data and length fields in the ASMLine object are populated. The |
|
|
|
normalization process converts tabs to spaces, lowercases all alphabetical |
|
|
|
characters, and removes runs of multiple spaces (outside of string |
|
|
|
literals), strips comments, and other things. |
|
|
|
strncpy(line->data, source + start, i - start + 1); |
|
|
|
line->length = i - start + 1; |
|
|
|
|
|
|
|
nexti = read_labels(source + i + 1, length - i - 1, &line->next, tail_ptr); |
|
|
|
*head_ptr = line; |
|
|
|
if (!nexti) |
|
|
|
*tail_ptr = line; |
|
|
|
return i + 1 + nexti; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
Preprocess a single source line (source, length) into one or more ASMLines. |
|
|
|
|
|
|
|
Only the data, length, and next fields of the ASMLine objects are |
|
|
|
populated. The normalization process strips comments, makes various |
|
|
|
adjustments outside of string literals (converts tabs to spaces, lowercases |
|
|
|
all alphabetical characters, and removes runs of multiple spaces), among |
|
|
|
other things. |
|
|
|
|
|
|
|
Return NULL if an ASM line was not generated from the source, i.e. if it is |
|
|
|
blank after being stripped. |
|
|
|
*/ |
|
|
|
static ASMLine* normalize_line(const char *source, size_t length) |
|
|
|
{ |
|
|
|
ASMLine *head, *tail; |
|
|
|
size_t offset = read_labels(source, length, &head, &tail); |
|
|
|
|
|
|
|
source += offset; |
|
|
|
length -= offset; |
|
|
|
|
|
|
|
char *data = malloc(sizeof(char) * length); |
|
|
|
if (!data) |
|
|
|
OUT_OF_MEMORY() |
|
|
@@ -138,7 +196,7 @@ static ASMLine* normalize_line(const char *source, size_t length) |
|
|
|
|
|
|
|
if (!has_content) { |
|
|
|
free(data); |
|
|
|
return NULL; |
|
|
|
return head; |
|
|
|
} |
|
|
|
|
|
|
|
ASMLine *line = malloc(sizeof(ASMLine)); |
|
|
@@ -151,6 +209,12 @@ static ASMLine* normalize_line(const char *source, size_t length) |
|
|
|
|
|
|
|
line->data = data; |
|
|
|
line->length = di; |
|
|
|
line->next = NULL; |
|
|
|
|
|
|
|
if (head) { // Line has labels, so link the main part up |
|
|
|
tail->next = line; |
|
|
|
return head; |
|
|
|
} |
|
|
|
return line; |
|
|
|
} |
|
|
|
|
|
|
@@ -240,19 +304,28 @@ static ErrorInfo* build_asm_lines( |
|
|
|
{ |
|
|
|
ErrorInfo *ei; |
|
|
|
ASMLine dummy = {.next = NULL}; |
|
|
|
ASMLine *line, *prev = &dummy; |
|
|
|
ASMLine *line, *prev = &dummy, *temp; |
|
|
|
const Line *orig, *next_orig = source->lines; |
|
|
|
|
|
|
|
while ((orig = next_orig)) { |
|
|
|
line = normalize_line(orig->data, orig->length); |
|
|
|
line = temp = normalize_line(orig->data, orig->length); |
|
|
|
next_orig = orig->next; |
|
|
|
if (!line) |
|
|
|
continue; |
|
|
|
|
|
|
|
// Populate ASMLine fields not set by normalize_line(): |
|
|
|
line->original = orig; |
|
|
|
line->filename = source->filename; |
|
|
|
line->next = NULL; |
|
|
|
while (temp) { |
|
|
|
temp->original = orig; |
|
|
|
temp->filename = source->filename; |
|
|
|
temp = temp->next; |
|
|
|
} |
|
|
|
|
|
|
|
// If there are multiple ASMLines, all but the last must be labels: |
|
|
|
while (line->next) { |
|
|
|
prev->next = line; |
|
|
|
prev = line; |
|
|
|
line = line->next; |
|
|
|
} |
|
|
|
|
|
|
|
if (IS_DIRECTIVE(line, DIR_INCLUDE)) { |
|
|
|
char *path = read_include_path(line); |
|
|
|