2013-12-19 22:22:57 +01:00

484 lines
11 KiB
C
Raw Permalink Blame History

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char outfilename[255] = "bf-default.asm"; //name of the outputfile
char infilename[255]; //name of the inputfile
int parsepos = 0; //current position in file
int arraysize = 0; //arraysize of bfCode (variable)
int* bfCode = NULL; //array of bfCode
int whilecount = 0; //counts the while-loops
int lastchar = 0; //for optimization
int charcount = 0; //for optimization
/*
* validate commandline arguments, set global variables as required or inform user of usage and quit the program
*/
int validateArguments(int argc, char *argv[])
{
switch(argc){
//fall ohne angabe des outfile
case 2: {
strcpy(infilename, argv[1]);
return 1;
}
//fall mit angabe des outfile
case 4: {
if(!strcmp(argv[1], "-o")){
strcpy(outfilename, argv[2]);
strcpy(infilename, argv[3]);
return 1;
}
}
default: {
printf("invalid arguments!\n");
return 0;
}
}
}
int checkChar(int command){
switch(command){
case 43: // +
case 45: // -
case 62: // >
case 60: // <
case 46: // .
case 44: // ,
case 91: // [
case 93: // ]
return 1;
break;
default:
return 0;
}
}
int checkSimpleCommand(int command){
switch(command){
case 43: // +
case 45: // -
case 62: // >
case 60: // <
case 46: // .
case 44: // ,
return 1;
break;
default:
return 0;
}
}
int parseSimpleCommand(){
if(checkSimpleCommand(bfCode[parsepos])){
return 1;
}
printf("Error: Not a simple command!\n");
return 0;
}
int parseWhileCommand(){
if( bfCode[parsepos] != '['){
printf("Error: While not started!\n");
return 0;
}
parsepos++; //skip [
while( bfCode[parsepos] != ']')
{
if(parseCommand() != 1){
return 0;
}
if(parsepos++ >= arraysize){
printf("Error: While not ended!\n");
return 0;
}
}
return 1;
}
int parseCommand(){
if(bfCode[parsepos] == 0){
printf("Compiling File %s succesfull!\n", infilename);
arraysize = parsepos;
return 1;
}
if( bfCode[parsepos] == '['){
return parseWhileCommand();
}
return parseSimpleCommand();
}
int parseProgram(){
while( parsepos < arraysize )
{
if(parseCommand() == 0){
return 0;
}
parsepos++;
}
}
//Some functions for assemblercode
void generateHead(FILE * pFile){
//Head
fputs( ".data\n" , pFile);
fputs( "\t curStackPos: .long 0\n" , pFile);
fputs( "\t datafield: .long 0\n" , pFile);
fputs( "\t\t\t .align 65536\n" , pFile);
fputs( "\t maxStack:\t.long 65536\n" , pFile);
fputs( "\t intout:\t.string \"%c\"\n" , pFile);
fputs( "\t endofline:\t.string \"\\n\"\n" , pFile);
fputs( "\n" , pFile);
fputs( ".text\n" , pFile);
fputs( ".globl main\n" , pFile);
fputs( "\n" , pFile);
//Main
fputs( "main:\n" , pFile);
fputs( "\t call bfCode\n" , pFile);
fputs( "\t jmp end\n" , pFile);
fputs( "\n" , pFile);
//End
fputs( "end:\n" , pFile);
fputs( "\t pushl $endofline\n" , pFile);
fputs( "\t call printf\n" , pFile);
fputs( "\t movl $1, %eax\n" , pFile);
fputs( "\t int $0x80\n" , pFile);
fputs( "\n" , pFile);
//Check Stack, ends Programm if > MaxStack
fputs( "checkStack:\n" , pFile);
fputs( "\t movl curStackPos, %ebx\n" , pFile);
fputs( "\t movl maxStack, %ecx\n" , pFile);
fputs( "\t cmp %ecx, %ebx\n" , pFile);
fputs( "\t jge end\n" , pFile);
fputs( "\t ret\n" , pFile);
fputs( "\n" , pFile);
//Get Stack @ curStackPos; result = %eax
fputs( "getStack:\n" , pFile);
fputs( "\t call checkStack\n" , pFile);
fputs( "\t movl curStackPos, %ecx\n" , pFile);
fputs( "\t movl datafield(, %ecx, 4), %eax\n" , pFile);
fputs( "\t ret\n" , pFile);
fputs( "\n" , pFile);
//Set Stack @ curStackPos; input = %eax
fputs( "setStack:\n" , pFile);
fputs( "\t call checkStack\n" , pFile);
fputs( "\t movl curStackPos, %ecx\n" , pFile);
fputs( "\t movl %eax, datafield(, %ecx, 4)\n" , pFile);
fputs( "\t ret\n" , pFile);
fputs( "\n" , pFile);
//ReadInput, reads from terminal
fputs( "readInput:\n" , pFile);
fputs( "\t xor %ecx, %ecx\n" , pFile); //Register nullen
fputs( "\t xor %edi, %edi\n" , pFile); //sys_READ :
fputs( "\t movl $0, %ebx\n" , pFile); // was soll gemacht werden? (0 -> STDIN)
fputs( "\t pushl $0\n" , pFile);
fputs( "\t leal (%esp), %ecx\n" , pFile); // %ecx beinhaltet Adresse von Speicherziel (Speicherziel: datafield( (%edi = 0), 4)
fputs( "\t movl $3, %eax\n" , pFile); // syscalltyp (3 -> sys_read)
fputs( "\t movl $1, %edx\n" , pFile); // L<>nge der Eingabe (hier 8 = 1byte)
fputs( "\t int $0x80\n" , pFile); // eigentlicher syscall
fputs( "\t popl %eax\n" , pFile);
fputs( "\t pushl $0\n" , pFile);
fputs( "\t addl $4, %esp\n" , pFile);
fputs( "\t ret\n" , pFile);
fputs( "\n" , pFile);
//WriteOutput, writes to terminal
fputs( "writeOutput:\n" , pFile);
fputs( "\t pushl %eax\n" , pFile);
fputs( "\t pushl $intout\n" , pFile);
fputs( "\t call printf\n" , pFile);
fputs( "\t popl %eax\n" , pFile);
fputs( "\t popl %eax\n" , pFile);
fputs( "\t pushl $0\n" , pFile);
fputs( "\t pushl $0\n" , pFile);
fputs( "\t addl $8, %esp\n" , pFile);
fputs( "\t ret\n" , pFile);
fputs( "\n" , pFile);
//Bf-Code
fputs( "\n" , pFile);
fputs( "bfCode:\n" , pFile);
fputs( "\n" , pFile);
}
void generatePlus(FILE * pFile, int count){
fprintf(pFile, "# Plus (%d mal):\n" , count);
fputs( "\t call getStack\n" , pFile);
fprintf(pFile, "\t movl $%d, %%ebx\n" , count);
fputs( "\t addl %ebx, %eax\n" , pFile);
fputs( "\t call setStack\n" , pFile);
fputs( "\n", pFile);
}
void generateMinus(FILE * pFile, int count){
fprintf(pFile, "# Minus (%d mal):\n" , count);
fputs( "\t call getStack\n" , pFile);
fprintf(pFile, "\t movl $%d, %%ebx\n" , count * -1);
fputs( "\t addl %ebx, %eax\n" , pFile);
fputs( "\t call setStack\n" , pFile);
fputs( "\n" , pFile);
}
void generateGroesser(FILE * pFile, int count){
fprintf(pFile, "# Groesser (%d mal):\n" , count);
fputs( "\t movl curStackPos, %eax\n" , pFile);
fprintf(pFile, "\t addl $%d, %%eax\n" , count);;
fputs( "\t movl %eax, curStackPos\n" , pFile);
fputs( "\n" , pFile);
}
void generateKleiner(FILE * pFile, int count){
fprintf(pFile, "# Kleiner (%d mal):\n" , count);
fputs( "\t movl curStackPos, %eax\n" , pFile);
fprintf(pFile, "\t subl $%d, %%eax\n" , count);;
fputs( "\t movl %eax, curStackPos\n" , pFile);
fputs( "\n" , pFile);
}
void generatePunkt(FILE * pFile, int count){
fputs( "# Punkt:\n" , pFile);
while(count > 0){
fputs( "\t call getStack\n" , pFile);
fputs( "\t call writeOutput\n" , pFile);
count--;
}
}
void generateKomma(FILE * pFile, int count){
fputs( "# Komma:\n", pFile);
while(count > 0){
fputs( "\t call readInput\n" , pFile);
fputs( "\t call setStack\n" , pFile);
count--;
}
}
void generateWhileStart(FILE * pFile, int whileNo){
fprintf(pFile, "# WhileBegin%d:\n" , whileNo);
fprintf(pFile, "WhileBegin%d:\n" , whileNo);
fputs( "\tcall getStack\n" , pFile);
fputs( "\tcmp $0, %eax\n" , pFile);
fprintf(pFile, "je WhileEnd%d\n" , whileNo);
fputs("\n", pFile);
}
void generateWhileEnd(FILE * pFile, int whileNo){
fprintf(pFile, "# WhileEnd%d:\n" , whileNo);
fprintf(pFile, "jmp WhileBegin%d\n" , whileNo);
fprintf(pFile, "WhileEnd%d:\n" , whileNo);
}
int generateSimpleCommandCode(FILE * pFile){
if(lastchar != 0){
switch(lastchar){
case 43: // +
generatePlus(pFile,charcount);
break;
case 45: // -
generateMinus(pFile,charcount);
break;
case 62: // >
generateGroesser(pFile,charcount);
break;
case 60: // <
generateKleiner(pFile,charcount);
break;
case 46: // .
generatePunkt(pFile,charcount);
break;
case 44: // ,
generateKomma(pFile,charcount);
break;
default:
printf("ERROR: Not a Simple Command\n");
return 0;
}
}
lastchar = 0;
charcount = 0;
return 1;
}
int generateSimpleCommand(FILE * pFile){
if(bfCode[parsepos] == lastchar){
charcount++;
} else {
generateSimpleCommandCode(pFile);
lastchar = bfCode[parsepos];
charcount = 1;
}
return 1;
}
int generateWhileCommand(FILE * pFile){
if( bfCode[parsepos] != '['){
printf("Error: While not Started\n");
return 0;
}
parsepos++; //skip [
int myWhileCount = whilecount++;
generateWhileStart(pFile, myWhileCount);
while( bfCode[parsepos] != ']')
{
if(generateCommand(pFile) != 1){
return 0;
}
if(parsepos++ >= arraysize){
printf("Error: While not Ended\n");
return 0;
}
}
generateSimpleCommandCode(pFile);
generateWhileEnd(pFile, myWhileCount);
return 1;
}
int generateCommand(FILE * pFile){
if( bfCode[parsepos] == '['){
generateSimpleCommandCode(pFile);
return generateWhileCommand(pFile);
}
return generateSimpleCommand(pFile);
}
int generateCode(){
FILE * pFile;
pFile = fopen(outfilename, "w");
parsepos = 0;
generateHead(pFile);
while( parsepos < arraysize )
{
if(generateCommand(pFile) == 0){
return 0;
}
parsepos++;
}
if(charcount != 0){
generateSimpleCommandCode(pFile);
}
fputs("\t ret", pFile);
return 1;
}
int scanner(const char *file){
FILE * pFile;
// open file
pFile = fopen(file, "r");
//file opend?
if (pFile == NULL){
printf("Error: Could not open Inputfile\n");
return 0;
}
//int f<>rs aktuelle Zeichen
int lc;
//how many chars did we read?
int i = 0;
//Sind wir im linecomment?
int linecomment = 0;
while((lc = fgetc(pFile)) != EOF){
if(lc == ';'){
linecomment = 1;
continue;
}
if(lc == '\n'){
linecomment = 0;
continue;
}
if( !linecomment &&
checkChar(lc) != 0){
if(arraysize <= i+1){
//Resize Array if needed
arraysize = (arraysize*2 + 1); //+ 1 for arraysize = 0
bfCode = (int*) realloc(bfCode,arraysize * sizeof(int));
}
bfCode[i] = lc;
i++;
}
}
//DEBUG
//int j;
//for(j = 0; j <= 8; j++){
//printf("%d\n", bfCode[j]);}
//done
fclose(pFile);
return 1;
}
int main (int argc, char *argv[])
{
//checks arguments and sets in- / outfilename
if(validateArguments(argc, argv)){
//Scanns in the file, strips all non-bf-chars
if(scanner(infilename)){
//Check Syntax
if(parseProgram()){
//Generate asm Code
if(generateCode()){
return 1; //SUCCESS
} else {return 0;} //Generate Error
} else {return 0;} //Syntax Error
} else {return 0;} //Scanner Error
} else {return 0;} //Arguments Error
}