/media/sda-magnetic/david/Dok-15-2023-11-27/fernuni-hagen/cs-i-ii/old-cs-2-01/comp-2021-09-07/compiler9.c


#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#define F_MAX_LENGTH 8192
#define GLOBAL_VARS_N_MAX 8192+1
#define VAR_STR_MAX_LENGTH 128

#define E_TO_FEW_PROGRAM_ARGUMENTS -1
#define E_CANT_OPEN_FILE -2
#define E_SOURCE_FILE_EXCEEDED -3
#define E_SYNTAX_ERROR -4
#define E_NOT_ENOUGH_MEMORY -5

float global_vars [8192];

char lexstream [F_MAX_LENGTH];
char *lexstreamptr = lexstream;
int loopcount = 0;


int hash (char *);
float numexpr ();
float numexpr2 ();
float term ();
float term2 ();
float factor ();
char *arrayname ();
int boolexpr ();
int block ();
int block_do_not_execute ();
int loop () ;
int statement () ;
void stmt () ;
int ech () ;
int assignment ();
int cnd ();
 


int main (int argc, char *argv []) {
    FILE *fp;
    int ch;
    
    char *p;
    int i;

    if (argc != 2) {
        perror ("Too few arguments for program");
        return E_TO_FEW_PROGRAM_ARGUMENTS;
    }
    if ((fp = fopen (argv [1], "r")) == NULL) {
        perror ("Can't open file");
        return E_CANT_OPEN_FILE;
    }
    
    i = 0;
    p = lexstream;
    while (!feof(fp)) {
        ch = fgetc (fp);
        if (i > 8129) {
            perror ("Source File to long");
            return E_SOURCE_FILE_EXCEEDED;
        }
        i++;
        *p = ch;
        p++;
    }
    *p = 0;
    
    lexstreamptr = lexstream;
    
    statement ();
    
return 0;    
}


int hash (char *v) {
    int h;
    
    for (h = 0;  *v != 0;  v++)
        h = (128*h+*v) % GLOBAL_VARS_N_MAX;
return h;
}

float numexpr () {
    float x;
    float y;
    
    x = term ();
    y = numexpr2 ();
    return x+y;
}

float numexpr2 () {
    char *ptrtmp;
    float x, y;
    
    ptrtmp = lexstreamptr;
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;
    if ((*lexstreamptr) == '+') {
        lexstreamptr++;
        x = term ();
        y = numexpr2 ();
        return x+y;
    }
    if ((*lexstreamptr) == '-') {
        lexstreamptr++;
        x = term ();
        y = numexpr2 ();
        return -x+y;
    }
    lexstreamptr = ptrtmp;
    return 0;
}

float term () {
    int x, y;
    
    x = factor ();
    y = term2 ();
    return x*y;
}

float term2 () {
    float x, y;
    char *ptrtmp;
    
    ptrtmp = lexstreamptr;
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;
    if ((*lexstreamptr) == '*') {
        lexstreamptr++;
        x = factor ();
        y = term2 ();
        return x*y;
    }
    if ((*lexstreamptr) == '/') {
        lexstreamptr++;
        x = factor ();
        y = term2 ();
        return y/x;
    }
    lexstreamptr = ptrtmp;
    return 1;
}

float factor () {
    float floatret;
    char floatstrtmp [VAR_STR_MAX_LENGTH];
    float retval;
    char *ptr;
    char varname [VAR_STR_MAX_LENGTH];
    char *arraynamestr;
    char buf [128];
    
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;

    floatret = strtof (lexstreamptr, NULL);
    
    if (((*lexstreamptr) != '0') && (floatret != 0)) {
        sprintf (floatstrtmp, "%.2f", floatret);
        lexstreamptr += strlen (floatstrtmp);
        return floatret;
    }
    else if ((*lexstreamptr) == '0') {
        sprintf (floatstrtmp, "%.2f", floatret);
        lexstreamptr += strlen (floatstrtmp);
        return floatret;
    }
    else if ((*lexstreamptr) == '(') {
        lexstreamptr ++;
        retval = numexpr ();
        if ((*lexstreamptr) == ' ')
            lexstreamptr++;
        if ((*lexstreamptr) != ')') { 
            perror ("Forget round bracket in arithmetic expression");
            return E_SYNTAX_ERROR;
        }
        lexstreamptr ++;
        return retval;
    }
    else if ((*lexstreamptr) == '$') {
        lexstreamptr++;
        
        if (!((*lexstreamptr >= 'a') && (*lexstreamptr <= 'z'))) {
            perror ("bad variable name");
            return E_SYNTAX_ERROR;
        }
        ptr = varname;
        while ((*lexstreamptr >= 'a') && (*lexstreamptr <= 'z')) {
            *ptr = *lexstreamptr;
            ptr++;
            lexstreamptr++;
        }
        *ptr = 0;
        arraynamestr = arrayname ();
        if (arraynamestr != NULL)
            strcat (varname, arraynamestr);
        return global_vars [hash (varname)];
    }
    else {
        perror ("error in arithmetic expression");
        return E_SYNTAX_ERROR;
    }
}

