259 lines
5.1 KiB
C
259 lines
5.1 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <dirent.h>
|
|
#include <stdbool.h>
|
|
#include <unistd.h>
|
|
#include "parser.h"
|
|
#include "translator.h"
|
|
#include "bootstrap.h"
|
|
#include "util.h"
|
|
|
|
#include <limits.h>
|
|
#ifndef PATH_MAX
|
|
#ifdef __linux__
|
|
#include <linux/limits.h>
|
|
#else
|
|
#define PATH_MAX 512
|
|
#endif
|
|
#endif
|
|
|
|
typedef struct {
|
|
char** files;
|
|
char** fnames;
|
|
int filecount;
|
|
int filessz;
|
|
char* output;
|
|
} TRANSLATIONLIST;
|
|
|
|
char* getname(char* f, int len) {
|
|
int startind = 0;
|
|
int endind = len - 1;
|
|
bool readsmt = false;
|
|
|
|
for(int i = endind; i >= 0; i--) {
|
|
if(f[i] == '/') {
|
|
if(!readsmt) {
|
|
endind = i-1;
|
|
f[i] = '\0';
|
|
continue;
|
|
}
|
|
startind = i+1;
|
|
break;
|
|
}
|
|
if(f[i] == '.')
|
|
endind = i-1;
|
|
readsmt = true;
|
|
}
|
|
|
|
int size = sizeof(char)*(endind - startind + 2);
|
|
char* startstr = f + (sizeof(char)*startind);
|
|
char* retstr = (char*)malloc(size);
|
|
snprintf(retstr, size, "%s", startstr);
|
|
return retstr;
|
|
}
|
|
|
|
char* getfullname(char* f, int len) {
|
|
int endind = len - 1;
|
|
bool readsmt = false;
|
|
|
|
for(int i = endind; i >= 0; i--) {
|
|
if(f[i] == '/') {
|
|
if(!readsmt) {
|
|
endind = i-1;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
if(f[i] == '.')
|
|
endind = i-1;
|
|
readsmt = true;
|
|
}
|
|
|
|
int size = sizeof(char)*(endind + 2);
|
|
char* retstr = (char*)malloc(size);
|
|
snprintf(retstr, size, "%s", f);
|
|
return retstr;
|
|
}
|
|
|
|
bool isdotvm(char* f, int extind) {
|
|
char* extstr = f + (sizeof(char) * extind);
|
|
return strcmp(extstr, ".vm") == 0;
|
|
}
|
|
|
|
bool isdir(char* f, int len) {
|
|
bool readsmt = false;
|
|
for(int i = len-1; i >= 0; i--) {
|
|
if(f[i] == '.')
|
|
if(readsmt)
|
|
return false;
|
|
else
|
|
continue;
|
|
if(f[i] == '/')
|
|
return 1;
|
|
readsmt = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
char* getoutname(char* input, int len, bool isdir) {
|
|
char* outname;
|
|
if(isdir) {
|
|
char olddir[PATH_MAX];
|
|
getcwd(olddir, PATH_MAX);
|
|
|
|
chdir(input);
|
|
char buf[PATH_MAX];
|
|
getcwd(buf, PATH_MAX);
|
|
|
|
chdir(olddir);
|
|
|
|
char* name = getname(buf, strlen(buf));
|
|
int sz = sizeof(char) * (strlen(name)+len+6);
|
|
outname = (char*)malloc(sz);
|
|
snprintf(outname, sz, "%s/%s.asm", input, name);
|
|
free(name);
|
|
}
|
|
else {
|
|
char* name = getfullname(input, len);
|
|
int sz = sizeof(char) * (strlen(name)+5);
|
|
outname = (char*)malloc(sz);
|
|
snprintf(outname, sz, "%s.asm", name);
|
|
free(name);
|
|
}
|
|
return outname;
|
|
}
|
|
|
|
void addfile(TRANSLATIONLIST* l, char* fullname, char* name) {
|
|
int count = l->filecount;
|
|
int targsize = (count + 1) * sizeof(char*);
|
|
|
|
if(l->filessz < targsize) {
|
|
int newsz = targsize * 2;
|
|
l->files = realloc(l->files, newsz);
|
|
l->fnames = realloc(l->fnames, newsz);
|
|
l->filessz = newsz;
|
|
}
|
|
|
|
l->files[count] = fullname;
|
|
l->fnames[count] = name;
|
|
l->filecount++;
|
|
}
|
|
|
|
TRANSLATIONLIST* getfiles(char* input) {
|
|
int filessz = sizeof(char*) * 16;
|
|
TRANSLATIONLIST* filelist = (TRANSLATIONLIST*)malloc(sizeof(TRANSLATIONLIST));
|
|
filelist->files = (char**)malloc(filessz);
|
|
filelist->fnames = (char**)malloc(filessz);
|
|
filelist->filessz = filessz;
|
|
filelist->filecount = 0;
|
|
|
|
int inplen = strlen(input);
|
|
bool isitdir = isdir(input, inplen);
|
|
if(isitdir) {
|
|
DIR* dir = opendir(input);
|
|
|
|
if(dir == NULL) {
|
|
fprintf(stderr, "%s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
struct dirent* thisfile;
|
|
while(thisfile = readdir(dir), thisfile != NULL) {
|
|
int len = strlen(thisfile->d_name);
|
|
if(len > 3) {
|
|
int extind = len - 3;
|
|
if(isdotvm(thisfile->d_name, extind)) {
|
|
int sz = sizeof(char)*(len+inplen+2);
|
|
char* str = (char*)malloc(sz);
|
|
snprintf(str, sz, "%s/%s", input, thisfile->d_name);
|
|
char* name = getname(thisfile->d_name, len);
|
|
addfile(filelist, str, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
closedir(dir);
|
|
|
|
if(filelist->filecount <= 0) {
|
|
fprintf(stderr, "Directory doesn't have any .vm file\n");
|
|
exit(1);
|
|
}
|
|
|
|
filelist->output = getoutname(input, inplen, isitdir);
|
|
}
|
|
else {
|
|
int extind = inplen - 3;
|
|
if(isdotvm(input, extind)){
|
|
char* name = getname(input, inplen);
|
|
char* f = heapstr(input, inplen);
|
|
addfile(filelist, f, name);
|
|
}
|
|
else {
|
|
fprintf(stderr, "Input file must be named like 'Xxx.vm'\n");
|
|
exit(1);
|
|
}
|
|
|
|
filelist->output = getoutname(input, inplen, isitdir);
|
|
}
|
|
|
|
return filelist;
|
|
}
|
|
|
|
void freetranslationlist(TRANSLATIONLIST* ls) {
|
|
for(int i = 0; i < ls->filecount; i++) {
|
|
free(ls->files[i]);
|
|
free(ls->fnames[i]);
|
|
}
|
|
free(ls->files);
|
|
free(ls->fnames);
|
|
free(ls->output);
|
|
free(ls);
|
|
}
|
|
|
|
int main(int argc, char* argv[]) {
|
|
if(argc < 2) {
|
|
fprintf(stderr, "Usage: %s {file}\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
TRANSLATIONLIST* ls = getfiles(argv[1]);
|
|
FILE* output = fopen(ls->output, "w");
|
|
|
|
for(int i = 0; i < BOOTSTRAPN; i++) {
|
|
fprintf(output, "%s\n", bootstrapcode[i]);
|
|
}
|
|
|
|
for(int i = 0; i < ls->filecount; i++) {
|
|
// file name validating
|
|
char* fname = ls->fnames[i];
|
|
|
|
FILE* input = fopen(ls->files[i], "r");
|
|
|
|
if(input == NULL) {
|
|
fprintf(stderr, "%s\n", strerror(errno));
|
|
return errno;
|
|
}
|
|
|
|
// parsing
|
|
PARSER* p = mkparser(input);
|
|
parse(p);
|
|
|
|
// translating
|
|
TRANSLATOR* t = mktranslator(p->lns, fname);
|
|
translate(t);
|
|
freeparser(p);
|
|
|
|
printlns(t->output, output);
|
|
|
|
// freeing rest
|
|
freetranslator(t);
|
|
}
|
|
|
|
freetranslationlist(ls);
|
|
fclose(output);
|
|
return 0;
|
|
}
|