484 lines
11 KiB
C
484 lines
11 KiB
C
#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
|
||
}
|