char *arrayname () {
    char *lexstreamptrtmp = lexstreamptr;
    char *lexstreamptrtmp2;
    char *arrayindexstr;
    char *arraynamestrpost;
    
    if ((arrayindexstr = (char *) malloc (VAR_STR_MAX_LENGTH)) == NULL) {
        perror ("Not enough memory");
        exit( E_NOT_ENOUGH_MEMORY );
    }
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;

    if ((*lexstreamptr) == '[') {
        lexstreamptr++;
        sprintf (arrayindexstr, "%i", (int) numexpr());
        if ((*lexstreamptr) == ' ')
            lexstreamptr++;
        if ((*lexstreamptr) != ']') {
            perror ("Forgot closing array bracket");
            exit ( E_SYNTAX_ERROR );
        }
        lexstreamptr++;
        
        lexstreamptrtmp2 = lexstreamptr;
        if ((*lexstreamptr) == ' ')
            lexstreamptr++;
        if ((*lexstreamptr) == '[') {
            lexstreamptr = lexstreamptrtmp2;
            arraynamestrpost = arrayname ();
            if (arraynamestrpost != NULL)
                strcat (arrayindexstr, arraynamestrpost);
        }
        else
            lexstreamptr = lexstreamptrtmp2;
        return arrayindexstr;    
    }
    else {
        free (arrayindexstr);
        lexstreamptr = lexstreamptrtmp;
        return NULL;
    }
}

int boolexpr () {
    float x, y;
    
    x = numexpr ();
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;

    if ((*lexstreamptr) == '<') {
        lexstreamptr++;
        y = numexpr ();
        return (x < y);
    }
    else if ((*lexstreamptr) == '>') {
        lexstreamptr++;
        y = numexpr ();
        return (x > y);
    }
    else if (((*lexstreamptr) == '<') && (*(lexstreamptr+1) == '=')) {
        lexstreamptr+=2;
        y = numexpr ();
        return (x <= y);
    }
    else if (((*lexstreamptr) == '>') && (*(lexstreamptr+1) == '=')) {
        lexstreamptr+=2;
        y = numexpr ();
        return (x >= y);
    }
    else if (((*lexstreamptr) == '=') && (*(lexstreamptr+1) == '=')) {
        lexstreamptr+=2;
        y = numexpr ();
        return (x == y);
    }
    else if (((*lexstreamptr) == '!') && (*(lexstreamptr+1) == '=')) {
        lexstreamptr+=2;
        y = numexpr ();
        return (x != y);
    }
    else {
        perror ("Wrong compare operator in boolesche expression");
        exit ( E_SYNTAX_ERROR );
    }
}

int block () {
    char *lexstreamptrtmp = lexstreamptr;
    
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;
    if (strncmp (lexstreamptr, "begin", strlen ("begin")) == 0) {
        lexstreamptr += strlen ("begin");
        statement ();
        if ((*lexstreamptr) == ' ')
            lexstreamptr++;
        if (strncmp (lexstreamptr, "end", strlen ("end")) == 0)
            lexstreamptr += strlen ("end");
        else {
            perror ("forgot end in block");
            exit ( E_SYNTAX_ERROR );
        }
    }
    else {
        perror ("forgot begin in block");
        exit ( E_SYNTAX_ERROR );
    }
}

int block_do_not_execute () {
    int count = 1;
    
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;

    if (strncmp (lexstreamptr, "begin", strlen ("begin")) == 0) {
        lexstreamptr += strlen ("begin");
        while ((*lexstreamptr) != 0) {
            if ((*lexstreamptr) == ' ')
                lexstreamptr++;
            if (strncmp (lexstreamptr, "end", strlen ("end")) == 0) {
                lexstreamptr += strlen ("end");
                count--;
            }
            else if (count == 0)
                break;
            else if (strncmp (lexstreamptr, "begin", strlen ("begin")) == 0) {
                lexstreamptr += strlen ("begin");
                count++;
            }
            else 
                lexstreamptr ++;
        }
        if (count != 0) {
            perror ("code ends before block cloesd");
            exit ( E_SYNTAX_ERROR );
        }
    }
    else {
        perror ("forgot begin in block");
        exit ( E_SYNTAX_ERROR );
    }

}

