12 * quick and dirty assembler for dcpu16
14 * Justin Wind <justin.wind@gmail.com>
15 * 2012 04 07 - implementation started
16 * 2012 04 10 - functional
19 * needs ability to specify location for code or data
20 * short labels not correctly computed
23 static const char * const src_id_
= "$Id$";
25 const char const out_filename_default_
[] = "a.out";
27 /* global invocation options */
36 #define DEBUG_PRINTF(...) do { if (opt_.verbose > 2) { printf("DEBUG: "); printf(__VA_ARGS__); } } while (0)
37 #define DEBUG_PRINTFQ(...) do { if (opt_.verbose > 2) printf(__VA_ARGS__); } while (0)
38 #define VERBOSE_PRINTF(...) do { if (opt_.verbose) printf(__VA_ARGS__); } while (0)
41 void usage_(char *prog
, unsigned int full
) {
42 FILE *f
= full
? stdout
: stderr
;
43 char *x
= strrchr(prog
, '/');
49 fprintf(f
, "%s -- \n\n",
52 fprintf(f
, "Usage: %s [-h] [-v] [-s] [-o file] file [file [...]]\n",
56 fprintf(f
, "\nOptions:\n"
57 "\t-h -- this screen\n"
58 "\t-o <file> -- output to <file> [default: %s]\n"
59 "\t-s -- allow short labels in instruction words\n"
60 "\t-d -- dry run, print results, do not write to file\n"
61 "\t-v -- verbose output\n",
62 out_filename_default_
);
64 fprintf(f
, "\n%78s\n",
70 /* instructions have operands */
72 struct operand_
*next
;
73 char *operand
; /* tokenized operand text */
76 /* keep an array of instructions as we read them in */
78 char *label
; /* set if a label points here */
79 char *opcode
; /* tokenized instruction text */
80 struct operand_
*operands
; /* list of operands */
81 unsigned int ready
: 1; /* bytecode computed? */
82 unsigned int length
; /* number of words of bytecode */
83 DCPU16_WORD instr_words
[];
86 /* keep an array of labels, indexed back to their instruction locations */
88 char *label
; /* name of label */
89 struct instruction_
**instr
; /* pointer into array of instructions */
90 unsigned int ready
: 1; /* do we know where this label is yet? */
95 /* routines to support generic grow-able arrays */
97 struct dynamic_array_
{
105 #define DYNARRAY_ITEM(da, index) ( (char *)(da).a + ( (da).entry_size * index ) )
107 /* allocate and initialize a new generic dynamic array */
109 struct dynamic_array_
*dynarray_new_(size_t entry_size
, size_t grow_size
) {
110 struct dynamic_array_
*da
;
112 if (entry_size
== 0 || grow_size
== 0) {
113 fprintf(stderr
, "%s: internal error: sizes cannot be zero\n", __func__
);
117 da
= calloc(1, sizeof *da
);
119 fprintf(stderr
, "%s():%s\n", "calloc", strerror(errno
));
123 da
->entry_size
= entry_size
;
124 da
->grow_size
= grow_size
;
126 da
->a
= malloc(da
->entry_size
* da
->grow_size
);
128 fprintf(stderr
, "%s():%s\n", "malloc", strerror(errno
));
131 da
->allocated
= grow_size
;
133 DEBUG_PRINTF("allocated new dynarray:%p a:%p entry_size:%zu\n", da
, da
->a
, da
->entry_size
);
138 /* copy item onto end of array */
140 void *dynarray_add_(struct dynamic_array_
*da
, void *item
) {
143 /* make room, make room */
144 if (da
->entries
== da
->allocated
) {
145 size_t new_allocated
= da
->allocated
+ da
->grow_size
;
146 void *tmp_ptr
= realloc(da
->a
, new_allocated
* da
->entry_size
);
147 if (tmp_ptr
== NULL
) {
148 fprintf(stderr
, "%s():%s\n", "realloc", strerror(errno
));
152 da
->allocated
= new_allocated
;
154 DEBUG_PRINTF("grew dynarray:%p\n", da
);
157 dst
= DYNARRAY_ITEM(*da
, da
->entries
);
158 memcpy(dst
, item
, da
->entry_size
);
162 DEBUG_PRINTF("added dynarray:%p entry:%zu item:%p\n", da
, da
->entries
, item
);
168 /* locate and return the label entry matching name */
170 struct label_
*label_find_(struct dynamic_array_
*labels
, char *name
) {
173 for (x
= 0; x
< labels
->entries
; x
++) {
174 struct label_
*l
= (struct label_
*)DYNARRAY_ITEM(*labels
, x
);
175 if (strcmp(l
->label
, name
) == 0)
182 /* if a label has a validly-calculated address, fetch it */
184 int label_addr_(struct dynamic_array_
*labels
, char *name
, DCPU16_WORD
*addr
) {
187 if ( (l
= label_find_(labels
, name
)) == NULL
)
196 /* attempt to determine the addresses of all labels */
198 void label_addr_calculate_(struct dynamic_array_
*instructionps
, struct dynamic_array_
*labels
) {
201 /* for each label.. */
202 for (i
= 0; i
< labels
->entries
; i
++) {
204 struct instruction_
**instr
;
205 unsigned int word_count
= 0;
207 l
= (struct label_
*)DYNARRAY_ITEM(*labels
, i
);
209 /* if it's already calculated, great. */
214 * starting at the instruction for this label,
215 * walk backwards through the list of instructions
216 * until we get to the start or a known prior label address.
217 * update our label with the freshly calculated addr
219 for (instr
= ((struct label_
*)DYNARRAY_ITEM(*labels
, i
))->instr
;
220 instr
>= (struct instruction_
**)DYNARRAY_ITEM(*instructionps
, 0);
223 word_count
+= (*instr
)->length
;
225 /* have we come across an instruction which a label points to?
226 it should already be calculated, so just add that on and be done */
228 && strcmp((*instr
)->label
, l
->label
)) {
231 if (label_addr_(labels
, (*instr
)->label
, &addr
)) {
232 fprintf(stderr
, "internal error: incomplete prior address for '%s' while calculating '%s'\n",
242 l
->addr
= word_count
;
244 DEBUG_PRINTF("label '%s' now has addr of 0x%04x\n", l
->label
, word_count
);
249 void instr_free_(struct instruction_
*i
) {
254 while (i
->operands
) {
255 struct operand_
*o
= i
->operands
;
257 i
->operands
= o
->next
;
264 /* generate the nibble for a given basic opcode */
266 int opcode_bits_(char *opcode
) {
270 } opcodes_lower_nibble
[] = {
272 /* { "future nbi instruction", 0x00 }, */
291 for (o
= opcodes_lower_nibble
; o
->op
[0]; o
++) {
292 if (strcasecmp(o
->op
, opcode
) == 0)
296 if (o
->op
[0] == '\0') {
297 fprintf(stderr
, "unknown instruction '%s'\n", opcode
);
304 /* generate the six bits for a given nbi opcode (aka first operand to opcode 0x00) */
306 int nbi_opcode_bits_(char *nbi_opcode
) {
310 } nbi_opcodes_bits
[] = {
311 { " ", 0x00 }, /* reserved for future */
316 for (o
= nbi_opcodes_bits
; o
->op
[0]; o
++) {
317 if (strcasecmp(o
->op
, nbi_opcode
) == 0)
321 if (o
->op
[0] == '\0') {
322 fprintf(stderr
, "unknown nbi instruction '%s'\n", o
->op
);
329 /* convert register character like 'x' to value like 0x03 */
331 unsigned int register_enumerate_(char r
) {
332 const char regs
[] = "AaBbCcXxYyZzIiJj";
333 const char *x
= strchr(regs
, r
);
338 fprintf(stderr
, "internal error, unknown register character 0x%02x\n", r
);
342 /* removes all occurences of chars from buf */
344 void buf_strip_chars_(char *buf
, char *chars
) {
347 for (s
= d
= buf
; *s
; s
++, d
++) {
348 while (*s
&& strchr(chars
, *s
)) {
359 * generate the six bits for a given operand string
360 * returns -1 if it could not parse the operand
361 * returns -2 if it could not parse the operand due to an unresolved label
362 * notes: nextword may be overwritten even if it's not used in final instruction
365 int value_bits_(struct dynamic_array_
*labels
, char *operand_orig
, DCPU16_WORD
*nextword
, unsigned int *nextwordused
, unsigned int allow_short_labels
) {
366 static char *operand
= NULL
;
367 static size_t operand_sz
= 0;
373 Our operand working buffer shouldn't ever need to be too big,
374 but DAT might blow that assumption.
376 if (operand_sz
<= strlen(operand_orig
)) {
378 size_t new_sz
= strlen(operand_orig
);
384 DEBUG_PRINTF("%s: allocating buffer of size %zu\n", __func__
, new_sz
);
385 tmp_ptr
= realloc(operand
, new_sz
);
386 if (tmp_ptr
== NULL
) {
387 fprintf(stderr
, "%s(%zu):%s\n", "realloc", new_sz
, strerror(errno
));
394 o
= strcpy(operand
, operand_orig
);
396 DEBUG_PRINTF("%s: operand '%s' ", __func__
, operand
); /* completed later */
398 /* this is a very stupid parser */
400 /* first, let's trim all whitespace out of string at once to make parsing easier */
401 buf_strip_chars_(operand
, " \t\n");
403 /* single character might match a register */
404 if (strlen(operand
) == 1
405 && strchr("AaBbCcXxYyZzIiJj", *operand
)) {
406 DEBUG_PRINTFQ("is register %c\n", *operand
);
407 return register_enumerate_(*operand
);
411 if (strcasecmp(operand
, "POP") == 0) {
412 DEBUG_PRINTFQ("is POP\n");
415 if (strcasecmp(operand
, "PUSH") == 0) {
416 DEBUG_PRINTFQ("is PUSH\n");
419 if (strcasecmp(operand
, "PEEK") == 0) {
420 DEBUG_PRINTFQ("is PEEK\n");
423 if (strcasecmp(operand
, "SP") == 0) {
424 DEBUG_PRINTFQ("is register SP\n");
427 if (strcasecmp(operand
, "PC") == 0) {
428 DEBUG_PRINTFQ("is register PC\n");
431 if (strcasecmp(operand
, "O") == 0) {
432 DEBUG_PRINTFQ("is register O\n");
436 /* is the operand [bracketed]? */
437 if (operand
[0] == '[' && operand
[strlen(operand
) - 1] == ']') {
438 /* eat the brackets */
439 operand
[strlen(operand
) - 1] = '\0';
442 /* is it [register]? */
443 if (strlen(operand
) == 1
444 && strchr("AaBbCcXxYyZzIiJj", *operand
)) {
445 DEBUG_PRINTFQ("is dereferenced register %c\n", *operand
);
446 return 0x08 | register_enumerate_(*operand
);
449 /* is it [register+something]? */
450 if ( (ep
= strchr(operand
, '+')) ) {
458 /* figure out which one is which */
460 && strchr("AaBbCcXxYyZzIiJj", *ep
)) {
463 } else if (strlen(operand
) == 1
464 && strchr("AaBbCcXxYyZzIiJj", *operand
) ) {
468 DEBUG_PRINTFQ("is unparsable\n");
469 fprintf(stderr
, "couldn't parse operand '%s'\n", operand_orig
);
473 /* check if something is understandable as a value */
475 l
= strtoul(constant
, &ep
, 0);
477 && (*constant
&& (*ep
== '\0')) ) {
478 /* string conversion went without issue */
479 /* validate it will fit in a word */
481 DEBUG_PRINTFQ("is out of range\n");
482 fprintf(stderr
, "constant invalid in operand '%s'\n", operand_orig
);
487 *nextword
= l
& 0xffff;
489 DEBUG_PRINTFQ("is a dereferenced register (%c) + constant (%hu)\n", *reg
, *nextword
);
490 return 0x10 | register_enumerate_(*reg
);
492 DEBUG_PRINTFQ("is out of range\n");
493 fprintf(stderr
, "trouble with operand '%s': %s\n", operand_orig
, strerror(errno
));
497 /* what? still here? assume it's a label, I guess */
498 /* try to populate nextword with label address */
499 if (label_addr_(labels
, operand
, nextword
)) {
500 DEBUG_PRINTFQ("(deferred label resolution)\n");
504 DEBUG_PRINTFQ("is a dereferenced register (%c) + label\n", *reg
);
506 return 0x10 | register_enumerate_(*reg
);
509 /* it must just be a dereferenced literal then */
512 l
= strtoul(operand
, &ep
, 0);
514 && (*operand
&& (*ep
== '\0')) ) {
515 /* string conversion went without issue */
516 /* validate it will fit in a word */
518 DEBUG_PRINTFQ("is out of range\n");
519 fprintf(stderr
, "constant invalid in operand '%s'\n", operand_orig
);
523 DEBUG_PRINTFQ("is a dereferenced literal value (%hu)\n", *nextword
);
524 *nextword
= l
& 0xffff;
528 DEBUG_PRINTFQ("is out of range\n");
529 fprintf(stderr
, "trouble with operand '%s': %s\n", operand_orig
, strerror(errno
));
532 /* not a number? try a label */
533 if (label_addr_(labels
, operand
, nextword
)) {
534 DEBUG_PRINTFQ("(deferred label resolution)\n");
538 DEBUG_PRINTFQ("is a dereferenced label\n");
543 /* left with a literal or a label, then */
546 l
= strtoul(operand
, &ep
, 0);
548 || (*operand
&& (*ep
== '\0')) ) {
550 DEBUG_PRINTFQ("is out of range\n");
551 fprintf(stderr
, "constant invalid in operand '%s'\n", operand_orig
);
555 DEBUG_PRINTFQ("is literal value (%lu)\n", l
);
560 *nextword
= l
& 0xffff;
565 /* try to populate nextword with label address */
566 if (label_addr_(labels
, operand
, nextword
)) {
567 DEBUG_PRINTFQ("(deferred label resolution)\n");
568 /* assume non-small literal value */
573 DEBUG_PRINTFQ("is label '%s' (0x%02hx)\n", operand
, *nextword
);
574 if (*nextword
< 0x20 && allow_short_labels
) {
575 DEBUG_PRINTF("small value label win\n");
576 return (0x20 + *nextword
) & 0x3f;
583 /* prints an instruction's assembly */
585 int instruction_print_(struct instruction_
*i
, unsigned int with_label
) {
590 r
= printf("%-16s %3s", i
->label
? i
->label
: "", i
->opcode
);
592 r
= printf("%3s", i
->opcode
);
594 for (o
= i
->operands
; o
; o
= o
->next
)
595 r
+= printf(" %s%s", o
->operand
, o
->next
? "," : "");
600 /* parse an instruction out of buf, create new instruction struct if seemingly valid */
601 /* does not actually check if instruction is valid yet */
602 /* buf must be 0-terminated */
604 int buf_tokenize_(char *buf
, struct instruction_
**next_instr
) {
605 const char const *sep
= " \t\n";
606 struct instruction_
*instr
= NULL
;
616 assert(next_instr
!= NULL
);
621 if ((x
= strchr(buf
, ';')) != NULL
)
623 /* kill leading whitespace */
624 buf
+= strspn(buf
, " \t\n");
625 /* kill trailing whitespace */
627 x
= buf
+ strlen(buf
);
628 while (strchr(" \t\n", *x
)) {
634 if ((x
= strrchr(buf
, '\n')) != NULL
)
637 /* determine if first token is label, opcode, or we just have a blank line to ignore */
638 x
= strtok_r(buf
, sep
, &st
);
640 /* empty line? nothing to do here. */
645 /* labels end with :, otherwise its an opcode */
646 y
= x
+ strlen(x
) - 1;
650 opcode
= strtok_r(NULL
, sep
, &st
);
652 #else /* OTHER_LABELS */
653 /* labels.. begin? with ':' ? okay, I guess. Whatever. */
654 /* otherwise, it's an opcode */
657 opcode
= strtok_r(NULL
, sep
, &st
);
662 #endif /* OTHER_LABELS */
668 /* extra room for assembled words */
669 instr
= calloc(1, 3 + sizeof *instr
);
671 fprintf(stderr
, "%s():%s\n", "calloc", strerror(errno
));
675 instr
->label
= label
? strdup(label
) : NULL
;
676 instr
->opcode
= opcode
? strdup(opcode
) : NULL
;
679 struct operand_
**o_next
= &instr
->operands
;
681 for (x
= strtok_r(operand
, ",", &st
);
683 x
= strtok_r(NULL
, ",", &st
) ) {
684 *o_next
= malloc(3 + sizeof **o_next
); /* FIXME: handle this on the fly later */
686 if (*o_next
== NULL
) {
687 fprintf(stderr
, "%s():%s\n", "calloc", strerror(errno
));
693 x
+= strspn(x
, " \t\n");
695 y
= x
+ strlen(x
) - 1;
696 while (strchr(" \t\n", *y
)) {
702 (*o_next
)->operand
= strdup(x
);
703 (*o_next
)->next
= NULL
;
704 o_next
= &((*o_next
)->next
);
713 /* try to generate bytecode for an instruction */
715 int instr_assemble_(struct dynamic_array_
*labels
, struct instruction_
*i
, unsigned int allow_short_labels
) {
716 unsigned int nwu
= 0; /* number of words used */
717 unsigned int incomplete
= 0;
719 struct operand_
*o
= i
->operands
;
721 if (opt_
.verbose
> 2) {
722 printf("%s: assembling %p ", __func__
, i
);
723 instruction_print_(i
, 1);
728 /* already assembled, nothing to do */
732 /* special case DAT */
733 if (strncasecmp(i
->opcode
, "DAT", 3) == 0) {
734 /* just dump operands into words, I guess */
735 fprintf(stderr
, "FIXME unhandled raw data\n");
736 /* count total length of data.. */
737 /* realloc instruction */
742 /* start with opcode bits */
743 bits
= opcode_bits_(i
->opcode
);
745 fprintf(stderr
, "unrecognized instruction '%s%s", i
->opcode
, i
->operands
? " " : "");
746 for (o
= i
->operands
; o
; o
= o
->next
)
747 fprintf(stderr
, " %s%s", o
->operand
, o
->next
? "," : "");
748 fprintf(stderr
, "'\n");
751 i
->instr_words
[0] |= 0x0f & bits
;
753 /* in rendered bytecode, all instructions have two operands; nbi instructions take 'first operand' bits. */
754 if ((bits
& 0x0f) == 0) {
755 bits
= nbi_opcode_bits_(i
->opcode
);
757 fprintf(stderr
, "INTERNAL ERROR: missing instruction in nbi opcode table\n");
762 fprintf(stderr
, "'%s' requires more operands\n", i
->opcode
);
765 bits
= value_bits_(labels
, o
->operand
, i
->instr_words
+ 1, &nwu
, allow_short_labels
);
767 fprintf(stderr
, "couldn't assemble instruction\n");
769 } else if (bits
== -2) {
770 DEBUG_PRINTF("%s: assembly deferred: unresolved label\n", __func__
);
771 /* keep going, but don't finalize until we can calculate label address */
777 i
->instr_words
[0] |= (bits
& 0x3f) << 4;
780 fprintf(stderr
, "'%s' requires more operands\n", i
->opcode
);
784 bits
= value_bits_(labels
, o
->operand
, i
->instr_words
+ nwu
+ 1, &nwu
, allow_short_labels
);
786 fprintf(stderr
, "couldn't assemble instruction\n");
788 } else if (bits
== -2) {
789 DEBUG_PRINTF("%s: assembly deferred: unresolved label\n", __func__
);
790 /* keep going, but don't finalize until we can calculate label address */
795 i
->instr_words
[0] |= (bits
& 0x3f) << 10;
798 fprintf(stderr
, "too many operands\n");
802 /* counting labels as words, we now know at least the maximum instruction length */
806 DEBUG_PRINTF("instruction words: [%u]", i
->length
);
807 for (bits
= 0; bits
<= (int)nwu
; bits
++)
808 DEBUG_PRINTFQ(" %04x", i
->instr_words
[bits
]);
811 DEBUG_PRINTFQ(" (preliminary)");
822 * read lines from stream f
823 * break each line into parts, populate parts into structures
826 int parse_stream_(FILE *f
, const char *src
, struct dynamic_array_
*instructionps
, struct dynamic_array_
*labels
, unsigned int allow_short_labels
) {
827 struct instruction_
*instr
, **instr_list_entry
;
828 unsigned int line
= 0;
832 buf
[sizeof buf
- 1] = '\0';
834 while (fgets(buf
, sizeof buf
, f
)) {
837 if (buf
[sizeof buf
- 1] != '\0') {
838 fprintf(stderr
, "%s:%u:%s", src
, line
, "input line too long\n");
843 if (buf_tokenize_(buf
, &instr
)) {
844 fprintf(stderr
, "%s:%u:%s", src
, line
, "trouble tokenizing input\n");
850 /* add to list of instructions */
851 instr_list_entry
= dynarray_add_(instructionps
, &instr
);
852 if (instr_list_entry
== NULL
) {
853 fprintf(stderr
, "%s:%u:%s", src
, line
, "could not populate instruction list\n");
858 struct label_ new_label
= {
859 .label
= instr
->label
,
860 .instr
= instr_list_entry
,
864 if (label_find_(labels
, instr
->label
)) {
865 fprintf(stderr
, "%s:%u:%s", src
, line
, "duplicate label\n");
869 if (dynarray_add_(labels
, &new_label
) == NULL
) {
870 fprintf(stderr
, "%s:%u:%s", src
, line
, "could not populate label list\n");
873 label_addr_calculate_(instructionps
, labels
);
876 instr_assemble_(labels
, instr
, allow_short_labels
);
880 fprintf(stderr
, "%s():%s\n", "fgets", strerror(errno
));
884 fprintf(stderr
, "parsing aborted\n");
892 * make a full pass over instruction list to resolve labels
895 int assemble_check_(struct dynamic_array_
*instructionps
, struct dynamic_array_
*labels
, unsigned int allow_short_labels
) {
899 DEBUG_PRINTF(" final pass of assembler...\n");
900 for (x
= 0; x
< instructionps
->entries
; x
++) {
901 struct instruction_
**instrp
= (struct instruction_
**)DYNARRAY_ITEM(*instructionps
, x
);
902 retval
|= instr_assemble_(labels
, *instrp
, allow_short_labels
);
904 fprintf(stderr
, "instruction %zu failed to assemble\n", x
);
908 VERBOSE_PRINTF("%3s %6s %-32s %-4s\n", "", "_addr_", "_label_", "_instruction_");
909 for (x
= 0; x
< labels
->entries
; x
++) {
910 struct label_
*l
= (struct label_
*)DYNARRAY_ITEM(*labels
, x
);
914 printf("%3s0x%04x %-32s ",
918 instruction_print_(*(l
->instr
), 0);
923 VERBOSE_PRINTF("\n");
926 fprintf(stderr
, "some labels could not be resolved\n");
932 int output_(struct dynamic_array_
*instructionps
, const char *filename
) {
934 struct instruction_
**instrp
;
935 size_t i
, r
, total_words
= 0;
939 of
= fopen(filename
, "w");
941 fprintf(stderr
, "%s('%s'):%s\n", "fopen", filename
, strerror(errno
));
946 for (i
= 0; i
< instructionps
->entries
; i
++) {
947 instrp
= (struct instruction_
**)DYNARRAY_ITEM(*instructionps
, i
);
951 s
= instruction_print_(*instrp
, 1);
952 printf("%*s;", (44 - s
) > 0 ? (44 - s
) : 0, "");
953 for (x
= 0; x
< (*instrp
)->length
; x
++) {
954 printf(" %04x", (*instrp
)->instr_words
[x
]);
960 r
= fwrite((*instrp
)->instr_words
, sizeof(DCPU16_WORD
), (*instrp
)->length
, of
);
961 if (r
< (*instrp
)->length
) {
962 fprintf(stderr
, "%s():%s\n", "fwrite", strerror(errno
));
966 total_words
+= (*instrp
)->length
;
969 fprintf(stderr
, "%s 0x%04zx instructions as 0x%04zx words\n",
970 opt_
.dryrun
? "assembled" : "wrote",
977 static struct dynamic_array_
*instructionps_
;
978 static struct dynamic_array_
*labels_
;
980 int main(int argc
, char *argv
[]) {
981 const char *out_filename
= NULL
;
982 unsigned int allow_short_labels
= 0;
985 while ( (c
= getopt(argc
, argv
, "dhsvo:")) != EOF
) {
992 allow_short_labels
++;
997 fprintf(stderr
, "Sorry, I can only write one file at a time.\n");
1000 out_filename
= optarg
;
1020 if (out_filename
== NULL
)
1021 out_filename
= out_filename_default_
;
1024 instructionps_
= dynarray_new_(sizeof (struct instruction_
*), 1024);
1025 labels_
= dynarray_new_(sizeof(struct label_
), 256);
1026 if (instructionps_
== NULL
1027 || labels_
== NULL
) {
1028 fprintf(stderr
, "failed to initialize\n");
1032 /* if filenames were specified, parse them instead of stdin */
1035 char *filename
= *argv
;
1036 FILE *f
= fopen(filename
, "r");
1041 fprintf(stderr
, "%s('%s'):%s\n", "fopen", filename
, strerror(errno
));
1045 VERBOSE_PRINTF("assembling '%s'...\n", filename
);
1046 parse_stream_(f
, filename
, instructionps_
, labels_
, allow_short_labels
);
1051 VERBOSE_PRINTF("assembling '%s'...\n", "stdin");
1052 parse_stream_(stdin
, "-", instructionps_
, labels_
, allow_short_labels
);
1055 if (assemble_check_(instructionps_
, labels_
, allow_short_labels
)) {
1056 fprintf(stderr
, "errors prevented assembly\n");
1060 if (output_(instructionps_
, out_filename
)) {
1061 fprintf(stderr
, "failed to create output\n");