diff options
author | Pixel <> | 2001-04-15 01:15:02 +0000 |
---|---|---|
committer | Pixel <> | 2001-04-15 01:15:02 +0000 |
commit | 1d2c4bd4e380395c68151d40239d1539d39fdd91 (patch) | |
tree | 5d257d14007c3a67ac716c01c8334878483c3697 /lib/assembler.c | |
parent | a984cf3f28d3a5935c84f96f6da3bc7bd39a9ff1 (diff) |
Assembleur
Diffstat (limited to 'lib/assembler.c')
-rw-r--r-- | lib/assembler.c | 705 |
1 files changed, 655 insertions, 50 deletions
diff --git a/lib/assembler.c b/lib/assembler.c index 2a3bb86..60fe86f 100644 --- a/lib/assembler.c +++ b/lib/assembler.c @@ -1,6 +1,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> #include "config.h" #include "meta.h" @@ -30,13 +31,13 @@ typedef struct expression_t { typedef struct bytestream_t { unsigned long int Encoded; int offset, segment, size; - char * Label; - expression_t * Expr; + char *Label; + expression_t *Expr; - struct bytestream_t * next; + struct bytestream_t *next; int line; - char * filename; + char *filename; } bytestream_t; enum { @@ -61,26 +62,75 @@ int segment = -1; int special = 0; _TableauVariable defines, labels; int line = -1; -char * filename = NULL, * filenames[32]; +char *filename = NULL, *filenames[32], *defined; int nestedinc = 0; -bytestream_t * text, * data, * bss, * p_text, * p_data, * p_bss; +bytestream_t *text, *data, *bss, *p_text, *p_data, *p_bss; int s_text = 0, s_data = 0, s_bss = 0; -expression_t *copy_expression(expression_t * e); +static void debug_print_expression(expression_t * e) +{ + switch (e->e_subtype) { + case E_OPERATION: + switch (e->op) { + case OP_PLUS: + fprintf(stderr, "Operation plus\n"); + break; + case OP_MOINS: + fprintf(stderr, "Operation moins\n"); + break; + case OP_DECAL: + fprintf(stderr, "Operation decal\n"); + break; + case OP_DIRECT: + fprintf(stderr, "Operation direct\n"); + break; + default: + fprintf(stderr, "Operation diverse...\n"); + break; + } + debug_print_expression(e->child); + fprintf(stderr, "--\n"); + break; + case E_VALUE: + fprintf(stderr, "Valeur: %li\n", e->avalue); + break; + case E_LABEL: + fprintf(stderr, "Label: %s\n", e->symbol); + break; + case E_STRING: + fprintf(stderr, "String: %s\n", e->symbol); + break; + case E_PATTERN: + fprintf(stderr, "Pattern: %s, index %i\n", e->pattern->name, e->index); + break; + case E_INTERNAL: + fprintf(stderr, "Instruction interne: %s\n", e->symbol); + break; + case E_INSTRUCT: + fprintf(stderr, "Instruction: %s\n", e->symbol); + break; + } + if (e->next) { + debug_print_expression(e->next); + } +} + +static expression_t *copy_expression(expression_t * e); + +static bytestream_t *pushuninit(int size) +{ + bytestream_t *s; -static bytestream_t * pushuninit(int size) { - bytestream_t * s; - s = (bytestream_t *) Emalloc(sizeof(bytestream_t)); s->next = NULL; s->Encoded = 0; - s->segment = segment + s->segment = segment; s->size = size; s->Label = NULL; s->Expr = NULL; - s->line = line + s->line = line; s->filename = filenames[nestedinc]; @@ -103,51 +153,57 @@ static bytestream_t * pushuninit(int size) { p_bss = s; s_bss += size; break; - + } - + return s; } -static bytestream_t * pushdword(unsigned long int d, expression_t * e) { - bytestream_t * s; +static bytestream_t *pushdword(unsigned long int d, expression_t * e) +{ + bytestream_t *s; - if ((segment <= 0) || (segment >= 1)) { + if ((segment < 0) || (segment > 1)) { exception(1, _("You have to be into the .text or the .data segment to define a value.")); } - + s = pushuninit(1); s->Encoded = d; if (e) { - s->Expr = copyexpression(e); + s->Expr = copy_expression(e); } - + return s; } -static bytestream_t * pushlabel(char * label) { - bytestream_t * s; +static bytestream_t *pushlabel(char *label) +{ + bytestream_t *s; char trouve; s = pushuninit(0); s->Label = Estrdup(label); - + NomVarToVar(label, labels, &trouve); - + if (trouve) { exception(1, _("Label already defined")); } + InsererVarDansTab(&labels, CreerElement(label, s)); + return s; } -static void pushstring(char * s) { - char marker = *s, valid, tstring[6]; - +static void pushstring(char *s) +{ + char marker = *s, tstring[6]; + int valid; + while ((*s) && (marker != *s)) { if (*s == '\\') { s++; - switch(*s) { + switch (*s) { case '0': pushdword('\0', NULL); break; @@ -184,11 +240,11 @@ static void pushstring(char * s) { break; } } else { - pushdword(s, NULL); + pushdword(*s, NULL); } s++; } - + } static void pushstart(void) @@ -246,6 +302,10 @@ static void free_expr(expression_t * e) free_expr(e->next); } + if (e->symbol) { + free(e->symbol); + } + free(e); } @@ -372,6 +432,7 @@ void push_pile(char *a) break; case 2: /* Cas de #define */ if (wc == 1) { + defined = Estrdup(a); break; } case 0: /* Cas normal */ @@ -416,7 +477,7 @@ void push_pile(char *a) /* Cas des pseudos instructions {DB, DW, DD, DS} */ - if (wc == 1) { + if (wc <= 1) { trouve = 0; switch (downcase(*a)) { case 'd': @@ -424,9 +485,13 @@ void push_pile(char *a) trouve = 1; switch (downcase(*(a + 1))) { case 'b': + e->op = 1; case 'w': + e->op = 2; case 'd': + e->op = 3; case 's': + e->op = 4; break; default: trouve = 0; @@ -435,7 +500,9 @@ void push_pile(char *a) } if (trouve) { e->e_subtype = E_INTERNAL; - e->prev->e_subtype = E_LABEL; + if (e->prev) { + e->prev->e_subtype = E_LABEL; + } } } @@ -455,7 +522,9 @@ void push_pile(char *a) /* Dans tous les autres cas, nous considerons qu'il s'agit d'une référence à un label... */ if (e->e_subtype == E_STRING) { - e->e_subtype = E_LABEL; + if ((e->symbol[0] != '\"') && (e->symbol[0] != '\'')) { + e->e_subtype = E_LABEL; + } } e_current = e; @@ -491,6 +560,7 @@ void push_pile(char *a) {'-', 2, OP_MOINS}, {'*', 3, OP_MUL}, {'/', 3, OP_DIV}, + {'%', 3, OP_MOD}, {'+' + 128, 4, OP_PLUS_UNARY}, {'-' + 128, 4, OP_MOINS_UNARY}, {'(', 5, OP_FUNC_CALL}, @@ -512,6 +582,7 @@ static void evaluate(expression_t * e) case OP_MOINS: case OP_MUL: case OP_DIV: + case OP_MOD: if ((e->child->e_subtype == E_VALUE) && (e->child->next->e_subtype == E_VALUE)) { switch (e->op) { case OP_PLUS: @@ -529,6 +600,12 @@ static void evaluate(expression_t * e) } e->avalue = e->child->avalue / e->child->next->avalue; break; + case OP_MOD: + if (!e->child->next->avalue) { + exception(1, _("Zero divide.")); + } + e->avalue = e->child->avalue % e->child->next->avalue; + break; } free(e->child->next); free(e->child); @@ -581,6 +658,15 @@ static void evaluate(expression_t * e) if (e->child->next->child->e_subtype == e->child->next->child->next->e_subtype) { exception(1, _("Expression too complex or invalid")); } + /* On veut obtenir quelque chose sous la forme LABEL[VALUE + PATTERN] */ + if (e->child->next->child->e_subtype == E_PATTERN) { + t = e->child->next->child; + e->child->next->child = t->next; + t->next->prev = NULL; + t->next->next = t; + t->prev = t->next; + t->next = NULL; + } } break; case OP_DIRECT: @@ -592,7 +678,8 @@ static void evaluate(expression_t * e) | Nous la modifierons au fur et a mesure de sorte à lui donner une | | forme canonique afin de pouvoir la traiter correctement plus tard | \*******************************************************************/ - if (e->child->e_subtype == E_OPERATION) { + switch (e->child->e_subtype) { + case E_OPERATION: if (!((e->child->op == OP_PLUS) || (e->child->op == OP_MOINS))) { exception(1, _("Address operation invalid")); } @@ -850,10 +937,16 @@ static void evaluate(expression_t * e) break; } } else { - /* Le pire, c'est que je vois même pas comment on peut atterir ici... - J'ai beau me creuser les méninges, je vois pas :) - On va donc dire que c'est invalide */ - exception(1, _("Expression too complex")); + /* Bon si l'on est ici, c'est que l'on est dans le cas [PATTERN + VALUE] + ou [VALUE + PATTERN]. On se met sur la forme [VALUE + PATTERN] */ + if (e->child->child->e_subtype == E_PATTERN) { + t = e->child->child; + e->child->child = t->next; + t->next->prev = NULL; + t->next->next = t; + t->prev = t->next; + t->next = NULL; + } } } /* Bon si on arrive ici sain et sauf, c'est que l'expression est sous la forme @@ -870,11 +963,21 @@ static void evaluate(expression_t * e) } free(t); e->op = OP_DECAL; - - } /* if operation */ + break; /* case OPERATION */ + case E_LABEL: + /* On est sous la forme [LABEL], on va mettre sous la forme LABEL[0] */ + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_VALUE; + t->avalue = 0; + t->next = t->child = NULL; + t->prev = e->child; + e->child->next = t; + t->father = e; + e->op = OP_DECAL; + break; + } break; } - } void act_pile(int o) @@ -897,15 +1000,18 @@ void act_pile(int o) case OP_MOINS: case OP_MUL: case OP_DIV: + case OP_MOD: case OP_DECAL: - e2 = e_current; e1 = e_current->prev; + e2 = e_current; if (e_current->prev->prev) { e_current->prev->prev->next = NULL; + e_current = e1->prev; } else { e_current = NULL; } e1->prev = NULL; + e2->next = NULL; e->child = e1; e1->father = e2->father = e; break; @@ -983,29 +1089,495 @@ int assembler_init(void) Initialise(&labels); if (!defines) return 1; - if (!(p_text = text = (bytestream_t *) malloc(sizeof(bytestream_t)))) return 1; - if (!(p_data = data = (bytestream_t *) malloc(sizeof(bytestream_t)))) return 1; - if (!(p_bss = bss = (bytestream_t *) malloc(sizeof(bytestream_t)))) return 1; - + if (!(p_text = text = (bytestream_t *) malloc(sizeof(bytestream_t)))) + return 1; + if (!(p_data = data = (bytestream_t *) malloc(sizeof(bytestream_t)))) + return 1; + if (!(p_bss = bss = (bytestream_t *) malloc(sizeof(bytestream_t)))) + return 1; + text->next = data->next = bss->next = NULL; text->size = data->size = bss->size = 0; return 0; } +static void super_pattern(pattern_t * patterns, expression_t * e) +{ + int i; + + if (!(e->e_subtype == E_OPERATION)) + return; + if (!((e->op == OP_DECAL) || (e->op == OP_DIRECT))) + return; + + for (patterns = patterns->next; patterns; patterns = patterns->next) { + for (i = 0; i < patterns->nbr; i++) { + if (!patterns->expr[i]->name) { + if (e->e_subtype == E_OPERATION) { + if (e->op == OP_DIRECT) { + if (!patterns->expr[i]->left) { + e->pattern = patterns; + e->index = i; + } + } else { + if (patterns->expr[i]->left) { + e->pattern = patterns; + e->index = i; + } + } + } + } else { + if (patterns->expr[i]->string) { + if (patterns->expr[i]->string[0] == 'O') { + if (e->e_subtype == E_OPERATION) { + if (((e->op == OP_DIRECT) && (e->child->e_subtype == E_VALUE)) + || ((e->op == OP_DECAL) + && (e->child->next->e_subtype = E_VALUE))) { + e->pattern = patterns; + e->index = i; + } + } else { + if (e->e_subtype == E_LABEL) { + e->pattern = patterns; + e->index = i; + } + } + } + } + } + } + } +} + +static int islabel(expression_t *); + +static int islabel2(expression_t * e) +{ + if (islabel(e)) + return 1; + if (e->next) { + return islabel2(e->next); + } + return 0; +} + +static int islabel(expression_t * e) +{ + if (e->e_subtype == E_LABEL) + return 1; + if (e->child) { + return islabel2(e->child); + } + return 0; +} + +static instruct_t *e_match_i(phon_t * phons, instruct_t * instructs, expression_t * e) +{ + char *stringtolook = e->symbol; + expression_t *t; + int i, go_out; + + for (t = e->next; t; t = t->next) { + if (!t->pattern) + super_pattern(patterns, t); + } + + for (phons = phons->next; phons; phons = phons->next) { + if (!strcasecmp(phons->p1, stringtolook)) { + stringtolook = phons->p2; + break; + } + } + + for (instructs = instructs->next; instructs; instructs = instructs->next) { + t = e; + go_out = 0; + for (i = 0; (!go_out) && (i < instructs->nbexplicit); i++) { + if (!instructs->strings[i]) { + if (strcasecmp(instructs->names[i], i ? t->symbol : stringtolook)) { + go_out = 1; + } else + fprintf(stderr, "On a reconnu le mot %s au %i eme mot\n", t->symbol, i); + } else { + switch (instructs->strings[i][0]) { + case 'P': + if (!t->pattern) { + fprintf(stderr, + "On a une pattern sur le mot %i, mais pas dans l'instruction...\n", + i); + go_out = 1; + } else { + fprintf(stderr, + "On a la pattern %s sur le mot %i, on la compare avec %s\n", + instructs->strings[i] + 1, i, t->pattern->name); + if (strcasecmp(instructs->strings[i] + 1, t->pattern->name)) + go_out = 1; + else + fprintf(stderr, "Ok, on ne sort pas.\n"); + } + break; + case 'C': + if (t->e_subtype != E_VALUE) { + go_out = 1; + if (t->e_subtype == E_OPERATION) { + if (t->op == OP_FUNC_CALL) + go_out = 0; + } + } + break; + case 'o': + /* Pour que quelque chose soit absolu, il nous suffit d'avoir un label dans l'expression */ + if (!islabel(t)) + go_out = 1; + break; + case 'O': + /* C'est le cas le plus simple ou presque, il suffit de tout prendre */ + break; + default: + exception(1, _("Unknow predefined string into the meta language")); + } + } + + if (!(t = t->next) && ((i + 1) < instructs->nbexplicit)) { + go_out = 1; + fprintf(stderr, "On sort quand même... (t = %p et i = %i)\n", t, i); + } + } + + if (!go_out) { + break; + } + } + + if (instructs) { + fprintf(stderr, "Nous avons reconnu une instruction:\n"); + fprintf(stderr, " o Instruction contenant %i champs explicites et %i champs implicites.\n", + instructs->nbexplicit, instructs->nbimplicit); + fprintf(stderr, " => Champs explicites.\n"); + for (i = 0; i < instructs->nbexplicit; i++) { + fprintf(stderr, " + %s <= %s (type %s)\n", + instructs->names[i], + instructs->strings[i] ? instructs->strings[i] : "Pas de chaîne associée", + instructs->etypes[i] ? "prédéfinit" : "direct"); + } + fprintf(stderr, " => Champs implicites.\n"); + for (i = 0; i < instructs->nbimplicit; i++) { + switch (instructs->itypes[i]) { + case 0: + fprintf(stderr, " + %s <= %s (type direct)\n", instructs->implicits[i], + instructs->istrings[i]); + break; + case 1: + fprintf(stderr, " + %s <= %s (type prédéfinit)\n", instructs->implicits[i], + instructs->istrings[i]); + break; + case 2: + fprintf(stderr, " + %s <= %i (type valeur)\n", instructs->implicits[i], + instructs->ivalues[i]); + break; + } + } + } else { + fprintf(stderr, "Nous n'avons pas reconnu l'instruction.\n"); + } + + return instructs; +} + +static void evaluate_pattern(_TableauVariable * it, expression_t * e) +{ + metaexpr_t *m; + expression_t *t; + + if (!e->pattern) { + exception(1, _("Pattern not matching...")); + } + + m = e->pattern->expr[e->index]; + + switch (e->e_subtype) { + case E_OPERATION: + switch (e->op) { + case OP_DECAL: + /* On est sous la forme LABEL[VALEUR + PATTERN] au pire */ + switch (e->child->next->e_subtype) { + case E_OPERATION: + /* Et voila on y est... */ + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_VALUE; + t->avalue = e->child->next->child->next->index; + t->next = t->child = NULL; + + InsererVarDansTab(it, CreerElement(m->string, t)); + free(t); + + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_LABEL; + t->avalue = 0; + t->next = t->child = NULL; + t->symbol = Estrdup(e->child->symbol); + + pushdword(e->child->next->child->avalue, t); + free(t); + break; + case E_VALUE: + /* Sous la forme LABEL[VALEUR] */ + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_LABEL; + t->avalue = 0; + t->next = t->child = NULL; + t->symbol = Estrdup(e->child->symbol); + + pushdword(e->child->next->avalue, t); + free(t); + break; + case E_PATTERN: + /* Sous la forme LABEL[PATTERN] */ + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_VALUE; + t->avalue = e->child->next->index; + t->next = t->child = NULL; + + InsererVarDansTab(it, CreerElement(m->string, t)); + free(t); + + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_LABEL; + t->avalue = 0; + t->next = t->child = NULL; + t->symbol = Estrdup(e->child->symbol); + + pushdword(0, t); + free(t); + break; + default: + exception(1, _("Pattern not matching...")); + break; + } + break; + case OP_DIRECT: + switch (e->child->e_subtype) { + case E_OPERATION: + /* Sous la forme [VALUE + PATTERN] */ + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_VALUE; + t->avalue = e->child->child->next->index; + t->next = t->child = NULL; + + InsererVarDansTab(it, CreerElement(m->string, t)); + free(t); + + pushdword(e->child->child->avalue, NULL); + break; + case E_VALUE: + /* Sous la forme [VALUE] */ + pushdword(e->child->avalue, NULL); + break; + case E_PATTERN: + /* Sous la forme [PATTERN] */ + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_VALUE; + t->avalue = e->child->child->next->index; + t->next = t->child = NULL; + + InsererVarDansTab(it, CreerElement(m->string, t)); + free(t); + + pushdword(e->child->child->avalue, NULL); + break; + default: + exception(1, _("Pattern not matching...")); + break; + } + break; + default: + exception(1, _("Pattern not matching...")); + break; + } + break; + case E_PATTERN: + break; + default: + exception(1, _("Pattern not matching...")); + break; + } +} + void asm_eol(void) { - /* Gros morceau encore ici... */ + instruct_t *instr; + expression_t *t; + int i; + bytestream_t *pi; + _TableauVariable it; + + switch (special) { + case 2: /* Cas de #define */ + InsererVarDansTab(&defines, CreerElement(defined, e_line)); + free(defined); + break; + case 1: /* Cas des directives . */ + case 3: /* Cas de #undef */ + case 4: /* Cas de #include */ + /* Rien à faire ici... tout est déjà fait dans la routine push_pile() */ + break; + case 0: /* Cas normal */ + /* C'est ici la bonne histoire... Il faut reconnaitre l'instruction */ + + fprintf(stderr, "Fin de ligne sur:\n"); + debug_print_expression(e_line); + + e_current = e_line; + /* Est-ce que le premier mot est un label terminant par ':' ? */ + if (e_current->e_subtype == E_LABEL) { + if (e_current->symbol[strlen(e_current->symbol) - 1] == ':') { + pushlabel(e_current->symbol); + e_line = e_current->next; + e_current->next = NULL; + free_expr(e_current); + e_current = e_line; + } else { + /* C'est peut-être une instruction spéciale */ + if ((e_current->next) && (e_current->next->e_subtype == E_INTERNAL)) { + pushlabel(e_current->symbol); + e_line = e_current->next; + e_current->next = NULL; + free_expr(e_current); + e_current = e_line; + } else { + exception(1, _("Unknow instruction")); + } + } + } + + switch (e_current->e_subtype) { + case E_INTERNAL: + switch (e_current->op) { + case 1: + case 2: + case 3: + do { + e_line = e_current->next; + e_current->next = NULL; + free_expr(e_current); + e_current = e_line; + if (!e_current) + break; + switch (e_current->e_subtype) { + case E_VALUE: + pushdword(e_current->avalue, NULL); + break; + case E_LABEL: + case E_OPERATION: + pushdword(0, e_current); + break; + default: + exception(1, _("Bad constant for an immediate value")); + } + } while (1); + break; + case 4: + do { + e_line = e_current->next; + e_current->next = NULL; + free_expr(e_current); + e_current = e_line; + if (!e_current) + break; + switch (e_current->e_subtype) { + case E_STRING: + pushstring(e_current->symbol); + break; + default: + exception(1, _("Bad constant for a string")); + } + } while (1); + break; + } + break; + case E_INSTRUCT: + if (segment != SEG_TEXT) { + exception(1, _("You can only have an instruction into a .text segment")); + } + if (!(instr = e_match_i(phons, instructs, e_current))) { + exception(1, _("Unmatched instruction")); + } + + /* Operation crutiale: nous avons l'instruction qui correspond le mieux à notre + expression, on va tenter de l'évaluer */ + + Initialise(&it); + pi = pushdword(0, NULL); + + for (i = 0; i < instr->nbexplicit; i++) { + if (instr->strings[i]) { + switch (instr->strings[i][0]) { + case 'C': + if (instr->etypes) { + if (!strcmp(instr->names[i], "I")) { + if (e_current->e_subtype == E_VALUE) { + pushdword(e_current->avalue, 0); + } else { + pushdword(0, e_current); + } + } else { + exception(1, + _ + ("Unknow constant type in the meta language")); + } + } else { + InsererVarDansTab(&it, + CreerElement(instr->names[i], e_current)); + } + break; + case 'P': + t = (expression_t *) Emalloc(sizeof(expression_t)); + t->e_type = t->e_subtype = E_VALUE; + t->avalue = e_current->index; + t->child = t->next = NULL; + InsererVarDansTab(&it, CreerElement(instr->names[i], t)); + free(t); + evaluate_pattern(&it, e_current); + + + + break; + default: + exception(1, _("Unknow constant type in the meta language")); + } + } + + e_line = e_current->next; + e_current->next = NULL; + free_expr(e_current); + e_current = e_line; + } + + + + break; + default: + exception(1, _("Unknow instruction")); + break; + } + + break; + } + wc = 0; special = 0; + e_current = e_line = NULL; } void asm_eof(void) { } -static void delete_bytestream(bytestream_t * s) { - if (s->next) delete_bytestream(s->next); +static void delete_bytestream(bytestream_t * s) +{ + if (s->next) + delete_bytestream(s->next); free(s); } @@ -1020,6 +1592,39 @@ void assembler_flush(void) int process_file(char *name) { - /* Petite chose à faire ici et cela sera bon */ + FILE *f; + char buf[BUFSIZ], errctx[BUFSIZ], *p; + int i = 0; + + pushcontext(_("Loading file")); + sprintf(errctx, _("Opening file '%s'"), name); + pushcontext(errctx); + filenames[nestedinc++] = Estrdup(name); + if (!(f = fopen(name, "r"))) { + pushcontext(strerror(errno)); + return 1; + } + popcontext(); + pushcontext(_("Reading file")); + while (fgets(buf, BUFSIZ, f)) { + sprintf(errctx, _("Reading line %i"), line = ++i); + pushcontext(errctx); + if ((p = strchr(buf, '\r'))) { + *p = '\0'; + } + if ((p = strchr(buf, '\n'))) { + *p = '\0'; + } + parse_line(buf); + sprintf(errctx, _("Summering line %s"), buf); + pushcontext(errctx); + asm_eol(); + popcontext(); + popcontext(); + } + nestedinc--; + popcontext(); + popcontext(); + fclose(f); return 0; } |