From a5fdd83641a44037d28381570b32412d2d1417a1 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Fri, 26 May 2023 21:44:35 +0200 Subject: [PATCH 01/11] Add initial preprocessor macro support --- Makefile | 1 + src/avra.c | 163 +++++++++++++++++----- src/avra.h | 49 ++++++- src/directiv.c | 43 +----- src/expr.c | 2 +- src/parser.c | 362 +++++++++++++++++++++++++++++++++++++++++++++++-- src/stdextra.c | 18 +++ 7 files changed, 555 insertions(+), 83 deletions(-) diff --git a/Makefile b/Makefile index 1f10c59..b1ce953 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ TARGET_INCLUDE_PATH ?= $(PREFIX)/include/avr CDEFS = -DDEFAULT_INCLUDE_PATH='"$(TARGET_INCLUDE_PATH)"' \ -DVERSION='"$(VERSION)"' +CDEFS += $(USER_DEFS) export CDEFS .PHONY: all diff --git a/src/avra.c b/src/avra.c index 5aec61d..57f6471 100644 --- a/src/avra.c +++ b/src/avra.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "misc.h" @@ -35,8 +36,6 @@ #include "avra.h" #include "device.h" -#define debug 0 - const char *title = "AVRA: advanced AVR macro assembler (version %s)\n"; const char *usage = @@ -90,7 +89,7 @@ main(int argc, const char *argv[]) #if debug == 1 int i; for (i = 0; i < argc; i++) { - printf(argv[i]); + printf("%s", argv[i]); printf("\n"); } #endif @@ -259,42 +258,27 @@ assemble(struct prog_info *pi) int load_arg_defines(struct prog_info *pi) { - int i; - char *expr; - char buff[256]; struct data_list *define; + char *value; + char buff[256]; for (define = GET_ARG_LIST(pi->args, ARG_DEFINE); define; define = define->next) { +#if debug == 1 + printf("load_arg_defines opt \"%s\"\n", define->data); +#endif strcpy(buff, define->data); - expr = get_next_token(buff, TERM_EQUAL); - if (expr) { - /* we reach this, when there is actually a value passed.. */ - if (!get_expr(pi, expr, &i)) { + value = get_next_token(buff, TERM_EQUAL); + if (!value) + value = "1"; + if (pi->pass == PASS_1) { + if (test_preproc_macro(pi,buff,NULL)!=NULL) { + fprintf(stderr,"Error: Can't define preprocessor macro %s twice\n", buff); return (False); } - } else { - /* if user didnt specify a value, we default to 1 */ - i = 1; - } - /* Forward references allowed. But check, if everything is ok... */ - if (pi->pass==PASS_1) { /* Pass 1 */ - if (test_constant(pi,buff,NULL)!=NULL) { - fprintf(stderr,"Error: Can't define symbol %s twice\n", buff); + if (def_preproc_macro(pi, buff, PREPROC_MACRO_OBJECT_LIKE, NULL, value)==False) return (False); - } - if (def_const(pi, buff, i)==False) - return (False); - } else { /* Pass 2 */ - int j; - if (get_constant(pi, buff, &j)==False) { /* Defined in Pass 1 and now missing ? */ - fprintf(stderr,"Constant %s is missing in pass 2\n",buff); - return (False); - } - if (i != j) { - fprintf(stderr,"Constant %s changed value from %d in pass1 to %d in pass 2\n",buff,j,i); - return (False); - } - /* OK. Definition is unchanged */ + } else { + /* Pass 2 */ } } return (True); @@ -396,6 +380,7 @@ free_pi(struct prog_info *pi) free_ifdef_blacklist(pi); free_ifndef_blacklist(pi); free_orglist(pi); + free_preproc_macros(pi); } void @@ -871,6 +856,120 @@ free_orglist(struct prog_info *pi) pi->last_orglist = NULL; } +int +get_preproc_macro(struct prog_info *pi,char *name,struct preproc_macro **pm) +{ + struct preproc_macro *macro; + macro = search_preproc_macro(pi, pi->first_preproc_macro, name, NULL); + if (macro == NULL) return False; + if (pm != NULL) *pm = macro; + return True; +} + +struct preproc_macro * +test_preproc_macro(struct prog_info *pi,char *name,char *message) +{ + return search_preproc_macro(pi, pi->first_preproc_macro, name, message); +} + +struct preproc_macro * +search_preproc_macro(struct prog_info *pi,struct preproc_macro *first,char *name,char *message) +{ + struct preproc_macro *macro; + for (macro = first; macro; macro = macro->next) + if (!nocase_strcmp(macro->name, name)) { + if (message) { + print_msg(pi, MSGTYPE_ERROR, message, name); + } + return (macro); + } + return (NULL); +} + +int +def_preproc_macro(struct prog_info *pi, char *name, int type, struct item_list *params, char *value) { + struct preproc_macro *macro; + macro = malloc(sizeof(struct preproc_macro)); + if (!macro) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return (False); + } + memset(macro, 0, sizeof(struct preproc_macro)); + macro->name = malloc(strlen(name)+1); + if (!macro->name) { + free(macro); + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return (False); + } + strcpy(macro->name, name); + macro->type = type; + macro->params = params; + macro->value = malloc(strlen(value)+1); + if (!macro->value) { + free(macro->name); + free(macro); + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return (False); + } + strcpy(macro->value, value); + + if (pi->last_preproc_macro) + pi->last_preproc_macro->next = macro; + else + pi->first_preproc_macro = macro; + pi->last_preproc_macro = macro; + return (True); +} + +void +free_preproc_macros(struct prog_info *pi) +{ + struct preproc_macro *macro, *temp_macro; + struct item_list *param, *temp_param; + + for (macro = pi->first_preproc_macro; macro;) { + temp_macro = macro; + macro = macro->next; + + free(temp_macro->value); + if (temp_macro->type == PREPROC_MACRO_FUNCTION_LIKE) + for (param = temp_macro->params; param;) { + temp_param = param; + param = param->next; + free(temp_param->value); + free(temp_param); + } + free(temp_macro->name); + free(temp_macro); + } + + pi->first_preproc_macro = NULL; + pi->last_preproc_macro = NULL; +} + +/* Determine the length of an item list. */ +int +item_list_length(struct item_list *lst) +{ + int len; + if (!lst) + return (0); + for (len = 0; lst->next; lst = lst->next, len++); + return (len); +} + +/* Free up an item list. */ +void +free_item_list(struct item_list *lst) +{ + struct item_list *temp_lst; + while (lst) { + temp_lst = lst; + lst = lst->next; + free(temp_lst->value); + free(temp_lst); + } +} /* avra.c */ diff --git a/src/avra.h b/src/avra.h index 363d91f..f4a2b58 100644 --- a/src/avra.h +++ b/src/avra.h @@ -110,7 +110,24 @@ enum { TERM_EQUAL, TERM_DASH, TERM_DOUBLEQUOTE, - TERM_COLON + TERM_COLON, + TERM_CLOSING_PAREN +}; + +enum { + PREPROCESS_FATAL_ERROR = 0, + PREPROCESS_NEXT_LINE, + PREPROCESS_PARSE_LINE +}; + +enum { + PREPROC_MACRO_OBJECT_LIKE = 0, + PREPROC_MACRO_FUNCTION_LIKE +}; + +enum { + PREPROC_LINE_PART_WHITE = 0, + PREPROC_LINE_PART_GREY }; /* Structures */ @@ -157,6 +174,8 @@ struct prog_info { int error_count; int max_errors; int warning_count; + struct preproc_macro *first_preproc_macro; + struct preproc_macro *last_preproc_macro; struct include_file *last_include_file; struct include_file *first_include_file; struct def *first_def; @@ -273,6 +292,19 @@ struct location { int file_num; }; +struct item_list { + struct item_list *next; + char *value; +}; + +struct preproc_macro { + struct preproc_macro *next; + char *name; + int type; + struct item_list* params; + char *value; +}; + /* Prototypes */ /* avra.c */ int assemble(struct prog_info *pi); @@ -313,12 +345,26 @@ void free_ifdef_blacklist(struct prog_info *pi); void free_ifndef_blacklist(struct prog_info *pi); void free_variables(struct prog_info *pi); void free_orglist(struct prog_info *pi); +int get_preproc_macro(struct prog_info *pi,char *name,struct preproc_macro **pm); +struct preproc_macro *test_preproc_macro(struct prog_info *pi,char *name,char *message); +struct preproc_macro *search_preproc_macro(struct prog_info *pi,struct preproc_macro *first,char *name,char *message); +int def_preproc_macro(struct prog_info *pi, char *name, int type, struct item_list *params, char *value); +void free_preproc_macros(struct prog_info *pi); +int item_list_length(struct item_list *lst); +void free_item_list(struct item_list *lst); /* parser.c */ int parse_file(struct prog_info *pi, const char *filename); +int preprocess_line(struct prog_info *pi, char *line); int parse_line(struct prog_info *pi, char *line); char *get_next_token(char *scratch, int term); char *fgets_new(struct prog_info *pi, char *s, int size, FILE *stream); +char *funcall_token(char *token); +char *locate_macro_call(char *line, char *name, char **end); +char *locate_funcall_expr(char *line, char *name, char **end); +int is_label(char *word); +int collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **paramsargs, struct item_list **last_paramarg); +int inplace_replace(char *line, char *begin, char *end, char *value, int buff_len); /* expr.c */ int get_expr(struct prog_info *pi, char *data, int *value); @@ -378,6 +424,7 @@ int atoi_n(char *s, int n); int atox_n(char *s, int n); char *my_strlwr(char *in); char *my_strupr(char *in); +char *strdup_section(char *begin, char *end); char *snprint_list(char *buf, size_t limit, const char *const list[]); /* coff.c */ diff --git a/src/directiv.c b/src/directiv.c index 5627516..f91e6c5 100644 --- a/src/directiv.c +++ b/src/directiv.c @@ -533,45 +533,6 @@ parse_directive(struct prog_info *pi) if (test_constant(pi,next,"%s have already been defined as a .EQU constant")!=NULL) return (True); return (def_var(pi, next, i)); - case DIRECTIVE_DEFINE: - if (!next) { - print_msg(pi, MSGTYPE_ERROR, ".DEFINE needs an operand"); - return (True); - } - data = get_next_token(next, TERM_SPACE); - if (data) { - get_next_token(data, TERM_END); - if (!get_expr(pi, data, &i)) - return (False); - } else - i = 1; - if (test_label(pi,next,"%s have already been defined as a label")!=NULL) - return (True); - if (test_variable(pi,next,"%s have already been defined as a .SET variable")!=NULL) - return (True); - /* Forward references allowed. But check, if everything is ok ... */ - if (pi->pass==PASS_1) { /* Pass 1 */ - if (test_constant(pi,next,"Can't redefine constant %s, use .SET instead")!=NULL) - return (True); - if (def_const(pi, next, i)==False) - return (False); - } else { /* Pass 2 */ - int j; - if (get_constant(pi, next, &j)==False) { /* Defined in Pass 1 and now missing ? */ - print_msg(pi, MSGTYPE_ERROR, "Constant %s is missing in pass 2", next); - return (False); - } - if (i != j) { - print_msg(pi, MSGTYPE_ERROR, "Constant %s changed value from %d in pass1 to %d in pass 2", next,j,i); - return (False); - } - /* OK. Definition is unchanged */ - } - if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) { - fprintf(pi->list_file, " %s\n", pi->list_line); - pi->list_line = NULL; - } - break; case DIRECTIVE_NOOVERLAP: if (pi->pass == PASS_1) { fix_orglist(pi->segment); @@ -640,7 +601,7 @@ parse_directive(struct prog_info *pi) get_next_token(next, TERM_END); /* Store location of ifdef (line number and file number) if the condition * fails on pass 1 so that we do not reinterpret it as succeeding on pass 2. */ - if ((pi->pass==PASS_1 && get_symbol(pi, next, NULL)) || (pi->pass==PASS_2 && !ifdef_is_blacklisted(pi))) { + if ((pi->pass==PASS_1 && get_preproc_macro(pi, next, NULL)) || (pi->pass==PASS_2 && !ifdef_is_blacklisted(pi))) { pi->conditional_depth++; } else { if (pi->pass==PASS_1) { @@ -662,7 +623,7 @@ parse_directive(struct prog_info *pi) get_next_token(next, TERM_END); /* Store location of ifndef (line number and file number) if the condition * fails on pass 1 so that we do not reinterpret it as succeeding on pass 2. */ - if ((pi->pass==PASS_1 && !get_symbol(pi, next, NULL)) || (pi->pass==PASS_2 && !ifndef_is_blacklisted(pi))) { + if ((pi->pass==PASS_1 && !get_preproc_macro(pi, next, NULL)) || (pi->pass==PASS_2 && !ifndef_is_blacklisted(pi))) { pi->conditional_depth++; } else { if (pi->pass==PASS_1) { diff --git a/src/expr.c b/src/expr.c index 8d8baea..9e524e4 100644 --- a/src/expr.c +++ b/src/expr.c @@ -470,7 +470,7 @@ get_expr(struct prog_info *pi, char *data, int *value) break; } data[i + length++] = '\0'; - if (get_symbol(pi, &data[i], NULL)) + if (get_preproc_macro(pi, &data[i], NULL)) element->data = 1; else element->data = 0; diff --git a/src/parser.c b/src/parser.c index 710f1d6..27faa88 100644 --- a/src/parser.c +++ b/src/parser.c @@ -151,9 +151,9 @@ parse_file(struct prog_info *pi, const char *filename) fi->line_number++; pi->list_line = fi->buff; ok = parse_line(pi, fi->buff); -#if debug == 1 - printf("parse_line was %i\n", ok); -#endif +// #if debug == 1 +// printf("parse_line was %i\n", ok); +// #endif if (ok) { if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) fprintf(pi->list_file, " %s\n", pi->list_line); @@ -177,6 +177,195 @@ parse_file(struct prog_info *pi, const char *filename) return (ok); } +/* Preprocess one line. */ +int +preprocess_line(struct prog_info *pi, char *line) +{ + char *ptr, *next, *data, *param, *next_param; + int macro_type, len, params_cnt, args_cnt, macro_expanded; + struct item_list *params, *last_param, *args, *last_arg, *args_ptr; + struct preproc_macro *macro; + char *macro_begin, *macro_end, *par_begin, *par_end; + char *arg, *next_arg; + char temp[LINEBUFFER_LENGTH]; + + do { + macro_expanded = False; + params = NULL, args = NULL; + ptr = line; + + while (IS_HOR_SPACE(*ptr)) ptr++; + if (IS_END_OR_COMMENT(*ptr)) + return (PREPROCESS_NEXT_LINE); + if (ptr != line) + memmove(line, ptr, line+LINEBUFFER_LENGTH-1-ptr); + strcpy(temp, line); + + if (*temp == '#') { + next = get_next_token(temp, TERM_SPACE); + if (!nocase_strcmp(temp+1, "define")) { /* #define */ + /* #define name [value] */ + /* #define name(arg, ...) [value] */ + if (!next) { + print_msg(pi, MSGTYPE_ERROR, "#define needs an operand"); + return (PREPROCESS_NEXT_LINE); + } + /* Is it an object-like or a function-like macro? */ + param = funcall_token(next); + if (!param) { + /* Object-like macro definition */ + macro_type = PREPROC_MACRO_OBJECT_LIKE; + data = get_next_token(next, TERM_SPACE); + if (!data) + data = "1"; /* No value part provided, defaults to 1 */ + else + get_next_token(data, TERM_END); +#if debug == 1 + printf("preprocess_line obj next \"%s\" data \"%s\"\n", next, data); +#endif + } else { + /* Function-like macro definition */ +#if debug == 1 + printf("preprocess_line fun next \"%s\"\n", next); +#endif + macro_type = PREPROC_MACRO_FUNCTION_LIKE; + /* Collect params */ + while ((next_param = get_next_token(param, TERM_COMMA))) { +#if debug == 1 + printf("preprocess_line fun param \"%s\"\n", param); +#endif + if (!is_label(param)) { + print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid parameter %s", next, param); + return (PREPROCESS_NEXT_LINE); + } + if (!collect_paramarg(pi, param, ¶ms, &last_param)) + return (PREPROCESS_FATAL_ERROR); + param = next_param; + } + data = get_next_token(param, TERM_CLOSING_PAREN); + if (!data) { + print_msg(pi, MSGTYPE_ERROR, "Fuction-like macro %s misses value", next); + return (PREPROCESS_NEXT_LINE); + } else + get_next_token(data, TERM_END); + if (!*param) { + print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s misses a parameter", next); + return (PREPROCESS_NEXT_LINE); + } +#if debug == 1 + printf("preprocess_line fun param \"%s\"\n", param); + printf("preprocess_line fun data \"%s\"\n", data); +#endif + if (!is_label(param)) { + print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid parameter %s", next, param); + return (PREPROCESS_NEXT_LINE); + } + if (!collect_paramarg(pi, param, ¶ms, &last_param)) + return (PREPROCESS_FATAL_ERROR); + } + if (pi->pass == PASS_1) { + if (test_preproc_macro(pi, next, "Preprocessor macro %s has already been defined") != NULL) + return (PREPROCESS_NEXT_LINE); + if (def_preproc_macro(pi, next, macro_type, params, data) == False) + return (PREPROCESS_FATAL_ERROR); + } else { + /* Pass 2 */ + } + if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) { + fprintf(pi->list_file, " %s\n", pi->list_line); + pi->list_line = NULL; + } + return (PREPROCESS_NEXT_LINE); + } else if (!nocase_strcmp(temp+1, "undef")) { /* #undef */ + print_msg(pi, MSGTYPE_ERROR, "#undef is not supported at the moment"); + return (PREPROCESS_NEXT_LINE); + } else { + /* Rest of the preprocessor macros to be handled by the original code */ + } + } else { + /* Expand preprocessor macros */ + for (macro = pi->first_preproc_macro; macro;) { + if (macro->type == PREPROC_MACRO_OBJECT_LIKE) { + while ((macro_begin = locate_macro_call(line, macro->name, ¯o_end))) { + if (!inplace_replace(line, macro_begin, macro_end, macro->value, LINEBUFFER_LENGTH)) { + print_msg(pi, MSGTYPE_ERROR, "Expanded macro %s with value %s too big", macro->name, macro->value); + return (PREPROCESS_NEXT_LINE); + } + macro_expanded = True; + } + } else { + /* Function like macro */ + while ((macro_begin = locate_funcall_expr(line, macro->name, ¯o_end))) { + arg = strdup_section(macro_begin + strlen(macro->name) +1, macro_end); + if (!arg) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return (PREPROCESS_FATAL_ERROR); + } + /* Collect args */ + while ((next_arg = get_next_token(arg, TERM_COMMA))) { + if (!is_label(arg)) { + print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid argument %s", macro->name, arg); + return (PREPROCESS_NEXT_LINE); + } + if (!collect_paramarg(pi, arg, &args, &last_arg)) + return (PREPROCESS_FATAL_ERROR); + arg = next_arg; + } + get_next_token(arg, TERM_CLOSING_PAREN); + if (!*arg) { + print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s misses an argument", macro->name); + return (PREPROCESS_NEXT_LINE); + } + if (!is_label(arg)) { + print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid argument %s", macro->name, arg); + return (PREPROCESS_NEXT_LINE); + } + if (!collect_paramarg(pi, arg, &args, &last_arg)) + return (PREPROCESS_FATAL_ERROR); + /* Parameter vs. argument list length check */ + params_cnt = item_list_length(macro->params); + args_cnt = item_list_length(args); + if (params_cnt != args_cnt) { + print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s called with %d arguments, however is defined with %d parameters", macro->name, args_cnt, params_cnt); + return (PREPROCESS_NEXT_LINE); + } + strcpy(temp, macro->value); +#if debug == 1 + printf("preprocess_line temp \"%s\"\n", temp); +#endif + for (params = macro->params, args_ptr = args; params; params = params->next, args_ptr = args_ptr->next) { + while ((par_begin = locate_macro_call(temp, params->value, &par_end))) { + if (!inplace_replace(temp, par_begin, par_end, args_ptr->value, LINEBUFFER_LENGTH)) { + print_msg(pi, MSGTYPE_ERROR, "Expanded macro parameter %s with value %s too big", params->value, args_ptr->value); + return (PREPROCESS_NEXT_LINE); + } +#if debug == 1 + printf("preprocess_line temp \"%s\"\n", temp); +#endif + } + } + free_item_list(args); +#if debug == 1 + printf("preprocess_line line (before replace) \"%s\"\n", line); +#endif + if (!inplace_replace(line, macro_begin, macro_end, temp, LINEBUFFER_LENGTH)) { + print_msg(pi, MSGTYPE_ERROR, "Expanded macro %s with value %s too big", macro->name, temp); + return (PREPROCESS_NEXT_LINE); + } +#if debug == 1 + printf("preprocess_line line (after replace) \"%s\"\n", line); +#endif + macro_expanded = True; + } + } + macro = macro->next; + } + } + + } while (macro_expanded); + return (PREPROCESS_PARSE_LINE); +} + /* Parse one line. */ int parse_line(struct prog_info *pi, char *line) @@ -190,17 +379,25 @@ parse_line(struct prog_info *pi, char *line) struct macro_call *macro_call; int len; - while (IS_HOR_SPACE(*line)) line++; /* At first remove leading spaces / tabs */ - if (IS_END_OR_COMMENT(*line)) /* Skip comment line or empty line */ - return (True); + /* Preprocess the line. */ + switch (preprocess_line(pi, line)) { + case PREPROCESS_PARSE_LINE: + break; + case PREPROCESS_NEXT_LINE: + return (True); + default: + case PREPROCESS_FATAL_ERROR: + return (False); + } + /* Filter out .stab debugging information */ /* .stabs sometimes contains colon : symbol - might be interpreted as label */ if (*line == '.') { /* minimal slowdown of existing code */ - if (strncmp(temp,".stabs ",7) == 0) { /* compiler output is always lower case */ + if (strncmp(line,".stabs ",7) == 0) { /* compiler output is always lower case */ strcpy(temp,line); /* TODO : Do we need this temp variable ? Please check */ return parse_stabs(pi, temp); } - if (strncmp(temp,".stabn ",7) == 0) { + if (strncmp(line,".stabn ",7) == 0) { strcpy(temp,line); return parse_stabn(pi, temp); } @@ -361,6 +558,10 @@ get_next_token(char *data, int term) /* Skip to next equals or EOL or start of comment. */ while ((data[i] != '=') && !IS_END_OR_COMMENT(data[i])) i++; break; + case TERM_CLOSING_PAREN: + /* Skip to next ) or EOL or start of comment. */ + while ((data[i] != ')') && !IS_END_OR_COMMENT(data[i])) i++; + break; } /* If we hit EOL or a comment, return null. */ if (IS_END_OR_COMMENT(data[i])) { @@ -386,5 +587,150 @@ get_next_token(char *data, int term) return (&data[i]); } +/* Check whether the pointed token is a function call. + * If so, terminate the name and return a pointer to the next token or end. */ +char * +funcall_token(char *token) { + if (*token != '%' && *token != '_' && !isalpha(*token)) return NULL; + while (IS_LABEL(*token)) token++; + if (*token == '(') { + *token++ = '\0'; /* Null-out paren, so we get the name */ + while (IS_HOR_SPACE(*token)) token++; /* Skip whitespace after paren */ + return (token); /* Return a pointer to the next token or end */ + } + return (NULL); +} + +/* Locate the first occurence of a macro call in a line. + * Intended to be called repetitively to exhaust all possibilities. + * Returns NULL in case there is no occurence. + * Otherwise returns the pointer to the beginning of the macro call and sets the end ptr.*/ +char * +locate_macro_call(char *line, char *name, char **end) +{ + char *macro_call, *macro_call_end, *comment, *ptr; + char *funcall_begin, *funcall_end; + int name_len, inside_defined; + comment = strchr(line, ';'); + name_len = strlen(name); + while (1) { + macro_call = nocase_strstr(line, name); + if (!macro_call) + return (NULL); + if (comment && comment < macro_call) + return (NULL); + macro_call_end = macro_call + name_len - 1; + if (macro_call == line || IS_END_OR_COMMENT(*(macro_call_end + 1))) + break; + if (IS_LABEL(*(macro_call - 1)) || IS_LABEL(*(macro_call_end + 1))) { + while (IS_LABEL(*macro_call_end)) macro_call_end++; + line = macro_call_end; + continue; + } + ptr = line; + inside_defined = False; + while (!inside_defined && + (funcall_begin = locate_funcall_expr(ptr, "defined", &funcall_end))) { + if (funcall_begin < macro_call && macro_call_end < funcall_end) + inside_defined = True; + ptr = funcall_end + 1; + } + if (!inside_defined) + break; + line = funcall_end + 1; + } + if (end) *end = macro_call_end; + return (macro_call); +} + +/* Locate the first occurence of the function call expression in a line. + * Intended to be called repetitively to exhaust all possibilities. + * Returns NULL in case there is no occurence. + * Otherwise returns the pointer to the beginning of the expr. and sets the end ptr.*/ +char * +locate_funcall_expr(char *line, char *name, char **end) +{ + char *expr, *expr_end, *comment, *ptr; + int len; + expr = nocase_strstr(line, name); + if (expr) { + ptr = expr + strlen(name); + if (*ptr == '(') { + len = par_length(ptr + 1); + if (len >= 0) { + expr_end = ptr + 1 + len; + comment = strchr(line, ';'); + if (!comment || expr_end < comment) { + if (expr == line || !IS_LABEL(*(expr - 1))) { + if (end) *end = expr_end; + return (expr); + } + } + } + } + } + return (NULL); +} + +/* Checks whether the given word is a label. + * Returns true, when it is a label. False otherwise. */ +int +is_label(char *word) +{ + if (word == NULL) + return (False); + do { + if (!IS_LABEL(*word)) + return (False); + } while(*++word); + return (True); +} + +/* Collect parameters or arguments into the supplied list. + * Signals error and returns False in case of memory full. */ +int +collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **paramsargs, struct item_list **last_paramarg) +{ + struct item_list *new_paramarg; + new_paramarg = malloc(sizeof(struct item_list)); + if (!new_paramarg) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return (False); + } + new_paramarg->next = NULL; + new_paramarg->value = malloc(strlen(paramarg)+1); + if (!new_paramarg->value) { + print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); + return (False); + } + strcpy(new_paramarg->value, paramarg); + + if (!*paramsargs) { + *paramsargs = new_paramarg; + *last_paramarg = new_paramarg; + } else { + (*last_paramarg)->next = new_paramarg; + *last_paramarg = new_paramarg; + } + return (True); +} + +/* Replace the range of characters in line between begin and end with value. + * Returns False in case the result would not fit into the line buffer. */ +int +inplace_replace(char *line, char *begin, char *end, char *value, int buff_len) +{ + int value_len, rest_len, range_len; + value_len = strlen(value); + rest_len = strlen(end + 1); + range_len = end - begin +1; + if (strlen(line) +1 - range_len + value_len > buff_len) + return (False); + if (range_len != value_len) + memmove(begin + value_len, end + 1, rest_len + 1); + memmove(begin, value, value_len); + return (True); +} + /* end of parser.c */ diff --git a/src/stdextra.c b/src/stdextra.c index 968618e..238c83c 100644 --- a/src/stdextra.c +++ b/src/stdextra.c @@ -27,6 +27,8 @@ #include #include +#include +#include #include "misc.h" @@ -157,6 +159,22 @@ my_strupr(char *in) return (in); } +/* Create a dynamically allocated duplicate of the section pointed by begin and end. + * Returns the pointer the duplicate or NULL when no memory. + * Begin and end must be pointers to a section within the same string. */ +char * +strdup_section(char *begin, char *end) +{ + char *dup; + size_t len = end - begin +1; + dup = malloc(len +1); + if (!dup) + return (NULL); + strncpy(dup, begin, len); + dup[len] = '\0'; + return (dup); +} + static int snprint(char **buf, size_t *limit, const char *const str) { From 8e93dcf2c1e6f7d5408d87ed5aead62cc05db7c4 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Fri, 26 May 2023 21:47:10 +0200 Subject: [PATCH 02/11] Update version number --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index b1ce953..712c07e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ OS = linux -VERSION = 1.4.2 +VERSION = 1.4.2b DISTFILES = src \ includes \ From acee686ce348b9fbcee51301200df7a7c6c347d2 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Sat, 27 May 2023 00:22:10 +0200 Subject: [PATCH 03/11] Add concatenation operator --- src/avra.h | 1 + src/parser.c | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/avra.h b/src/avra.h index f4a2b58..c90ca11 100644 --- a/src/avra.h +++ b/src/avra.h @@ -365,6 +365,7 @@ char *locate_funcall_expr(char *line, char *name, char **end); int is_label(char *word); int collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **paramsargs, struct item_list **last_paramarg); int inplace_replace(char *line, char *begin, char *end, char *value, int buff_len); +void apply_preproc_macro_opers(char *line); /* expr.c */ int get_expr(struct prog_info *pi, char *data, int *value); diff --git a/src/parser.c b/src/parser.c index 27faa88..18352e7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -346,14 +346,18 @@ preprocess_line(struct prog_info *pi, char *line) } free_item_list(args); #if debug == 1 - printf("preprocess_line line (before replace) \"%s\"\n", line); + printf("preprocess_line line (before inplace_replace) \"%s\"\n", line); #endif if (!inplace_replace(line, macro_begin, macro_end, temp, LINEBUFFER_LENGTH)) { print_msg(pi, MSGTYPE_ERROR, "Expanded macro %s with value %s too big", macro->name, temp); return (PREPROCESS_NEXT_LINE); } #if debug == 1 - printf("preprocess_line line (after replace) \"%s\"\n", line); + printf("preprocess_line line (after inplace_replace) \"%s\"\n", line); +#endif + apply_preproc_macro_opers(line); +#if debug == 1 + printf("preprocess_line line (after apply_preproc_macro_opers) \"%s\"\n", line); #endif macro_expanded = True; } @@ -732,5 +736,19 @@ inplace_replace(char *line, char *begin, char *end, char *value, int buff_len) return (True); } +/* Apply the preprocessor macro operators. */ +void +apply_preproc_macro_opers(char *line) +{ + char *begin, *end; + + while ((begin = strstr(line, "##"))) { /* Apply Concatenation (##) operator */ + end = begin + 2; + while (begin - 1 > line && IS_HOR_SPACE(*(begin - 1))) begin--; + while (IS_HOR_SPACE(*end)) end++; + memmove(begin, end, strlen(end) + 1); + } +} + /* end of parser.c */ From 7fbea54c7cb48db6f1ae3f9ddc8042527cb9c038 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Sat, 27 May 2023 00:41:27 +0200 Subject: [PATCH 04/11] Add regression test --- tests/regression/preprocessor-macros/test.asm | 14 ++++++++++++++ .../preprocessor-macros/test.hex.expected | 3 +++ 2 files changed, 17 insertions(+) create mode 100644 tests/regression/preprocessor-macros/test.asm create mode 100644 tests/regression/preprocessor-macros/test.hex.expected diff --git a/tests/regression/preprocessor-macros/test.asm b/tests/regression/preprocessor-macros/test.asm new file mode 100644 index 0000000..d126587 --- /dev/null +++ b/tests/regression/preprocessor-macros/test.asm @@ -0,0 +1,14 @@ +.device atmega328p + +#define EIGHT (1 << 3) +#define SQR(X) ((X)*(X)) + +ldi r16, EIGHT +ldi r16, SQR(4) + +#define FOOBAR subi +#define IMMED(X) X##i +#define SUBI(X,Y) X ## Y + +IMMED(ld) r16, 1 +SUBI(FOO, BAR) r16, 1 diff --git a/tests/regression/preprocessor-macros/test.hex.expected b/tests/regression/preprocessor-macros/test.hex.expected new file mode 100644 index 0000000..aadb8e6 --- /dev/null +++ b/tests/regression/preprocessor-macros/test.hex.expected @@ -0,0 +1,3 @@ +:020000020000FC +:0800000008E000E101E00150FD +:00000001FF From 4877ef74bf480aa6d14efd8d1f884a129b8ef7d3 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Mon, 29 May 2023 15:56:06 +0200 Subject: [PATCH 05/11] Remove unused local variable --- src/parser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.c b/src/parser.c index 18352e7..2356439 100644 --- a/src/parser.c +++ b/src/parser.c @@ -182,7 +182,7 @@ int preprocess_line(struct prog_info *pi, char *line) { char *ptr, *next, *data, *param, *next_param; - int macro_type, len, params_cnt, args_cnt, macro_expanded; + int macro_type, params_cnt, args_cnt, macro_expanded; struct item_list *params, *last_param, *args, *last_arg, *args_ptr; struct preproc_macro *macro; char *macro_begin, *macro_end, *par_begin, *par_end; From e348d4210ef76fd8a666b64c992b1e23992397e8 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Mon, 29 May 2023 16:06:58 +0200 Subject: [PATCH 06/11] Fix memory leak --- src/parser.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/parser.c b/src/parser.c index 2356439..19a06e3 100644 --- a/src/parser.c +++ b/src/parser.c @@ -186,7 +186,7 @@ preprocess_line(struct prog_info *pi, char *line) struct item_list *params, *last_param, *args, *last_arg, *args_ptr; struct preproc_macro *macro; char *macro_begin, *macro_end, *par_begin, *par_end; - char *arg, *next_arg; + char *arg_mem, *arg, *next_arg; char temp[LINEBUFFER_LENGTH]; do { @@ -296,14 +296,15 @@ preprocess_line(struct prog_info *pi, char *line) } else { /* Function like macro */ while ((macro_begin = locate_funcall_expr(line, macro->name, ¯o_end))) { - arg = strdup_section(macro_begin + strlen(macro->name) +1, macro_end); - if (!arg) { + arg_mem = arg = strdup_section(macro_begin + strlen(macro->name) +1, macro_end); + if (!arg_mem) { print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); return (PREPROCESS_FATAL_ERROR); } /* Collect args */ while ((next_arg = get_next_token(arg, TERM_COMMA))) { if (!is_label(arg)) { + free(arg_mem); print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid argument %s", macro->name, arg); return (PREPROCESS_NEXT_LINE); } @@ -313,15 +314,18 @@ preprocess_line(struct prog_info *pi, char *line) } get_next_token(arg, TERM_CLOSING_PAREN); if (!*arg) { + free(arg_mem); print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s misses an argument", macro->name); return (PREPROCESS_NEXT_LINE); } if (!is_label(arg)) { + free(arg_mem); print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid argument %s", macro->name, arg); return (PREPROCESS_NEXT_LINE); } if (!collect_paramarg(pi, arg, &args, &last_arg)) return (PREPROCESS_FATAL_ERROR); + free(arg_mem); /* Parameter vs. argument list length check */ params_cnt = item_list_length(macro->params); args_cnt = item_list_length(args); From d79491b7a2d595bd58fd935a4b2634f11afac7a6 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Mon, 29 May 2023 19:48:18 +0200 Subject: [PATCH 07/11] Reinstate assembler directive functionality --- src/directiv.c | 4 ++-- src/expr.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/directiv.c b/src/directiv.c index f91e6c5..b1745da 100644 --- a/src/directiv.c +++ b/src/directiv.c @@ -601,7 +601,7 @@ parse_directive(struct prog_info *pi) get_next_token(next, TERM_END); /* Store location of ifdef (line number and file number) if the condition * fails on pass 1 so that we do not reinterpret it as succeeding on pass 2. */ - if ((pi->pass==PASS_1 && get_preproc_macro(pi, next, NULL)) || (pi->pass==PASS_2 && !ifdef_is_blacklisted(pi))) { + if ((pi->pass==PASS_1 && (get_preproc_macro(pi, next, NULL) || get_symbol(pi, next, NULL))) || (pi->pass==PASS_2 && !ifdef_is_blacklisted(pi))) { pi->conditional_depth++; } else { if (pi->pass==PASS_1) { @@ -623,7 +623,7 @@ parse_directive(struct prog_info *pi) get_next_token(next, TERM_END); /* Store location of ifndef (line number and file number) if the condition * fails on pass 1 so that we do not reinterpret it as succeeding on pass 2. */ - if ((pi->pass==PASS_1 && !get_preproc_macro(pi, next, NULL)) || (pi->pass==PASS_2 && !ifndef_is_blacklisted(pi))) { + if ((pi->pass==PASS_1 && (!get_preproc_macro(pi, next, NULL) && !get_symbol(pi, next, NULL))) || (pi->pass==PASS_2 && !ifndef_is_blacklisted(pi))) { pi->conditional_depth++; } else { if (pi->pass==PASS_1) { diff --git a/src/expr.c b/src/expr.c index 9e524e4..3fa202f 100644 --- a/src/expr.c +++ b/src/expr.c @@ -470,7 +470,7 @@ get_expr(struct prog_info *pi, char *data, int *value) break; } data[i + length++] = '\0'; - if (get_preproc_macro(pi, &data[i], NULL)) + if (get_preproc_macro(pi, &data[i], NULL) || get_symbol(pi, &data[i], NULL)) element->data = 1; else element->data = 0; From cc749fed3d6729d265fd9032f1291dc5b664a6cb Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Tue, 30 May 2023 11:51:28 +0200 Subject: [PATCH 08/11] Fix bugs --- src/avra.c | 9 +-- src/avra.h | 2 +- src/parser.c | 66 ++++++++++--------- tests/regression/preprocessor-macros/test.asm | 3 + .../preprocessor-macros/test.hex.expected | 2 +- 5 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/avra.c b/src/avra.c index 57f6471..fabd5ec 100644 --- a/src/avra.c +++ b/src/avra.c @@ -951,10 +951,11 @@ free_preproc_macros(struct prog_info *pi) int item_list_length(struct item_list *lst) { - int len; - if (!lst) - return (0); - for (len = 0; lst->next; lst = lst->next, len++); + int len = 0; + while (lst) { + len++; + lst = lst->next; + } return (len); } diff --git a/src/avra.h b/src/avra.h index c90ca11..bdac2a1 100644 --- a/src/avra.h +++ b/src/avra.h @@ -363,7 +363,7 @@ char *funcall_token(char *token); char *locate_macro_call(char *line, char *name, char **end); char *locate_funcall_expr(char *line, char *name, char **end); int is_label(char *word); -int collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **paramsargs, struct item_list **last_paramarg); +int collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **first_paramarg, struct item_list **last_paramarg); int inplace_replace(char *line, char *begin, char *end, char *value, int buff_len); void apply_preproc_macro_opers(char *line); diff --git a/src/parser.c b/src/parser.c index 19a06e3..cb4cb58 100644 --- a/src/parser.c +++ b/src/parser.c @@ -183,7 +183,7 @@ preprocess_line(struct prog_info *pi, char *line) { char *ptr, *next, *data, *param, *next_param; int macro_type, params_cnt, args_cnt, macro_expanded; - struct item_list *params, *last_param, *args, *last_arg, *args_ptr; + struct item_list *params, *first_param, *last_param, *first_arg, *last_arg, *args_ptr; struct preproc_macro *macro; char *macro_begin, *macro_end, *par_begin, *par_end; char *arg_mem, *arg, *next_arg; @@ -191,7 +191,6 @@ preprocess_line(struct prog_info *pi, char *line) do { macro_expanded = False; - params = NULL, args = NULL; ptr = line; while (IS_HOR_SPACE(*ptr)) ptr++; @@ -230,6 +229,7 @@ preprocess_line(struct prog_info *pi, char *line) #endif macro_type = PREPROC_MACRO_FUNCTION_LIKE; /* Collect params */ + first_param = last_param = NULL; while ((next_param = get_next_token(param, TERM_COMMA))) { #if debug == 1 printf("preprocess_line fun param \"%s\"\n", param); @@ -238,7 +238,7 @@ preprocess_line(struct prog_info *pi, char *line) print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid parameter %s", next, param); return (PREPROCESS_NEXT_LINE); } - if (!collect_paramarg(pi, param, ¶ms, &last_param)) + if (!collect_paramarg(pi, param, &first_param, &last_param)) return (PREPROCESS_FATAL_ERROR); param = next_param; } @@ -260,13 +260,13 @@ preprocess_line(struct prog_info *pi, char *line) print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid parameter %s", next, param); return (PREPROCESS_NEXT_LINE); } - if (!collect_paramarg(pi, param, ¶ms, &last_param)) + if (!collect_paramarg(pi, param, &first_param, &last_param)) return (PREPROCESS_FATAL_ERROR); } if (pi->pass == PASS_1) { if (test_preproc_macro(pi, next, "Preprocessor macro %s has already been defined") != NULL) return (PREPROCESS_NEXT_LINE); - if (def_preproc_macro(pi, next, macro_type, params, data) == False) + if (def_preproc_macro(pi, next, macro_type, first_param, data) == False) return (PREPROCESS_FATAL_ERROR); } else { /* Pass 2 */ @@ -286,6 +286,7 @@ preprocess_line(struct prog_info *pi, char *line) /* Expand preprocessor macros */ for (macro = pi->first_preproc_macro; macro;) { if (macro->type == PREPROC_MACRO_OBJECT_LIKE) { + /* Object-like macro */ while ((macro_begin = locate_macro_call(line, macro->name, ¯o_end))) { if (!inplace_replace(line, macro_begin, macro_end, macro->value, LINEBUFFER_LENGTH)) { print_msg(pi, MSGTYPE_ERROR, "Expanded macro %s with value %s too big", macro->name, macro->value); @@ -294,41 +295,46 @@ preprocess_line(struct prog_info *pi, char *line) macro_expanded = True; } } else { - /* Function like macro */ + /* Function-like macro */ while ((macro_begin = locate_funcall_expr(line, macro->name, ¯o_end))) { - arg_mem = arg = strdup_section(macro_begin + strlen(macro->name) +1, macro_end); + if (pi->pass == PASS_2 && pi->list_line && pi->list_on) { + fprintf(pi->list_file, "%c:%06lx + %s\n", + pi->cseg->ident, pi->cseg->addr, pi->list_line); + // pi->list_line = NULL; + } + arg_mem = arg = strdup_section(macro_begin + strlen(macro->name) +1, macro_end-1); if (!arg_mem) { print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL); return (PREPROCESS_FATAL_ERROR); } +#if debug == 1 + printf("preprocess_line arg \"%s\"\n", arg); +#endif /* Collect args */ + first_arg = last_arg = NULL; while ((next_arg = get_next_token(arg, TERM_COMMA))) { +#if debug == 1 + printf("preprocess_line arg 1+ \"%s\"\n", arg); +#endif if (!is_label(arg)) { - free(arg_mem); print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid argument %s", macro->name, arg); + free(arg_mem); return (PREPROCESS_NEXT_LINE); } - if (!collect_paramarg(pi, arg, &args, &last_arg)) + if (!collect_paramarg(pi, arg, &first_arg, &last_arg)) return (PREPROCESS_FATAL_ERROR); arg = next_arg; } - get_next_token(arg, TERM_CLOSING_PAREN); - if (!*arg) { - free(arg_mem); - print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s misses an argument", macro->name); - return (PREPROCESS_NEXT_LINE); - } - if (!is_label(arg)) { - free(arg_mem); - print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s with invalid argument %s", macro->name, arg); - return (PREPROCESS_NEXT_LINE); - } - if (!collect_paramarg(pi, arg, &args, &last_arg)) + get_next_token(arg, TERM_END); +#if debug == 1 + printf("preprocess_line arg 1 \"%s\"\n", arg); +#endif + if (!collect_paramarg(pi, arg, &first_arg, &last_arg)) return (PREPROCESS_FATAL_ERROR); free(arg_mem); /* Parameter vs. argument list length check */ params_cnt = item_list_length(macro->params); - args_cnt = item_list_length(args); + args_cnt = item_list_length(first_arg); if (params_cnt != args_cnt) { print_msg(pi, MSGTYPE_ERROR, "Function-like macro %s called with %d arguments, however is defined with %d parameters", macro->name, args_cnt, params_cnt); return (PREPROCESS_NEXT_LINE); @@ -337,7 +343,7 @@ preprocess_line(struct prog_info *pi, char *line) #if debug == 1 printf("preprocess_line temp \"%s\"\n", temp); #endif - for (params = macro->params, args_ptr = args; params; params = params->next, args_ptr = args_ptr->next) { + for (params = macro->params, args_ptr = first_arg; params; params = params->next, args_ptr = args_ptr->next) { while ((par_begin = locate_macro_call(temp, params->value, &par_end))) { if (!inplace_replace(temp, par_begin, par_end, args_ptr->value, LINEBUFFER_LENGTH)) { print_msg(pi, MSGTYPE_ERROR, "Expanded macro parameter %s with value %s too big", params->value, args_ptr->value); @@ -348,7 +354,7 @@ preprocess_line(struct prog_info *pi, char *line) #endif } } - free_item_list(args); + free_item_list(first_arg); #if debug == 1 printf("preprocess_line line (before inplace_replace) \"%s\"\n", line); #endif @@ -697,7 +703,7 @@ is_label(char *word) /* Collect parameters or arguments into the supplied list. * Signals error and returns False in case of memory full. */ int -collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **paramsargs, struct item_list **last_paramarg) +collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **first_paramarg, struct item_list **last_paramarg) { struct item_list *new_paramarg; new_paramarg = malloc(sizeof(struct item_list)); @@ -713,13 +719,11 @@ collect_paramarg(struct prog_info *pi, char *paramarg, struct item_list **params } strcpy(new_paramarg->value, paramarg); - if (!*paramsargs) { - *paramsargs = new_paramarg; - *last_paramarg = new_paramarg; - } else { + if (*last_paramarg) (*last_paramarg)->next = new_paramarg; - *last_paramarg = new_paramarg; - } + else + *first_paramarg = new_paramarg; + *last_paramarg = new_paramarg; return (True); } diff --git a/tests/regression/preprocessor-macros/test.asm b/tests/regression/preprocessor-macros/test.asm index d126587..6777943 100644 --- a/tests/regression/preprocessor-macros/test.asm +++ b/tests/regression/preprocessor-macros/test.asm @@ -12,3 +12,6 @@ ldi r16, SQR(4) IMMED(ld) r16, 1 SUBI(FOO, BAR) r16, 1 + +#define REGN(N) r##N +ldi REGN(16), SQR(4) diff --git a/tests/regression/preprocessor-macros/test.hex.expected b/tests/regression/preprocessor-macros/test.hex.expected index aadb8e6..e6faf4d 100644 --- a/tests/regression/preprocessor-macros/test.hex.expected +++ b/tests/regression/preprocessor-macros/test.hex.expected @@ -1,3 +1,3 @@ :020000020000FC -:0800000008E000E101E00150FD +:0A00000008E000E101E0015000E11A :00000001FF From bfd2845fe5a9bf5b2d9adf9d81cfc2c5d1a8ac2c Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Tue, 30 May 2023 16:51:30 +0200 Subject: [PATCH 09/11] Update regression test --- tests/regression/preprocessor-macros/test.asm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/regression/preprocessor-macros/test.asm b/tests/regression/preprocessor-macros/test.asm index 6777943..422ec2e 100644 --- a/tests/regression/preprocessor-macros/test.asm +++ b/tests/regression/preprocessor-macros/test.asm @@ -13,5 +13,4 @@ ldi r16, SQR(4) IMMED(ld) r16, 1 SUBI(FOO, BAR) r16, 1 -#define REGN(N) r##N -ldi REGN(16), SQR(4) +IMMED(ld) r16, SQR(SQR(1+1)) From a16a2f684ad004627c41004ea4156939037145cb Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Thu, 1 Jun 2023 01:31:41 +0200 Subject: [PATCH 10/11] Refactor some code to improve clarity --- src/avra.c | 8 +------- src/parser.c | 30 ++++++++++++++++++------------ 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/avra.c b/src/avra.c index fabd5ec..5af6bce 100644 --- a/src/avra.c +++ b/src/avra.c @@ -925,7 +925,6 @@ void free_preproc_macros(struct prog_info *pi) { struct preproc_macro *macro, *temp_macro; - struct item_list *param, *temp_param; for (macro = pi->first_preproc_macro; macro;) { temp_macro = macro; @@ -933,12 +932,7 @@ free_preproc_macros(struct prog_info *pi) free(temp_macro->value); if (temp_macro->type == PREPROC_MACRO_FUNCTION_LIKE) - for (param = temp_macro->params; param;) { - temp_param = param; - param = param->next; - free(temp_param->value); - free(temp_param); - } + free_item_list(temp_macro->params); free(temp_macro->name); free(temp_macro); } diff --git a/src/parser.c b/src/parser.c index cb4cb58..934c0d9 100644 --- a/src/parser.c +++ b/src/parser.c @@ -182,7 +182,7 @@ int preprocess_line(struct prog_info *pi, char *line) { char *ptr, *next, *data, *param, *next_param; - int macro_type, params_cnt, args_cnt, macro_expanded; + int params_cnt, args_cnt, macro_expanded; struct item_list *params, *first_param, *last_param, *first_arg, *last_arg, *args_ptr; struct preproc_macro *macro; char *macro_begin, *macro_end, *par_begin, *par_end; @@ -213,7 +213,6 @@ preprocess_line(struct prog_info *pi, char *line) param = funcall_token(next); if (!param) { /* Object-like macro definition */ - macro_type = PREPROC_MACRO_OBJECT_LIKE; data = get_next_token(next, TERM_SPACE); if (!data) data = "1"; /* No value part provided, defaults to 1 */ @@ -222,12 +221,19 @@ preprocess_line(struct prog_info *pi, char *line) #if debug == 1 printf("preprocess_line obj next \"%s\" data \"%s\"\n", next, data); #endif + if (pi->pass == PASS_1) { + if (test_preproc_macro(pi, next, "Preprocessor macro %s has already been defined") != NULL) + return (PREPROCESS_NEXT_LINE); + if (def_preproc_macro(pi, next, PREPROC_MACRO_OBJECT_LIKE, NULL, data) == False) + return (PREPROCESS_FATAL_ERROR); + } else { + /* Pass 2 */ + } } else { /* Function-like macro definition */ #if debug == 1 printf("preprocess_line fun next \"%s\"\n", next); #endif - macro_type = PREPROC_MACRO_FUNCTION_LIKE; /* Collect params */ first_param = last_param = NULL; while ((next_param = get_next_token(param, TERM_COMMA))) { @@ -262,20 +268,20 @@ preprocess_line(struct prog_info *pi, char *line) } if (!collect_paramarg(pi, param, &first_param, &last_param)) return (PREPROCESS_FATAL_ERROR); - } - if (pi->pass == PASS_1) { - if (test_preproc_macro(pi, next, "Preprocessor macro %s has already been defined") != NULL) - return (PREPROCESS_NEXT_LINE); - if (def_preproc_macro(pi, next, macro_type, first_param, data) == False) - return (PREPROCESS_FATAL_ERROR); - } else { - /* Pass 2 */ + if (pi->pass == PASS_1) { + if (test_preproc_macro(pi, next, "Preprocessor macro %s has already been defined") != NULL) + return (PREPROCESS_NEXT_LINE); + if (def_preproc_macro(pi, next, PREPROC_MACRO_FUNCTION_LIKE, first_param, data) == False) + return (PREPROCESS_FATAL_ERROR); + } else { + /* Pass 2 */ + } } if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) { fprintf(pi->list_file, " %s\n", pi->list_line); pi->list_line = NULL; } - return (PREPROCESS_NEXT_LINE); + return (PREPROCESS_NEXT_LINE); /* #define successfully parsed, continue with next line */ } else if (!nocase_strcmp(temp+1, "undef")) { /* #undef */ print_msg(pi, MSGTYPE_ERROR, "#undef is not supported at the moment"); return (PREPROCESS_NEXT_LINE); From 1c8bef06452de9b4f8b784f96a0798559a9a4166 Mon Sep 17 00:00:00 2001 From: Imre Horvath Date: Sat, 10 Jun 2023 13:47:51 +0200 Subject: [PATCH 11/11] Update commented out lines to be C style --- src/parser.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/parser.c b/src/parser.c index 934c0d9..08fb6ed 100644 --- a/src/parser.c +++ b/src/parser.c @@ -151,9 +151,9 @@ parse_file(struct prog_info *pi, const char *filename) fi->line_number++; pi->list_line = fi->buff; ok = parse_line(pi, fi->buff); -// #if debug == 1 -// printf("parse_line was %i\n", ok); -// #endif +/*#if debug == 1 + printf("parse_line was %i\n", ok); +#endif*/ if (ok) { if ((pi->pass == PASS_2) && pi->list_line && pi->list_on) fprintf(pi->list_file, " %s\n", pi->list_line);