int loop () {
    char *lexstreamptrtmp = lexstreamptr;
    
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;

    if (strncmp (lexstreamptr, "while", strlen ("while")) == 0) {
        lexstreamptr += strlen ("while");
        if (boolexpr ()) {
            if ((*lexstreamptr) == ' ')
                lexstreamptr++;

            if (strncmp (lexstreamptr, "do", strlen ("do")) == 0) {
                lexstreamptr += strlen ("do");
                block ();
                lexstreamptr = lexstreamptrtmp;
                loop ();
                return 1;
            }
            else  {
                perror ("Forgot do in while statement");
                exit ( E_SYNTAX_ERROR );
            }
        }
        else {
            if ((*lexstreamptr) == ' ')
                lexstreamptr++;
            if (strncmp (lexstreamptr, "do", strlen ("do")) == 0) {
                lexstreamptr += strlen ("do");
                block_do_not_execute ();
                return 1;
            }
            else {
                perror ("Forgot do in while statement");
                exit ( E_SYNTAX_ERROR );
            }
        }
    }
    else {
        lexstreamptr = lexstreamptrtmp;
        return 0;
    }
    
}

int statement () {
    char *lexstreamptrtmp = lexstreamptr;
    char *lexstreamptrtmp2;
    stmt ();
    lexstreamptrtmp2 = lexstreamptr;
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;
    if ((*lexstreamptr) == ';') {
        lexstreamptr++;
        statement ();
    }
    else 
        lexstreamptr = lexstreamptrtmp2;
}

void stmt () {
    if (loop ());
    else if (assignment ());
    else if (cnd ());
    else if (ech ());
}

int ech () {
    char *lexstreamptrtmp = lexstreamptr;
        
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;
    if (strncmp (lexstreamptr, "echo", strlen ("echo")) == 0) {
        lexstreamptr += strlen ("echo");
        if ((*lexstreamptr) == ' ')
            lexstreamptr++;
        printf ("%.2f\n", numexpr ());
        return 1;
    }
    else {
        lexstreamptr = lexstreamptrtmp; 
        return 0;
    }
}

int assignment () {
    char *lexstreamptrtmp = lexstreamptr;
    char *arraynamestr;
    char varname [VAR_STR_MAX_LENGTH];
    char *ptr;  
        
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;
    
    if ((*lexstreamptr) == '$') {
        lexstreamptr++;
        
        if (!((*lexstreamptr >= 'a') && (*lexstreamptr <= 'z'))) {
            perror ("bad variable name");
            exit ( E_SYNTAX_ERROR );
        }
        
        ptr = varname;
    
        while ((*lexstreamptr >= 'a') && (*lexstreamptr <= 'z')) {
            *ptr = *lexstreamptr;
            ptr++;
            lexstreamptr++;
        }
        *ptr = 0;
    
        arraynamestr = arrayname ();
        if (arraynamestr != NULL)
            strcat (varname, arraynamestr);
        if ((*lexstreamptr) == ' ')
            lexstreamptr++;
        if ((*(lexstreamptr) == ':') && (*(lexstreamptr+1) == '=')) {
            lexstreamptr += 2;
            global_vars [hash (varname)] = numexpr ();
            return 1;
        }
        else {
            lexstreamptr = lexstreamptrtmp;
            return 0;
        }
    }
    else {
        lexstreamptr = lexstreamptrtmp;
        return 0;
    }
}

int cnd () {
    char *lexstreamptrtmp = lexstreamptr;
    char *lexstreamptrtmp2;
    int flag;
    
    if ((*lexstreamptr) == ' ')
        lexstreamptr++;

    if (strncmp (lexstreamptr, "if", strlen ("if")) == 0) {
        lexstreamptr += strlen ("if");
        
        flag = boolexpr ();
        if ((*lexstreamptr) == ' ')
            lexstreamptr++;
        if (strncmp (lexstreamptr, "then", strlen ("then")) == 0) {
            lexstreamptr += strlen ("then");
            if (flag) {
                block ();
                lexstreamptrtmp2 = lexstreamptr;
                if ((*lexstreamptr) == ' ')
                    lexstreamptr++;
                if (strncmp (lexstreamptr, "else", strlen ("else")) == 0) {
                    lexstreamptr += strlen ("else");
                    block_do_not_execute ();
                }
                else
                    lexstreamptr = lexstreamptrtmp2;
                return 1;
            }
            else {
                block_do_not_execute ();
                lexstreamptrtmp = lexstreamptr;
                if ((*lexstreamptr) == ' ')
                    lexstreamptr++;
                if (strncmp (lexstreamptr, "else", strlen ("else")) == 0) {
                    lexstreamptr += strlen ("else");
                    block ();
                }
                else
                    lexstreamptr = lexstreamptrtmp2;
                return 1;
            }
        }
        else {
            perror ("Forget then in if-Statement");
            exit (E_SYNTAX_ERROR);
        }
    }
    else {
        lexstreamptr = lexstreamptrtmp;
        return 0;
    }
        
}