diff --git a/8to9/8to9.c b/8to9/8to9.c deleted file mode 100644 index 1fca89f..0000000 --- a/8to9/8to9.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 8to9.c -- convert octet files to nonet files - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include -#include -#include "pdp10-stdio.h" - -#define VERSION "pdp10-tools 8to9 version 0.0, built " __DATE__ " " __TIME__ "\n" - -int main(int argc, char **argv) -{ - const char *infile, *outfile; - FILE *infp; - PDP10_FILE *outfp; - int ch; - - infile = NULL; - outfile = NULL; - - for (;;) { - ch = getopt(argc, argv, "Vi:o:"); - switch (ch) { - case 'V': - printf(VERSION); - return 0; - case 'i': - infile = optarg; - continue; - case 'o': - outfile = optarg; - continue; - case -1: - break; - default: - fprintf(stderr, "%s -o OUTFILE [-i INFILE] [-V]\n", argv[0]); - return 1; - } - break; - } - - /* XXX: We currently require a named output file because pdp10-stdio.c doesn't - support fdopen:ing non-seekable files. That should be fixed at some point. */ - if (!outfile) { - fprintf(stderr, "%s: no OUTFILE specified\n", argv[0]); - return 1; - } else { - outfp = pdp10_fopen(outfile, "wb"); - if (!outfp) { - fprintf(stderr, "%s: %s: failed to open for writing: %s\n", argv[0], outfile, strerror(errno)); - return 1; - } - } - - if (!infile) { - infp = stdin; - } else { - infp = fopen(infile, "rb"); - if (!infp) { - fprintf(stderr, "%s: %s: failed to open for reading: %s\n", argv[0], infile, strerror(errno)); - return 1; - } - } - - while ((ch = fgetc(infp)) != EOF) - if (pdp10_fputc(ch, outfp) == EOF) { - fprintf(stderr, "%s: %s: failed to write: %s\n", argv[0], outfile, strerror(errno)); - return 1; - } - - if (pdp10_fclose(outfp) == EOF) { - fprintf(stderr, "%s: %s: failed to close: %s\n", argv[0], outfile, strerror(errno)); - return 1; - } - - return 0; -} diff --git a/8to9/Makefile b/8to9/Makefile deleted file mode 100644 index 1a02877..0000000 --- a/8to9/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# 8to9/Makefile -# Copyright (C) 2013-2015 Mikael Pettersson -# -# This file is part of pdp10-tools. -# -# pdp10-tools is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# pdp10-tools is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with pdp10-tools. If not, see . - -CC=gcc -CFLAGS=-O2 -g -Wall -CPPFLAGS=-I../include - -8TO9OBJS=8to9.o -LIBOBJS=../lib/pdp10-stdio.o - -8to9: $(8TO9OBJS) $(LIBOBJS) - $(LINK.c) -o $@ $^ - -8to9.o: 8to9.c ../include/pdp10-stdint.h ../include/pdp10-stdio.h - -clean: - rm -f $(8TO9OBJS) 8to9 a.out core.* diff --git a/Makefile b/Makefile index f58b42d..1f2f3ee 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Makefile for pdp10-tools -# Copyright (C) 2013-2018 Mikael Pettersson +# Copyright (C) 2013-2023 Mikael Pettersson # # This file is part of pdp10-tools. # @@ -16,7 +16,7 @@ # You should have received a copy of the GNU General Public License # along with pdp10-tools. If not, see . -SUBDIRS= lib 8to9 ar as nm od readelf sim +SUBDIRS= erlang all: make TARGET= subdirs diff --git a/TODO b/TODO index 930b5cc..dcede99 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ # TODO notes for pdp10-tools -# Copyright (C) 2013-2020 Mikael Pettersson +# Copyright (C) 2013-2023 Mikael Pettersson # # This file is part of pdp10-tools. # @@ -33,9 +33,7 @@ Tools: - top-level Makefile: subdirs should error out on error in subdir - size: implement it - strip: implement it -- as: - * tunit_{strtab_,}section_enter() should be generalized and merged - * what happens if user defines .comment as say text, and later enters .ident? - * output: move section_symtab into the context - * tunit: add symtab sections analagous to strtab sections? - * add support for extended opcodes (emit second opcode after current .text section) +- ranlib: add wrapper script doing 'ar s' +- sim: improve it so it can run simple applications +- as/ld: add support for PIC +- as/ld: add support for shared objects diff --git a/ar/Makefile b/ar/Makefile deleted file mode 100644 index 4e5e89a..0000000 --- a/ar/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# ar/Makefile -# Copyright (C) 2013-2015 Mikael Pettersson -# -# This file is part of pdp10-tools. -# -# pdp10-tools is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# pdp10-tools is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with pdp10-tools. If not, see . - -CC=gcc -CFLAGS=-O2 -g -Wall -CPPFLAGS=-I../include - -AROBJS= ar.o -LIBOBJS=../lib/pdp10-stdio.o - -ar: $(AROBJS) $(LIBOBJS) - $(LINK.c) -o $@ $^ - -ar.o: ar.c ../include/pdp10-ar.h ../include/pdp10-inttypes.h ../include/pdp10-stdint.h ../include/pdp10-stdio.h - -clean: - rm -f $(AROBJS) ar a.out core.* diff --git a/ar/ar.c b/ar/ar.c deleted file mode 100644 index 230be13..0000000 --- a/ar/ar.c +++ /dev/null @@ -1,1020 +0,0 @@ -/* - * ar.c -- ar clone - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include "pdp10-ar.h" -#include "pdp10-inttypes.h" -#include "pdp10-stdio.h" - -#define VERSION "pdp10-tools ar version 0.1, built " __DATE__ " " __TIME__ "\n" - -enum modifier { - MOD_create = 1 << 0, /* 'c' */ - MOD_newer = 1 << 1, /* 'u' */ - MOD_verbose = 1 << 2, /* 'v' */ -}; - -struct strtab { - char *bytes; - unsigned long len; -}; - -struct arhdr { - char ar_name[16]; /* NUL-terminated unless ar_name[0] == '/' */ - time_t ar_date; /* File date, decimal seconds since Epoch. */ - unsigned int ar_uid; /* User ID. */ - unsigned int ar_gid; /* Group ID. */ - unsigned int ar_mode; /* File mode. */ - unsigned long ar_size; /* File size. */ -}; - -struct member { - struct member **prev_next, *next; - char *name; /* points into ->arhdr.ar_name, params->strtab, or argv[] */ - unsigned long strtaboffset; /* >=0: offset into strtab, -1U: short name in arhdr.ar_name, -2UL: short or long name in argv[] */ - unsigned long srcoffset; /* 0: in external file, >0: in old archive */ - struct arhdr arhdr; -}; - -struct params { - const char *progname; /* argv[0] */ - char operation; /* 'd', 'q', 'r', 't', 'x' */ - unsigned int modifiers; /* bitmask indexed by enum modifier */ - char *arname; - PDP10_FILE *pdp10fp; - struct strtab strtab; - struct member *members_head, **members_tail; -}; - -static void params_init(struct params *params) -{ - memset(params, '\0', sizeof *params); - params->progname = NULL; - params->arname = NULL; - params->pdp10fp = NULL; - params->strtab.bytes = NULL; - params->members_head = NULL; - params->members_tail = ¶ms->members_head; -} - -static struct member *lookup_member(struct params *params, const char *name) -{ - struct member *member; - - for (member = params->members_head; member; member = member->next) - if (strcmp(member->name, name) == 0) - return member; - - return NULL; -} - -static void unlink_member(struct member *member) -{ - *member->prev_next = member->next; - if (member->next) - member->next->prev_next = member->prev_next; -} - -static void append_member(struct params *params, struct member *member) -{ - member->next = NULL; - member->prev_next = params->members_tail; - *params->members_tail = member; - params->members_tail = &member->next; -} - -static int ar_fgetc(struct params *params, const char *srcname, PDP10_FILE *srcfp) -{ - int ch; - - ch = pdp10_fgetc(srcfp); - if (ch == EOF) { - fprintf(stderr, "%s: %s: premature EOF on read\n", params->progname, srcname); - return EOF; - } - return ch; -} - -static int ar_fputc(struct params *params, const char *dstname, PDP10_FILE *dstfp, uint16_t ch) -{ - if (pdp10_fputc(ch, dstfp) < 0) { - fprintf(stderr, "%s: %s: failed to write: %s\n", - params->progname, dstname, strerror(errno)); - return -1; - } - return 0; -} - -static int ar_fputvec(struct params *params, const char *dstname, PDP10_FILE *dstfp, const pdp10_uint9_t *v, size_t n) -{ - size_t i; - - for (i = 0; i < n; ++i) - if (ar_fputc(params, dstname, dstfp, v[i]) < 0) - return -1; - - return 0; -} - -static int copy_file_data( - struct params *params, unsigned long nrbytes, PDP10_FILE *srcfp, const char *srcname, PDP10_FILE *dstfp, const char *dstname) -{ - unsigned int i; - - for (i = 0; i < nrbytes; ++i) { - int ch = ar_fgetc(params, srcname, srcfp); - if (ch == EOF) - return -1; - if (ar_fputc(params, dstname, dstfp, ch) < 0) - return -1; - } - return 0; -} - -static const pdp10_uint9_t armag[PDP10_SARMAG] = PDP10_ARMAG; - -static int read_armag(struct params *params) -{ - unsigned int i; - - for (i = 0; i < PDP10_SARMAG; ++i) { - int ch = ar_fgetc(params, params->arname, params->pdp10fp); - if (ch == EOF) - return -1; - if (ch != armag[i]) { - fprintf(stderr, "%s: %s: file format not recognized\n", params->progname, params->arname); - return -1; - } - } - return 0; -} - -static int write_armag(struct params *params, const char *tmparname, PDP10_FILE *tmparfp) -{ - return ar_fputvec(params, tmparname, tmparfp, armag, PDP10_SARMAG); -} - -static const pdp10_uint9_t arfmag[2] = PDP10_ARFMAG; - -static int read_arhdr(struct params *params, struct arhdr *arhdr) -{ - union { - struct pdp10_ar_hdr arhdr; - pdp10_uint9_t buf[PDP10_ARHDR_SIZEOF]; - } u; - unsigned int i; - char buf[16]; - - for (i = 0; i < PDP10_ARHDR_SIZEOF; ++i) { - int ch = pdp10_fgetc(params->pdp10fp); - if (ch == EOF) { - if (i == 0) - return 0; - fprintf(stderr, "%s: %s: premature EOF in ar_hdr\n", params->progname, params->arname); - return -1; - } - u.buf[i] = ch; - } - - if (u.arhdr.ar_fmag[0] != arfmag[0] || u.arhdr.ar_fmag[1] != arfmag[1]) { - fprintf(stderr, "%s: %s: wrong value in ar_fmag\n", params->progname, params->arname); - return -1; - } - - for (i = 0; i < 10; ++i) - buf[i] = (char)(unsigned char)u.arhdr.ar_size[i]; - buf[i] = '\0'; - arhdr->ar_size = strtoul(buf, NULL, 10); - - for (i = 0; i < 8; ++i) - buf[i] = (char)(unsigned char)u.arhdr.ar_mode[i]; - buf[i] = '\0'; - arhdr->ar_mode = strtoul(buf, NULL, 8); - - for (i = 0; i < 6; ++i) - buf[i] = (char)(unsigned char)u.arhdr.ar_gid[i]; - buf[i] = '\0'; - arhdr->ar_gid = strtoul(buf, NULL, 10); - - for (i = 0; i < 6; ++i) - buf[i] = (char)(unsigned char)u.arhdr.ar_uid[i]; - buf[i] = '\0'; - arhdr->ar_uid = strtoul(buf, NULL, 10); - - for (i = 0; i < 12; ++i) - buf[i] = (char)(unsigned char)u.arhdr.ar_date[i]; - buf[i] = '\0'; - arhdr->ar_date = strtoul(buf, NULL, 10); - - for (i = 0; i < 16; ++i) - arhdr->ar_name[i] = (char)(unsigned char)u.arhdr.ar_name[i]; - - if (arhdr->ar_name[0] != '/') { - for (i = 1; i < 15; ++i) - if (arhdr->ar_name[i] == '/') - break; - arhdr->ar_name[i] = '\0'; - } - - return 1; -} - -static int write_arhdr(struct params *params, const char *tmparname, PDP10_FILE *tmparfp, const struct arhdr *arhdr) -{ - union { - struct pdp10_ar_hdr arhdr; - pdp10_uint9_t buf[PDP10_ARHDR_SIZEOF]; - } u; - unsigned int i; - char buf[16]; - - u.arhdr.ar_fmag[0] = arfmag[0]; - u.arhdr.ar_fmag[1] = arfmag[1]; - - sprintf(buf, "%lu", arhdr->ar_size); - for (i = 0; i < 10 && buf[i] != '\0'; ++i) - u.arhdr.ar_size[i] = (unsigned char)buf[i]; - for (; i < 10; ++i) - u.arhdr.ar_size[i] = ' '; - - sprintf(buf, "%o", arhdr->ar_mode); - for (i = 0; i < 8 && buf[i] != '\0'; ++i) - u.arhdr.ar_mode[i] = (unsigned char)buf[i]; - for (; i < 8; ++i) - u.arhdr.ar_mode[i] = ' '; - - sprintf(buf, "%u", arhdr->ar_gid); - for (i = 0; i < 6 && buf[i] != '\0'; ++i) - u.arhdr.ar_gid[i] = (unsigned char)buf[i]; - for (; i < 6; ++i) - u.arhdr.ar_gid[i] = ' '; - - sprintf(buf, "%u", arhdr->ar_uid); - for (i = 0; i < 6 && buf[i] != '\0'; ++i) - u.arhdr.ar_uid[i] = (unsigned char)buf[i]; - for (; i < 6; ++i) - u.arhdr.ar_uid[i] = ' '; - - sprintf(buf, "%llu", (unsigned long long)arhdr->ar_date); - for (i = 0; i < 12 && buf[i] != '\0'; ++i) - u.arhdr.ar_date[i] = (unsigned char)buf[i]; - for (; i < 12; ++i) - u.arhdr.ar_date[i] = ' '; - - if (arhdr->ar_name[0] != '/') { - for (i = 0; i < 15 && arhdr->ar_name[i] != '\0'; ++i) - u.arhdr.ar_name[i] = (unsigned char)arhdr->ar_name[i]; - u.arhdr.ar_name[i] = '/'; - ++i; - } else { - for (i = 0; i < 16 && arhdr->ar_name[i] != '\0'; ++i) - u.arhdr.ar_name[i] = (unsigned char)arhdr->ar_name[i]; - } - for (; i < 16; ++i) - u.arhdr.ar_name[i] = ' '; - - if (ar_fputvec(params, tmparname, tmparfp, u.buf, PDP10_ARHDR_SIZEOF) < 0) - return -1; - - return 0; -} - -static int read_arstrtab(struct params *params, const struct arhdr *arhdr) -{ - unsigned int i; - - params->strtab.len = arhdr->ar_size; - params->strtab.bytes = malloc(params->strtab.len); - if (!params->strtab.bytes) { - fprintf(stderr, "%s: %s: failed to allocate %zu bytes for string table: %s\n", - params->progname, params->arname, params->strtab.len, strerror(errno)); - return -1; - } - - for (i = 0; i < params->strtab.len; ++i) { - int ch = ar_fgetc(params, params->arname, params->pdp10fp); - if (ch == EOF) - return -1; - if (ch == '/') - ch = '\0'; - params->strtab.bytes[i] = ch; - } - - if ((i & 1) && ar_fgetc(params, params->arname, params->pdp10fp) == EOF) - return -1; - - return 0; -} - -static int write_arstrtab(struct params *params, const char *tmparname, PDP10_FILE *tmparfp) -{ - struct arhdr arhdr; - unsigned int i; - - if (!params->strtab.len) - return 0; - - memset(&arhdr, 0, sizeof arhdr); - arhdr.ar_name[0] = '/'; - arhdr.ar_name[1] = '/'; - arhdr.ar_size = params->strtab.len; - if (write_arhdr(params, tmparname, tmparfp, &arhdr) < 0) - return -1; - - for (i = 0; i < params->strtab.len; ++i) { - int ch = params->strtab.bytes[i]; - if (ch == '\0') - ch = '/'; - if (ar_fputc(params, tmparname, tmparfp, ch) < 0) - return -1; - } - - if ((i & 1) && ar_fputc(params, tmparname, tmparfp, '\n') < 0) - return -1; - - return 0; -} - -static int skip_member(struct params *params, struct arhdr *arhdr) -{ - if (pdp10_fseeko(params->pdp10fp, (arhdr->ar_size + 1) & ~(unsigned long)1, PDP10_SEEK_CUR) < 0) { - fprintf(stderr, "%s: %s: failed to fseek to next member: %s\n", - params->progname, params->arname, strerror(errno)); - return -1; - } - return 0; -} - -static int read_arsymtab(struct params *params, struct arhdr *arhdr) -{ - /* XXX: symtab is NYI so just seek past this member */ - fprintf(stderr, "%s: %s: Warning: skipping symbol table\n", params->progname, params->arname); - return skip_member(params, arhdr); -} - -static int read_archive(struct params *params) -{ - struct arhdr arhdr; - int status; - struct member *member; - - if (read_armag(params) < 0) - return -1; - - status = read_arhdr(params, &arhdr); - if (status <= 0) - return status; - - if (arhdr.ar_name[0] == '/' && arhdr.ar_name[1] == ' ') { - status = read_arsymtab(params, &arhdr); - if (status < 0) - return -1; - status = read_arhdr(params, &arhdr); - if (status <= 0) - return status; - } - - if (arhdr.ar_name[0] == '/' && arhdr.ar_name[1] == '/' && arhdr.ar_name[2] == ' ') { - status = read_arstrtab(params, &arhdr); - if (status < 0) - return -1; - status = read_arhdr(params, &arhdr); - if (status <= 0) - return status; - } - - do { - member = malloc(sizeof *member); - if (!member) { - fprintf(stderr, "%s: %s: failed to allocate %zu bytes for new member\n", - params->progname, params->arname, sizeof *member); - return -1; - } - member->arhdr = arhdr; - member->srcoffset = pdp10_ftello(params->pdp10fp); - if (arhdr.ar_name[0] == '/') { - char buf[16]; - unsigned int i; - - if (arhdr.ar_name[1] < '0' || arhdr.ar_name[1] > '9') { - fprintf(stderr, "%s: %s: invalid member name '%.*s'\n", - params->progname, params->arname, 16, arhdr.ar_name); - return -1; - } - for (i = 0; i < 15; ++i) - buf[i] = arhdr.ar_name[i + 1]; - buf[i] = '\0'; - member->strtaboffset = strtoul(buf, NULL, 10); - if (!params->strtab.bytes || member->strtaboffset >= params->strtab.len) { - fprintf(stderr, "%s: %s: ar_name '%.*s' out of bounds\n", - params->progname, params->arname, 16, arhdr.ar_name); - return -1; - } - } else { - member->strtaboffset = -1UL; - member->name = member->arhdr.ar_name; - } - append_member(params, member); - if (skip_member(params, &arhdr) < 0) - return -1; - status = read_arhdr(params, &arhdr); - } while (status > 0); - - return status; -} - -/* - * ar t/x code - */ - -static int ar_tx_should_process_member(struct params *params, struct member *member, char **files, int nrfiles) -{ - int i; - - for (i = 0; i < nrfiles; ++i) - if (files[i] && strcmp(member->name, files[i]) == 0) { - files[i] = NULL; - return 1; - } - - return nrfiles <= 0; -} - -static char *rwx_string(unsigned int m, char *buf) -{ - buf[0] = (m & 4) ? 'r' : '-'; - buf[1] = (m & 2) ? 'w' : '-'; - buf[2] = (m & 1) ? 'x' : '-'; - buf[3] = '\0'; - return buf; -} - -static char *date_string(time_t t, char *buf) -{ - struct tm *tm; - - tm = gmtime(&t); - if (!tm) { - fprintf(stderr, "gmtime(%lu) failed: %s\n", t, strerror(errno)); - exit(1); - } - /* Mon Day HH:MM YYYY */ - strftime(buf, 64, "%b %e %H:%M %Y", tm); - return buf; -} - -static int ar_t_member(struct params *params, struct member *member) -{ - char mode_u_buf[4], mode_g_buf[4], mode_o_buf[4], date_buf[64]; - - if (params->modifiers & MOD_verbose) - printf("%s%s%s %d/%d %10lu %s ", - rwx_string(member->arhdr.ar_mode >> 6, mode_u_buf), - rwx_string(member->arhdr.ar_mode >> 3, mode_g_buf), - rwx_string(member->arhdr.ar_mode, mode_o_buf), - member->arhdr.ar_uid, - member->arhdr.ar_gid, - member->arhdr.ar_size, - date_string(member->arhdr.ar_date, date_buf)); - printf("%s\n", member->name); - return 0; -} - -static int ar_x_copy(struct params *params, struct member *member, PDP10_FILE *memberfp) -{ - if (pdp10_fseeko(params->pdp10fp, member->srcoffset, PDP10_SEEK_SET) < 0) { - fprintf(stderr, "%s: %s: failed to fseek to member %s: %s\n", - params->progname, params->arname, member->name, strerror(errno)); - return -1; - } - return copy_file_data(params, member->arhdr.ar_size, params->pdp10fp, params->arname, memberfp, member->name); -} - -static int ar_x_member(struct params *params, struct member *member) -{ - PDP10_FILE *memberfp; - int status; - - if (params->modifiers & MOD_verbose) - printf("x - %s\n", member->name); - - memberfp = pdp10_fopen(member->name, "wb"); - if (!memberfp) { - fprintf(stderr, "%s: %s: %s: failed to open: %s\n", - params->progname, params->arname, member->name, strerror(errno)); - return -1; - } - status = ar_x_copy(params, member, memberfp); - pdp10_fclose(memberfp); - if (status < 0) - return -1; - - if (chmod(member->name, member->arhdr.ar_mode & 0777) < 0) { - fprintf(stderr, "%s: %s: %s: failed to set mode %o: %s\n", - params->progname, params->arname, member->name, member->arhdr.ar_mode & 0777, strerror(errno)); - return -1; - } - - return 0; -} - -static int ar_tx(struct params *params, char **files, int nrfiles) -{ - struct member *member; - int status; - int i; - - if (nrfiles < 1) { - fprintf(stderr, "%s: archive name missing\n", params->progname); - return -1; - } - params->arname = files[0]; - ++files; - --nrfiles; - - params->pdp10fp = pdp10_fopen(params->arname, "rb"); - if (!params->pdp10fp) { - fprintf(stderr, "%s: %s: failed to open: %s\n", - params->progname, params->arname, strerror(errno)); - return -1; - } - - if (read_archive(params) < 0) - return -1; - - for (member = params->members_head; member; member = member->next) - if (ar_tx_should_process_member(params, member, files, nrfiles)) { - switch (params->operation) { - case 't': - status = ar_t_member(params, member); - break; - case 'x': - status = ar_x_member(params, member); - break; - default: - fprintf(stderr, "%s: %s: unexpected operation '%c'\n", params->progname, __FUNCTION__, params->operation); - return -1; - } - if (status < 0) - return -1; - } - - if (status < 0) - return status; - - for (i = 0; i < nrfiles; ++i) - if (files[i]) { - status = -1; - fprintf(stderr, "no entry %s in archive\n", files[i]); - } - - return status; -} - -/* - * ar d/q/r code - */ - -static int fixup_arstrtab(struct params *params) -{ - unsigned long new_strtab_len; - struct member *member; - size_t namlen; - char *new_strtab_bytes; - unsigned long curpos; - - new_strtab_len = 0; - for (member = params->members_head; member; member = member->next) { - if (member->strtaboffset == -1UL) - continue; - namlen = strlen(member->name); - if (namlen < 16) { - strcpy(member->arhdr.ar_name, member->name); - member->name = member->arhdr.ar_name; - member->strtaboffset = -1UL; - continue; - } - new_strtab_len += namlen + 2; /* for "\0\n" which is output as "/\n" */ - } - - if (new_strtab_len == 0) { - free(params->strtab.bytes); - params->strtab.bytes = NULL; - params->strtab.len = 0; - return 0; - } - - new_strtab_bytes = malloc(new_strtab_len); - if (!new_strtab_bytes) { - fprintf(stderr, "%s: %s: failed to allocate %lu bytes for updated string table: %s\n", - params->progname, params->arname, new_strtab_len, strerror(errno)); - return -1; - } - - curpos = 0; - for (member = params->members_head; member; member = member->next) { - if (member->strtaboffset == -1UL) - continue; - namlen = strlen(member->name); - member->strtaboffset = curpos; - strcpy(new_strtab_bytes + curpos, member->name); - member->name = new_strtab_bytes + curpos; - *(new_strtab_bytes + curpos + namlen + 1) = '\n'; - curpos += namlen + 2; - } - - free(params->strtab.bytes); - params->strtab.bytes = new_strtab_bytes; - params->strtab.len = new_strtab_len; - - return 0; -} - -static void update_arhdr(struct arhdr *arhdr, struct stat *stbuf) -{ - arhdr->ar_date = stbuf->st_mtime; - arhdr->ar_uid = stbuf->st_uid; - arhdr->ar_gid = stbuf->st_gid; - arhdr->ar_mode = stbuf->st_mode; - - /* stbuf->st_size is the file size in octets, convert it to the size in nonets; - see lib/pdp10-stdio.c:pdp10_fseeko() for the derivation of this formula */ - arhdr->ar_size = (stbuf->st_size / 9) * 8 + ((stbuf->st_size % 9) * 8) / 9; -} - -static int ar_d_process_files(struct params *params, char **files, int nrfiles) -{ - struct member *member; - int i; - char code; - - code = 0; - - for (i = 0; i < nrfiles; ++i) { - member = lookup_member(params, files[i]); - if (!member) { - fprintf(stderr, "%s: %s: member %s not found\n", - params->progname, params->arname, files[i]); - return -1; - } - unlink_member(member); - free(member); - code = 'd'; - if (params->modifiers & MOD_verbose) - printf("%c - %s\n", code, files[i]); - } - - return code; /* >0 if changes, 0 if no changes, -1 if error above */ -} - -static int ar_qr_process_files(struct params *params, char **files, int nrfiles) -{ - struct stat stbuf; - struct member *member; - int i; - char code; - - code = 0; - - for (i = 0; i < nrfiles; ++i) { - if (stat(files[i], &stbuf) < 0) { - fprintf(stderr, "%s: %s: failed to stat: %s\n", - params->progname, files[i], strerror(errno)); - return -1; - } - member = lookup_member(params, files[i]); - if (member && params->operation != 'q') { - if ((params->modifiers & MOD_newer) && stbuf.st_mtime <= member->arhdr.ar_date) - continue; - code = 'r'; - } else { - member = malloc(sizeof *member); - if (!member) { - fprintf(stderr, "%s: %s: failed to allocate %zu bytes for new member\n", - params->progname, params->arname, sizeof *member); - return -1; - } - member->name = files[i]; - member->strtaboffset = -2UL; - append_member(params, member); - code = 'a'; - } - if (params->modifiers & MOD_verbose) - printf("%c - %s\n", code, files[i]); - member->srcoffset = 0; - update_arhdr(&member->arhdr, &stbuf); - } - - return code; /* >0 if changes, 0 if no changes, -1 if error above */ -} - -static char *make_tmparname(struct params *params) -{ - char *last_slash; - unsigned int preflen; - char *tmparname; - - if (!params->pdp10fp) - return params->arname; - - last_slash = strrchr(params->arname, '/'); - if (last_slash) - preflen = last_slash + 1 - params->arname; - else - preflen = 0; - - tmparname = malloc(preflen + 5 + 6 + 1); /* artmpXXXXXX\0 */ - if (!tmparname) { - fprintf(stderr, "%s: %s: failed to allocate %u bytes for temporary archive name: %s\n", - params->progname, params->arname, preflen + 5 + 6 + 1, strerror(errno)); - return NULL; - } - - sprintf(tmparname, "%.*sartmpXXXXXX", preflen, params->arname); - return tmparname; -} - -static PDP10_FILE *make_tmparfp(struct params *params, char *tmparname) -{ - int tmparfd; - PDP10_FILE *tmparfp; - - if (!params->pdp10fp) { - tmparfp = pdp10_fopen(params->arname, "wb"); - if (!tmparfp) - fprintf(stderr, "%s: %s: failed to create: %s\n", params->progname, params->arname, strerror(errno)); - if (!(params->modifiers & MOD_create)) - printf("%s: creating %s\n", params->progname, params->arname); - return tmparfp; - } - - tmparfd = mkstemp(tmparname); - if (tmparfd < 0) { - fprintf(stderr, "%s: %s: failed to create temporary file: %s\n", - params->progname, tmparname, strerror(errno)); - return NULL; - } - - tmparfp = pdp10_fdopen(tmparfd, "wb"); - if (!tmparfp) - fprintf(stderr, "%s: fdopen failed: %s\n", params->progname, strerror(errno)); - - return tmparfp; -} - -static int write_member(struct params *params, const char *tmparname, PDP10_FILE *tmparfp, struct member *member) -{ - PDP10_FILE *srcfp; - const char *srcname; - int status; - - if (member->srcoffset == 0) { - srcname = member->name; - srcfp = pdp10_fopen(srcname, "rb"); - if (!srcfp) { - fprintf(stderr, "%s: %s: failed to open: %s\n", - params->progname, srcname, strerror(errno)); - return -1; - } - } else { - srcname = params->arname; - srcfp = params->pdp10fp; - if (pdp10_fseeko(srcfp, member->srcoffset, PDP10_SEEK_SET) < 0) { - fprintf(stderr, "%s: %s: failed to fseek to member %s: %s\n", - params->progname, srcname, member->name, strerror(errno)); - return -1; - } - } - - if (member->strtaboffset != -1UL) - sprintf(member->arhdr.ar_name, "/%lu", member->strtaboffset); - - status = -1; - do { - if (write_arhdr(params, tmparname, tmparfp, &member->arhdr) < 0) - break; - - if (copy_file_data(params, member->arhdr.ar_size, srcfp, srcname, tmparfp, tmparname) < 0) - break; - - if ((member->arhdr.ar_size & 1) && ar_fputc(params, tmparname, tmparfp, '\n') < 0) - break; - - status = 0; - } while (0); - - if (member->srcoffset == 0) - pdp10_fclose(srcfp); - - return status; -} - -static int write_archive(struct params *params, const char *tmparname, PDP10_FILE *tmparfp) -{ - struct member *member; - struct stat stbuf; - - if (write_armag(params, tmparname, tmparfp) < 0) - return -1; - - if (write_arstrtab(params, tmparname, tmparfp) < 0) - return -1; - - for (member = params->members_head; member; member = member->next) - if (write_member(params, tmparname, tmparfp, member) < 0) - return -1; - - if (!params->pdp10fp) - return 0; - - if (stat(params->arname, &stbuf) < 0) { - fprintf(stderr, "%s: %s: failed to stat: %s\n", - params->progname, params->arname, strerror(errno)); - return -1; - } - - if (chmod(tmparname, stbuf.st_mode) < 0) { - fprintf(stderr, "%s: %s: failed to chmod 0%o: %s\n", - params->progname, tmparname, stbuf.st_mode, strerror(errno)); - return -1; - } - - if (chown(tmparname, stbuf.st_uid, stbuf.st_gid) < 0) { - fprintf(stderr, "%s: %s: failed to chown %u/%u: %s\n", - params->progname, tmparname, stbuf.st_uid, stbuf.st_gid, strerror(errno)); - return -1; - } - - if (unlink(params->arname) < 0) { - fprintf(stderr, "%s: %s: failed to unlink: %s\n", - params->progname, params->arname, strerror(errno)); - return -1; - } - - if (link(tmparname, params->arname) < 0) { - fprintf(stderr, "%s: failed to link %s to %s: %s\n", - params->progname, tmparname, params->arname, strerror(errno)); - return -1; - } - - return 0; -} - -static int ar_dqr(struct params *params, char **files, int nrfiles) -{ - char *tmparname; - PDP10_FILE *tmparfp; - int status; - - if (nrfiles < 1) { - fprintf(stderr, "%s: archive name missing\n", params->progname); - return -1; - } - params->arname = files[0]; - ++files; - --nrfiles; - - params->pdp10fp = pdp10_fopen(params->arname, "rb"); - if (params->pdp10fp != NULL) { - if (read_archive(params) < 0) - return -1; - } else if (params->operation == 'd') { - fprintf(stderr, "%s: %s: failed to open: %s\n", - params->progname, params->arname, strerror(errno)); - return -1; - } - - if (params->operation == 'd') - status = ar_d_process_files(params, files, nrfiles); - else - status = ar_qr_process_files(params, files, nrfiles); - - if (status <= 0) - return status; - - if (fixup_arstrtab(params) < 0) - return -1; - - tmparname = make_tmparname(params); - if (!tmparname) - return -1; - - tmparfp = make_tmparfp(params, tmparname); - if (!tmparfp) - return -1; - - status = write_archive(params, tmparname, tmparfp); - - pdp10_fclose(tmparfp); - - if (params->pdp10fp) { - unlink(tmparname); - free(tmparname); - } - - return status; -} - -/* - * ar d/q/r/t/x dispatcher - */ - -static int ar(struct params *params, char **files, int nrfiles) -{ - switch (params->operation) { - case 'd': - case 'q': - case 'r': - return ar_dqr(params, files, nrfiles); - case 't': - case 'x': - return ar_tx(params, files, nrfiles); - default: - fprintf(stderr, "%s: NYI: operation '%c'\n", params->progname, params->operation); - return -1; - } -} - -/* - * Command-line interface. - */ - -static void usage(const char *progname) - -{ - fprintf(stderr, - "Usage: %s [-]{d,q,r,t,x}[cuvV] archive [member...]\n", - progname); -} - -int main(int argc, char **argv) -{ - struct params params; - char *opts; - - params_init(¶ms); - params.progname = argv[0]; - - if (argc < 2) { - usage(params.progname); - return 1; - } - - opts = argv[1]; - if (*opts == '-') - ++opts; - for (;; ++opts) { - switch (*opts) { - case 'd': - case 'q': - case 'r': - case 't': - case 'x': - params.operation = *opts; - continue; - case 'c': - params.modifiers |= MOD_create; - continue; - case 'u': - params.modifiers |= MOD_newer; - continue; - case 'v': - params.modifiers |= MOD_verbose; - continue; - case 'V': - printf(VERSION); - return 0; - case '\0': - break; - default: - fprintf(stderr, "%s: invalid option: %c\n", params.progname, *opts); - usage(params.progname); - return 1; - } - break; - } - - return ar(¶ms, &argv[2], argc - 2) == 0 ? 0 : 1; -} diff --git a/as/Makefile b/as/Makefile deleted file mode 100644 index 19318b3..0000000 --- a/as/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -# as/Makefile -# Copyright (C) 2013-2015 Mikael Pettersson -# -# This file is part of pdp10-tools. -# -# pdp10-tools is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# pdp10-tools is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with pdp10-tools. If not, see . - -CC=gcc -CFLAGS=-O2 -g -Wall -CPPFLAGS=-I../include - -ASOBJS=assemble.o hashtab.o input.o main.o output.o parse.o scan.o token.o tunit.o -LIBOBJS=../lib/pdp10-elf36.o ../lib/pdp10-extint.o ../lib/pdp10-opcodes.o ../lib/pdp10-stdio.o - -as: $(ASOBJS) $(LIBOBJS) - $(LINK.c) -o $@ $^ - -assemble.o: assemble.h tunit.h hashtab.h -hashtab.o: hashtab.h -input.o: hashtab.h input.h parse.h scan.h tunit.h token.h token.def -main.o: assemble.h input.h output.h tunit.h hashtab.h -output.o: output.h tunit.h hashtab.h -parse.o: input.h scan.h token.h tunit.h token.def hashtab.h -scan.o: scan.h token.h token.def -token.o: token.h token.def -tunit.o: hashtab.h tunit.h - -clean: - rm -f $(ASOBJS) as a.out core.* diff --git a/as/assemble.c b/as/assemble.c deleted file mode 100644 index 35812a3..0000000 --- a/as/assemble.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * assemble.c - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include -#include -#include "assemble.h" -#include "hashtab.h" -#include "tunit.h" -#include "pdp10-extint.h" - -static int assemble_section(struct hashnode *hashnode, void *data) -{ - struct section *section = container_of(hashnode, struct section, hashnode); - struct tunit *tunit = data; - unsigned long dot; - struct stmt *stmt; - - /* if it's not .text-like then we have nothing to do (for now) */ - if (section->sh_type != SHT_PROGBITS - || section->sh_flags != (SHF_ALLOC | SHF_EXECINSTR)) - return 0; - - section->dot = (section->dot + 3) & ~(unsigned long)3; - - section->image = malloc(section->dot * sizeof(pdp10_uint9_t)); - if (!section->image) { - fprintf(stderr, "%s: %s: failed to allocate %zu bytes for text image: %s\n", - tunit->progname, __FUNCTION__, section->dot * sizeof(pdp10_uint9_t), strerror(errno)); - return -1; - } - - dot = 0; - for (stmt = section->head; stmt; stmt = stmt->next) { - switch (stmt->tag) { - case S_LABEL: - { - struct symbol *symbol; - - symbol = tunit_symbol_lookup(tunit, stmt->u.symbol.name); - if (!symbol) - return -1; - - if (symbol->section != section - || !symbol->defined - || symbol->st_value != dot) - return -1; - - break; - } - case S_INSN: - { - pdp10_uint36_t word; - struct pdp10_ext_uint36 ext36; - unsigned int i; - - if (dot >= section->dot) { - fprintf(stderr, "%s: %s: internal error: text image overflow\n", tunit->progname, __FUNCTION__); - return -1; - } - word = - ((pdp10_uint36_t)(stmt->u.insn.opcode & 0x1FF) << (36 - 9) - | ((stmt->u.insn.accumulator & 0xF) << (36 - 13)) - | ((stmt->u.insn.at & 1) << (36 - 14)) - | ((stmt->u.insn.indexreg & 0xF) << (36 - 18)) - | (stmt->u.insn.address & PDP10_UINT18_MAX)); - pdp10_uint36_to_ext(word, &ext36); - for (i = 0; i < 4; ++i) - section->image[dot + i] = ext36.nonet[i]; - dot += 4; - break; - } - default: - break; - } - } - - if (dot != section->dot) { - fprintf(stderr, "%s: %s: internal error: text image size mismatch\n", tunit->progname, __FUNCTION__); - return -1; - } - - return 0; -} - -int assemble(struct tunit *tunit) -{ - return hashtab_enumerate(&tunit->sections, assemble_section, tunit); -} diff --git a/as/assemble.h b/as/assemble.h deleted file mode 100644 index 03ebae0..0000000 --- a/as/assemble.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * assemble.h - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#ifndef ASSEMBLE_H -#define ASSEMBLE_H - -#include "tunit.h" - -int assemble(struct tunit *tunit); - -#endif /* ASSEMBLE_H */ diff --git a/as/hashtab.c b/as/hashtab.c deleted file mode 100644 index 1b1445a..0000000 --- a/as/hashtab.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * hashtab.c - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include -#include -#include "hashtab.h" - -static struct hashnode **hashtab_alloc_bucket(unsigned int nrelem) -{ - size_t nrbytes; - struct hashnode **bucket; - unsigned int i; - - nrbytes = nrelem * sizeof(struct hashnode*); - bucket = malloc(nrbytes); - if (!bucket) { - fprintf(stderr, "%s: malloc(%zu) failed: %s\n", __FUNCTION__, nrbytes, strerror(errno)); - return NULL; - } - for (i = 0; i < nrelem; ++i) - bucket[i] = NULL; - return bucket; -} - -int hashtab_init(struct hashtab *hashtab, unsigned int log2size, hashtab_eq_func_t eq_func) -{ - unsigned int size; - - size = 1 << log2size; - hashtab->log2size = log2size; - hashtab->mask = size - 1; - hashtab->used = 0; - hashtab->eq_func = eq_func; - hashtab->bucket = hashtab_alloc_bucket(size); - return hashtab->bucket ? 0 : -1; -} - -struct hashnode *hashtab_lookup(const struct hashtab *hashtab, uintptr_t hashval, const void *data) -{ - unsigned int i; - struct hashnode *hashnode; - - i = hashval & hashtab->mask; - - hashnode = hashtab->bucket[i]; - while (hashnode != NULL) { - if (hashnode->hashval == hashval - && (hashtab->eq_func == NULL || (*hashtab->eq_func)(hashnode, data) != 0)) - break; - hashnode = hashnode->next; - } - - return hashnode; -} - -static int hashtab_grow(struct hashtab *hashtab) -{ - unsigned int old_size, new_size, new_mask, i; - struct hashnode **old_bucket, **new_bucket; - - old_size = 1 << hashtab->log2size; - new_size = old_size << 1; - new_bucket = hashtab_alloc_bucket(new_size); - if (!new_bucket) - return -1; - - old_bucket = hashtab->bucket; - hashtab->log2size += 1; - new_mask = new_size - 1; - hashtab->mask = new_mask; - hashtab->bucket = new_bucket; - - for (i = 0; i < old_size; ++i) { - struct hashnode *hashnode = old_bucket[i]; - while (hashnode != NULL) { - struct hashnode *next = hashnode->next; - unsigned int j = hashnode->hashval & new_mask; - hashnode->next = new_bucket[j]; - new_bucket[j] = hashnode; - hashnode = next; - } - } - - free(old_bucket); - return 0; -} - -int hashtab_insert(struct hashtab *hashtab, struct hashnode *hashnode) -{ - unsigned int i, size; - - i = hashnode->hashval & hashtab->mask; - hashnode->next = hashtab->bucket[i]; - hashtab->bucket[i] = hashnode; - hashtab->used += 1; - size = 1 << hashtab->log2size; - if (hashtab->used > (4 * size) / 5) /* rehash at 80% */ - return hashtab_grow(hashtab); - return 0; -} - -struct hashnode *hashtab_reset(struct hashtab *hashtab) -{ - unsigned int i, size; - struct hashnode **bucket, *all_nodes, *head, *tail; - - all_nodes = NULL; - bucket = hashtab->bucket; - size = 1 << hashtab->log2size; - - for (i = 0; i < size; ++i) { - head = bucket[i]; - if (head) { - bucket[i] = NULL; - tail = head; - while (tail->next) - tail = tail->next; - tail->next = all_nodes; - all_nodes = head; - } - } - - hashtab->used = 0; - return all_nodes; -} - -int hashtab_enumerate(const struct hashtab *hashtab, - int (*func)(struct hashnode *hashnode, void *data), - void *data) -{ - unsigned int i, size; - struct hashnode **bucket, *head; - int status; - - bucket = hashtab->bucket; - size = 1 << hashtab->log2size; - - for (i = 0; i < size; ++i) { - head = bucket[i]; - while (head != NULL) { - status = (*func)(head, data); - if (status != 0) - return status; - head = head->next; - } - } - - return 0; -} diff --git a/as/hashtab.h b/as/hashtab.h deleted file mode 100644 index bfad267..0000000 --- a/as/hashtab.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * hashtab.h - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#ifndef HASHTAB_H -#define HASHTAB_H - -#include /* uintptr_t */ - -struct hashnode { - uintptr_t hashval; - struct hashnode *next; -}; - -typedef int (*hashtab_eq_func_t)(const struct hashnode *hashnode, const void *data); - -struct hashtab { - unsigned int log2size; - unsigned int mask; /* INV: mask == (1 << log2size) - 1 */ - unsigned int used; - hashtab_eq_func_t eq_func; - struct hashnode **bucket; -}; - -int hashtab_init(struct hashtab *hashtab, unsigned int log2size, hashtab_eq_func_t eq_func); - -struct hashnode *hashtab_lookup(const struct hashtab *hashtab, uintptr_t hashval, const void *data); - -int hashtab_insert(struct hashtab *hashtab, struct hashnode *hashnode); - -struct hashnode *hashtab_reset(struct hashtab *hashtab); - -int hashtab_enumerate(const struct hashtab *hashtab, - int (*func)(struct hashnode *hashnode, void *data), - void *data); - -#endif /* HASHTAB_H */ diff --git a/as/input.c b/as/input.c deleted file mode 100644 index a0683a4..0000000 --- a/as/input.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * input.c - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include -#include -#include "hashtab.h" -#include "input.h" -#include "parse.h" -#include "scan.h" -#include "tunit.h" - -static int do_append(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt, unsigned long dot_incr) -{ - struct stmt *stmt2; - struct section *section; - - stmt2 = malloc(sizeof *stmt2); - if (!stmt2) { - fprintf(stderr, "%s: %s line %u: malloc(%zu) failed: %s\n", - scan_state->progname, scan_state->filename, scan_state->linenr, sizeof *stmt2, strerror(errno)); - return -1; - } - - *stmt2 = *stmt; - stmt2->next = NULL; - - section = tunit->cursect; - - *section->tailptr = stmt2; - section->tailptr = &stmt2->next; - section->dot += dot_incr; - - return 0; -} - -static int do_dot_file(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - struct symbol *symbol; - - symbol = tunit_symbol_enter(tunit, stmt->u.string.text); - if (!symbol) - return -1; - - symbol->section = NULL; - symbol->defined = 1; - symbol->st_value = 0; - symbol->st_size = 0; - symbol->st_info = ELF_ST_INFO(STB_LOCAL, STT_FILE); - - return 0; -} - -static int do_dot_globl(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - struct symbol *symbol; - - symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name); - if (!symbol) - return -1; - - if (ELF_ST_BIND(symbol->st_info) != STB_LOCAL) { - fprintf(stderr, "%s: %s line %u: symbol %s already has non-zero binding type %u\n", - scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name, ELF_ST_BIND(symbol->st_info)); - return -1; - } - - symbol->st_info = ELF_ST_INFO(STB_GLOBAL, ELF_ST_TYPE(symbol->st_info)); - - return 0; -} - -static int do_dot_ident(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - struct strtab *strtab; - - strtab = tunit_strtab_section_enter(tunit, ".comment"); - if (!strtab) - return -1; - - if (strtab->section.sh_type == SHT_NULL) { - /* The ELF specification doesn't specify attribute values for .comment - * sections, apart from sh_type, but GNU binutils formats them as string - * tables with the following attribute values. - */ - strtab->section.sh_type = SHT_PROGBITS; - strtab->section.sh_flags = SHF_MERGE | SHF_STRINGS; - strtab->section.sh_entsize = 1; - strtab->section.sh_addralign = 1; - } - - (void)strtab_enter(tunit, strtab, stmt->u.string.text); - - return 0; -} - -static int do_dot_size(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - struct symbol *symbol; - - symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name); - if (!symbol) - return -1; - - if (!symbol->section - || !symbol->defined) { - fprintf(stderr, "%s: %s line %u: symbol %s undefined\n", - scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name); - return -1; - } - if (symbol->st_size) { - fprintf(stderr, "%s: %s line %u: size of symbol %s already defined\n", - scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name); - return -1; - } - if (symbol->section != tunit->cursect) { - fprintf(stderr, "%s: %s line %u: symbol %s is not defined in current section\n", - scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name); - return -1; - } - - symbol->st_size = tunit->cursect->dot - symbol->st_value; - - return 0; -} - -static int do_dot_text(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - struct section *section; - - section = tunit_section_enter(tunit, ".text"); - if (!section) - return -1; - - if (section->sh_type == SHT_NULL) { - section->sh_type = SHT_PROGBITS; - section->sh_flags = SHF_ALLOC | SHF_EXECINSTR; - section->sh_addralign = 4; /* XXX: PDP10-specific */ - } - - tunit->cursect = section; - - return 0; -} - -static int do_dot_type_function(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - struct symbol *symbol; - - symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name); - if (!symbol) - return -1; - - if (ELF_ST_TYPE(symbol->st_info) != STT_NOTYPE) { - fprintf(stderr, "%s: %s line %u: symbol %s already has non-zero type %u\n", - scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name, ELF_ST_TYPE(symbol->st_info)); - return -1; - } - - symbol->st_info = ELF_ST_INFO(ELF_ST_BIND(symbol->st_info), STT_FUNC); - - return 0; -} - -static int do_label(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - struct symbol *symbol; - struct section *section; - - symbol = tunit_symbol_enter(tunit, stmt->u.symbol.name); - if (!symbol) - return -1; - - if (symbol->section - || symbol->defined - || symbol->st_value) { - fprintf(stderr, "%s: %s line %u: symbol %s already defined\n", - scan_state->progname, scan_state->filename, scan_state->linenr, stmt->u.symbol.name); - return -1; - } - - section = tunit->cursect; - - symbol->section = section; - symbol->defined = 1; - symbol->st_value = section->dot; - - return do_append(scan_state, tunit, stmt, 0); -} - -static int do_insn(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - if (tunit->cursect->dot & 3) { /* XXX: PDP10-specific */ - fprintf(stderr, "%s: %s line %u: misaligned instruction\n", - scan_state->progname, scan_state->filename, scan_state->linenr); - return -1; - } - return do_append(scan_state, tunit, stmt, 4); /* XXX: PDP10-specific sizeof */ -} - -static int interpret(struct scan_state *scan_state, struct tunit *tunit, struct stmt *stmt) -{ - switch (stmt->tag) { - case S_DOT_FILE: - return do_dot_file(scan_state, tunit, stmt); - case S_DOT_GLOBL: - return do_dot_globl(scan_state, tunit, stmt); - case S_DOT_IDENT: - return do_dot_ident(scan_state, tunit, stmt); - case S_DOT_SIZE: - return do_dot_size(scan_state, tunit, stmt); - case S_DOT_TEXT: - return do_dot_text(scan_state, tunit, stmt); - case S_DOT_TYPE_FUNCTION: - return do_dot_type_function(scan_state, tunit, stmt); - case S_LABEL: - return do_label(scan_state, tunit, stmt); - case S_INSN: - return do_insn(scan_state, tunit, stmt); - default: - fprintf(stderr, "%s: %s line %u: parser returned unexpected stmt->tag %u\n", - scan_state->progname, scan_state->filename, scan_state->linenr, stmt->tag); - return -1; - } -} - -int input(char **files, int nrfiles, struct tunit *tunit) -{ - char fake_file[3]; - char *fake_files[1]; - struct scan_state scan_state; - int i; - struct stmt stmt; - int status; - - if (nrfiles <= 0) { - fake_file[0] = '-'; - fake_file[1] = '-'; - fake_file[2] = '\0'; - fake_files[0] = fake_file; - files = fake_files; - nrfiles = 1; - } - - scan_init(&scan_state, tunit->progname); - - for (i = 0; i < nrfiles; ++i) { - if (scan_open(&scan_state, files[i]) < 0) - return -1; - for (;;) { - status = parse_stmt(&scan_state, &stmt); - if (status < 0) - return -1; - if (status == 0) - break; - if (interpret(&scan_state, tunit, &stmt) < 0) - return -1; - } - } - - return 0; -} diff --git a/as/input.h b/as/input.h deleted file mode 100644 index 16090e4..0000000 --- a/as/input.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * input.h - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#ifndef INPUT_H -#define INPUT_H - -#include "tunit.h" - -int input(char **files, int nrfiles, struct tunit *tunit); - -#endif /* INPUT_H */ diff --git a/as/main.c b/as/main.c deleted file mode 100644 index 02dec70..0000000 --- a/as/main.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * main.c -- as clone for pdp10-elf - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include "assemble.h" -#include "input.h" -#include "output.h" -#include "tunit.h" - -#define VERSION "pdp10-tools as version 0.2, built " __DATE__ " " __TIME__ "\n" - -int main(int argc, char **argv) -{ - const char *outfile = "a.out"; - struct tunit tunit; - - for (;;) { - int ch; - - ch = getopt(argc, argv, "vo:VQ:"); - switch (ch) { - case 'Q': /* SVR4 compat, ignored */ - continue; - case 'V': /* SVR4 compat, alias for -v */ - case 'v': - printf(VERSION); - continue; - case 'o': - outfile = optarg; - continue; - case -1: - break; - default: - fprintf(stderr, "Usage: %s [-v] [-o outfile] [files..]\n", argv[0]); - return 1; - } - break; - } - - if (tunit_init(&tunit, argv[0]) < 0) - return 1; - - if (input(&argv[optind], argc - optind, &tunit) < 0) - return 1; - - if (assemble(&tunit) < 0) - return 1; - - if (output(&tunit, outfile) < 0) - return 1; - - tunit_fini(&tunit); - - return 0; -} diff --git a/as/output.c b/as/output.c deleted file mode 100644 index 26880a2..0000000 --- a/as/output.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * output.c - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include -#include -#include "pdp10-elf36.h" -#include "pdp10-stdint.h" -#include "pdp10-stdio.h" -#include "hashtab.h" -#include "output.h" -#include "tunit.h" - -static int output_padding(PDP10_FILE *pdp10fp, unsigned int nrbytes) -{ - for (; nrbytes; --nrbytes) - if (pdp10_elf36_write_uint9(pdp10fp, '\0') < 0) - return -1; - return 0; -} - -struct context { - struct tunit *tunit; - Elf36_Word shnum; - Elf36_Word offset; - struct strtab shstrtab; - Elf36_Word symnum; - struct strtab symstrtab; - PDP10_FILE *pdp10fp; -}; - -static int append_section(struct context *context, struct section *section) -{ - if (section->dot == 0) - return 0; - - /* enter name before reading ->dot to allow this to work for .shstrtab too */ - section->sh_name = strtab_enter(context->tunit, &context->shstrtab, section->name); - if (section->sh_name == 0) - return -1; - - section->st_shndx = context->shnum; - ++context->shnum; - - section->sh_offset = (context->offset + (section->sh_addralign - 1)) & ~(section->sh_addralign - 1); - context->offset = section->sh_offset + section->dot; - - return 0; -} - -static int process_section(struct hashnode *hashnode, void *data) -{ - struct section *section = container_of(hashnode, struct section, hashnode); - struct context *context = data; - - return append_section(context, section); -} - -static int output_section_prologue(struct context *context, struct section *section) -{ - if (section->st_shndx != context->shnum) - abort(); - ++context->shnum; - - if (section->sh_offset < context->offset) - abort(); - - if (output_padding(context->pdp10fp, section->sh_offset - context->offset) < 0) - return -1; - - return 0; -} - -static void output_section_epilogue(struct context *context, struct section *section) -{ - context->offset = section->sh_offset + section->dot; -} - -static int output_section(struct hashnode *hashnode, void *data) -{ - struct section *section = container_of(hashnode, struct section, hashnode); - struct context *context = data; - - if (section->dot == 0 || (section->image == NULL && section->output == NULL)) - return 0; - - if (output_section_prologue(context, section) < 0) - return -1; - - if (section->output) { - if (section->output(context->pdp10fp, section) < 0) - return -1; - } else { - unsigned int i; - - for (i = 0; i < section->dot; ++i) - if (pdp10_elf36_write_uint9(context->pdp10fp, section->image[i]) < 0) - return -1; - } - - output_section_epilogue(context, section); - - return 0; -} - -static int output_section_header(struct context *context, const struct section *section) -{ - Elf36_Shdr shdr; - - shdr.sh_name = section->sh_name; - shdr.sh_type = section->sh_type; - shdr.sh_flags = section->sh_flags; - shdr.sh_addr = 0; - shdr.sh_offset = section->sh_offset; - shdr.sh_size = section->dot; - shdr.sh_link = section->sh_link; - shdr.sh_info = 0; /* XXX: for symtab, LAST_LOCAL + 1 */ - shdr.sh_addralign = section->sh_addralign; - shdr.sh_entsize = section->sh_entsize; - - return pdp10_elf36_write_shdr(context->pdp10fp, &shdr); -} - -static int output_shdr(struct hashnode *hashnode, void *data) -{ - struct section *section = container_of(hashnode, struct section, hashnode); - struct context *context = data; - - if (section->dot == 0) - return 0; - - return output_section_header(context, section); -} - -static int output_strtab(struct context *context, struct strtab *strtab) -{ - return output_section(&strtab->section.hashnode, context); -} - -static int process_symbol(struct hashnode *hashnode, void *data) -{ - struct symbol *symbol = container_of(hashnode, struct symbol, hashnode); - struct context *context = data; - - ++context->symnum; - - symbol->st_name = strtab_enter(context->tunit, &context->symstrtab, symbol->name); - if (symbol->st_name == 0) - return -1; - - return 0; -} - -struct finalize_symbol_context { - Elf36_Sym *symtab; - unsigned int i; -}; - -static int finalize_symbol(struct hashnode *hashnode, void *data) -{ - struct symbol *symbol = container_of(hashnode, struct symbol, hashnode); - struct finalize_symbol_context *fsctx = data; - Elf36_Word st_shndx; - - fsctx->symtab[fsctx->i].st_name = symbol->st_name; - fsctx->symtab[fsctx->i].st_value = symbol->st_value; - fsctx->symtab[fsctx->i].st_size = symbol->st_size; - fsctx->symtab[fsctx->i].st_info = symbol->st_info; - fsctx->symtab[fsctx->i].st_other = STV_DEFAULT; - - if (symbol->section) - st_shndx = symbol->section->st_shndx; - else - st_shndx = SHN_ABS; - fsctx->symtab[fsctx->i].st_shndx = st_shndx; - - ++fsctx->i; - - return 0; -} - -int output(struct tunit *tunit, const char *outfile) -{ - struct context context; - Elf36_Sym *symtab; - struct section section_symtab; - Elf36_Ehdr ehdr; - - context.tunit = tunit; - context.shnum = 1; - context.offset = ELF36_EHDR_SIZEOF; - strtab_init(&context.shstrtab, ".shstrtab"); - context.symnum = 0; - strtab_init(&context.symstrtab, ".strtab"); - context.pdp10fp = NULL; - - if (hashtab_enumerate(&tunit->sections, process_section, &context) < 0) - return -1; - - if (hashtab_enumerate(&tunit->symbols, process_symbol, &context) < 0) - return -1; - - symtab = NULL; - section_init(§ion_symtab, ".symtab"); - - /* if we have symbols, synthesize .strtab and .symtab */ - if (context.symnum) { - struct finalize_symbol_context fsctx; - - if (append_section(&context, &context.symstrtab.section) < 0) - return -1; - - ++context.symnum; /* for initial stub entry */ - - symtab = malloc(context.symnum * sizeof(Elf36_Sym)); - if (!symtab) { - fprintf(stderr, "%s: failed to allocate %zu bytes for Elf36 symbol table: %s\n", - tunit->progname, context.symnum * sizeof(Elf36_Sym), strerror(errno)); - return -1; - } - - symtab[0].st_name = 0; - symtab[0].st_value = 0; - symtab[0].st_size = 0; - symtab[0].st_info = ELF36_ST_INFO(STB_LOCAL, STT_NOTYPE); - symtab[0].st_other = 0; - symtab[0].st_shndx = SHN_UNDEF; - - fsctx.symtab = symtab; - fsctx.i = 1; - - if (hashtab_enumerate(&tunit->symbols, finalize_symbol, &fsctx) < 0) - return -1; - - section_symtab.sh_type = SHT_SYMTAB; - section_symtab.sh_entsize = ELF36_SYM_SIZEOF; - section_symtab.sh_link = context.symstrtab.section.st_shndx; - section_symtab.sh_addralign = 4; /* XXX: PDP10-specific */ - section_symtab.dot = context.symnum * ELF36_SYM_SIZEOF; - - if (append_section(&context, §ion_symtab) < 0) - return -1; - } - - /* if we have sections, synthesize .shstrtab */ - if (context.shnum > 1) { - if (append_section(&context, &context.shstrtab.section) < 0) - return -1; - - /* align context.offset for the section header table, which is last in the file */ - context.offset = (context.offset + (4 - 1)) & ~(Elf36_Word)(4 - 1); - } else { - context.shnum = 0; - context.offset = 0; - } - - ehdr.e_ident[EI_MAG0] = ELFMAG0; - ehdr.e_ident[EI_MAG1] = ELFMAG1; - ehdr.e_ident[EI_MAG2] = ELFMAG2; - ehdr.e_ident[EI_MAG3] = ELFMAG3; - ehdr.e_ident[EI_CLASS] = ELFCLASS36; - ehdr.e_ident[EI_DATA] = ELFDATA2MSB; - ehdr.e_ident[EI_VERSION] = EV_CURRENT; - ehdr.e_ident[EI_OSABI] = ELFOSABI_NONE; - ehdr.e_ident[EI_ABIVERSION] = 0; - { - int i; - - for (i = EI_PAD; i < EI_NIDENT; ++i) - ehdr.e_ident[i] = 0; - } - ehdr.e_type = ET_REL; - ehdr.e_machine = EM_PDP10; - ehdr.e_version = EV_CURRENT; - ehdr.e_entry = 0; - ehdr.e_phoff = 0; - ehdr.e_shoff = context.offset; - ehdr.e_flags = 0; - ehdr.e_ehsize = ELF36_EHDR_SIZEOF; - ehdr.e_phentsize = 0; - ehdr.e_phnum = 0; - ehdr.e_shentsize = ELF36_SHDR_SIZEOF; - ehdr.e_shnum = context.shnum; - ehdr.e_shstrndx = context.shstrtab.section.st_shndx; - - context.pdp10fp = pdp10_fopen(outfile, "wb"); - if (!context.pdp10fp) { - fprintf(stderr, "%s: failed to open %s: %s\n", tunit->progname, outfile, strerror(errno)); - return -1; - } - - if (pdp10_elf36_write_ehdr(context.pdp10fp, &ehdr) < 0) - return -1; - - context.shnum = 1; - context.offset = ELF36_EHDR_SIZEOF; - - if (hashtab_enumerate(&tunit->sections, output_section, &context) < 0) - return -1; - - if (context.symnum) { - unsigned int i; - - if (output_strtab(&context, &context.symstrtab) < 0) - return -1; - - if (output_section_prologue(&context, §ion_symtab) < 0) - return -1; - - for (i = 0; i < context.symnum; ++i) - if (pdp10_elf36_write_sym(context.pdp10fp, &symtab[i]) < 0) - return -1; - - output_section_epilogue(&context, §ion_symtab); - } - - if (context.shnum > 1) { - struct section section0; - - if (output_strtab(&context, &context.shstrtab) < 0) - return -1; - - if (ehdr.e_shoff < context.offset) - abort(); - if (output_padding(context.pdp10fp, ehdr.e_shoff - context.offset) < 0) - return -1; - section_init(§ion0, ""); - section0.sh_addralign = 0; - if (output_section_header(&context, §ion0) < 0) - return -1; - if (hashtab_enumerate(&tunit->sections, output_shdr, &context) < 0) - return -1; - if (context.symnum) { - if (output_section_header(&context, &context.symstrtab.section) < 0) - return -1; - if (output_section_header(&context, §ion_symtab) < 0) - return -1; - } - if (output_section_header(&context, &context.shstrtab.section) < 0) - return -1; - } - - pdp10_fclose(context.pdp10fp); - - return 0; -} diff --git a/as/output.h b/as/output.h deleted file mode 100644 index c5b975e..0000000 --- a/as/output.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * output.h - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#ifndef OUTPUT_H -#define OUTPUT_H - -#include "tunit.h" - -int output(struct tunit *tunit, const char *outfile); - -#endif /* OUTPUT_H */ diff --git a/as/parse.c b/as/parse.c deleted file mode 100644 index ba91974..0000000 --- a/as/parse.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * parse.c - * Copyright (C) 2013-2015 Mikael Pettersson - * - * This file is part of pdp10-tools. - * - * pdp10-tools is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * pdp10-tools is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with pdp10-tools. If not, see . - */ -#include -#include -#include -#include "pdp10-opcodes.h" -#include "input.h" /* for struct stmt */ -#include "parse.h" -#include "scan.h" -#include "token.h" - -static int error(struct scan_state *scan_state, const char *msg, enum token token, const union token_attribute *token_attr) -{ - fprintf(stderr, "%s: %s line %u: syntax error: %s; current token is ", - scan_state->progname, scan_state->filename, scan_state->linenr, msg); - token_print(stderr, token, token_attr); - fprintf(stderr, "\n"); - return -1; -} - -static int parse_dot_file_or_ident(struct scan_state *scan_state, struct stmt *stmt, enum stmt_tag tag, const char *errmsg) -{ - enum token token; - union token_attribute token_attr; - - token = scan_token(scan_state, &token_attr); - if (token == T_STRING) { - stmt->u.string.text = token_attr.text; - token = scan_token(scan_state, &token_attr); - if (token == T_NEWLINE) { - stmt->tag = tag; - return 1; - } - } - return error(scan_state, errmsg, token, &token_attr); -} - -static int parse_dot_file(struct scan_state *scan_state, struct stmt *stmt) -{ - return parse_dot_file_or_ident(scan_state, stmt, S_DOT_FILE, "junk after .file directive"); -} - -static int parse_dot_ident(struct scan_state *scan_state, struct stmt *stmt) -{ - return parse_dot_file_or_ident(scan_state, stmt, S_DOT_IDENT, "junk after .ident directive"); -} - -static int parse_dot_globl(struct scan_state *scan_state, struct stmt *stmt) -{ - enum token token; - union token_attribute token_attr; - - token = scan_token(scan_state, &token_attr); - if (token == T_SYMBOL) { - stmt->u.symbol.name = token_attr.text; - token = scan_token(scan_state, &token_attr); - if (token == T_NEWLINE) { - stmt->tag = S_DOT_GLOBL; - return 1; - } - } - return error(scan_state, "junk after .globl directive", token, &token_attr); -} - -/* for now, accepts: .size ,.- */ -static int parse_dot_size(struct scan_state *scan_state, struct stmt *stmt) -{ - enum token token; - union token_attribute token_attr; - - token = scan_token(scan_state, &token_attr); - if (token == T_SYMBOL) { - stmt->u.symbol.name = token_attr.text; - token = scan_token(scan_state, &token_attr); - if (token == T_COMMA) { - token = scan_token(scan_state, &token_attr); - if (token == T_DOT) { - token = scan_token(scan_state, &token_attr); - if (token == T_MINUS) { - token = scan_token(scan_state, &token_attr); - if (token == T_SYMBOL - && strcmp(token_attr.text, stmt->u.symbol.name) == 0) { - token = scan_token(scan_state, &token_attr); - if (token == T_NEWLINE) { - stmt->tag = S_DOT_SIZE; - return 1; - } - } - } - } - } - } - return error(scan_state, "junk after .size directive", token, &token_attr); -} - -static int parse_dot_text(struct scan_state *scan_state, struct stmt *stmt) -{ - enum token token; - union token_attribute token_attr; - - token = scan_token(scan_state, &token_attr); - if (token == T_NEWLINE) { - stmt->tag = S_DOT_TEXT; - return 1; - } - return error(scan_state, "junk after .text directive", token, &token_attr); -} - -static int parse_dot_type(struct scan_state *scan_state, struct stmt *stmt) -{ - enum token token; - union token_attribute token_attr; - - token = scan_token(scan_state, &token_attr); - if (token == T_SYMBOL) { - stmt->u.symbol.name = token_attr.text; - token = scan_token(scan_state, &token_attr); - if (token == T_COMMA) { - token = scan_token(scan_state, &token_attr); - if (token == T_AT) { - token = scan_token(scan_state, &token_attr); - if (token == T_SYMBOL - && strcmp(token_attr.text, "function") == 0) { - token = scan_token(scan_state, &token_attr); - if (token == T_NEWLINE) { - stmt->tag = S_DOT_TYPE_FUNCTION; - return 1; - } - } - } - } - } - return error(scan_state, "junk after .type directive", token, &token_attr); -} - -/* - * Recognize: - * - *