//// -*- mode:c; coding:utf-8 -*-
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static FILE* sortie;

void genere1(const char* instruction,int param){
    if(sortie!=0){
        fprintf(sortie,instruction,param);}}


void genere(const char* instruction){
    if(sortie!=0){
        fprintf(sortie,"%s",instruction);}}


void genere_tete(void){
    system("cat < npc.lib.c > npc.out.c");
    sortie=fopen("npc.out.c","a");
    if(sortie==0){
        fprintf(stderr,"Erreur ouverture du fichier intermediaire\n");
        exit(1);}
    fprintf(sortie,
            "int main(void)\n"
            "{ int acc; int tmp; int idx;\n");
    genere("store(300,100);\n");}


int genere_queue(void){
    if(sortie!=0){
        fprintf(sortie,
                "exit(0);\n"
                "return(0);\n"
                "}\n");
        fclose(sortie);
        sortie=0;
        return(1);}
    else{
        return(0);}}


void annuler_genere(void){
    if(sortie!=0){
        fclose(sortie);
        unlink("npc.out.c");
        sortie=0;}}


typedef struct node_s {
    struct node_s*   left;
    struct node_s*   right;
    char             code;}                 node_t;

node_t* node_create(node_t* left,node_t* right,char code){
    node_t* res=(node_t*)malloc(sizeof(node_t));
    res->left=left;
    res->right=right;
    res->code=code;
    return(res);}


void node_delete(node_t* n){
    if(n->left!=0){ node_delete(n->left);}
    if(n->right!=0){ node_delete(n->right);}
    free(n);}


static node_t* stack[100];
static int     top=0;

void node_push(node_t* node){
    if(top<100){
        stack[top++]=node;}
    else{
        fprintf(stderr,"Expression trop compliquee.\n");
        exit(1);}}

node_t* node_pop(void){
    if(top>0){
        return(stack[--top]);}
    else{
        fprintf(stderr,"Erreur de syntaxe: trop d'operateurs.\n");
        exit(1);}}


void node_print(node_t* n){
    if(n->left!=0){
        node_print(n->left);}
    if(n->right!=0){
        node_print(n->right);}
    fprintf(stderr,"%c ",n->code);}

void node_generate(node_t* n){

    /*
    100..199 pile
    200..225 memoire
    300      top
    */
    switch(n->code){
    case 'a':
    case 'b':
    case 'c':
    case 'd':
    case 'e':
    case 'f':
    case 'g':
    case 'h':
    case 'i':
    case 'j':
    case 'k':
    case 'l':
    case 'm':
    case 'n':
    case 'o':
    case 'p':
    case 'q':
    case 'r':
    case 's':
    case 't':
    case 'u':
    case 'v':
    case 'w':
    case 'x':
    case 'y':
    case 'z':
        genere("idx=retrieve(300);\n");
        genere("if(idx>199){ e_pile_pleine(); }\n");
        genere1("acc=retrieve(%d);\n",n->code-'a'+200);
        genere("store(idx,acc);\n");
        genere("idx++;\n");
        genere("store(300,idx);\n");
        break;
    case '0':
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
        genere("idx=retrieve(300);\n");
        genere("if(idx>199){ e_pile_pleine(); }\n");
        genere1("store(idx,%d);\n",n->code-'0');
        genere("idx++;\n");
        genere("store(300,idx);\n");
        break;
    case '+':
    case '-':
    case '*':
    case '/':
        node_generate(n->left);
        node_generate(n->right);
        genere("idx=retrieve(300);\n");
        genere("if(idx<=100){ e_pile_vide(); }\n");
        genere("idx--;\n");
            genere("acc=retrieve(idx);\n");
            if(n->code=='/'){
                genere("if(acc==0){ e_division_zero(); }\n");}
            genere("if(idx<=100){ e_pile_vide(); }\n");
            genere("idx--;\n");
            genere1("acc=retrieve(idx)%cacc;\n",n->code);
            genere("store(idx,acc);\n");
            genere("idx++;\n");
            genere("store(300,idx);\n");
            break;
        case '!':
            node_generate(n->left);
            genere("idx=retrieve(300);\n");
            genere("if(idx<=100){ e_pile_vide(); }\n");
            genere("idx--;\n");
            genere("acc=retrieve(idx);\n");
            genere1("store(%d,acc);\n",n->right->code-'a'+200);
            genere("store(300,idx);\n");
            break;

        case '~':
            node_generate(n->left);
            genere("idx=retrieve(300);\n");
            genere("if(idx<=100){ e_pile_vide(); }\n");
            genere("idx--;\n");
            genere("acc=retrieve(idx);\n");
            genere("acc=-acc;\n");
            genere("store(idx,acc);\n");
            break;
        case '=':
            node_generate(n->left);
            genere("idx=retrieve(300);\n");
            genere("if(idx<=100){ e_pile_vide(); }\n");
            genere("idx--;\n");
            genere("acc=retrieve(idx);\n");
            genere("imprimer(acc);\n");
            genere("store(300,idx);\n");
            break;
        default:
            break;}}

    int compile(void)
    {
        int c;
        node_t* left;
        node_t* right;
        genere_tete();
        while((c=getc(stdin))>1){
            switch(c){
            case 'a':
            case 'b':
            case 'c':
            case 'd':
            case 'e':
            case 'f':
            case 'g':
            case 'h':
            case 'i':
            case 'j':
            case 'k':
            case 'l':
            case 'm':
            case 'n':
            case 'o':
            case 'p':
            case 'q':
            case 'r':
            case 's':
            case 't':
            case 'u':
            case 'v':
            case 'w':
            case 'x':
            case 'y':
            case 'z':
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                node_push(node_create(0,0,c));
                break;
            case '+':
            case '-':
            case '*':
            case '/':
                right=node_pop();
                left=node_pop();
                node_push(node_create(left,right,c));
                break;
            case '!':
                right=node_pop();
                left=node_pop();
                if(('a'<=right->code)&&(right->code<='z')){
                    node_push(node_create(left,right,c));
                    right=node_pop();
                    node_generate(right);
                    node_delete(right);}
                else{
                    fprintf(stderr,"Erreur de syntaxe: '!' doit être précédé "
                        "d'une lettre, et pas de :\nleft=");
                    node_print(left);
                    fprintf(stderr,"\nright=");
                    node_print(right);
                    fprintf(stderr,"\n");
                    node_delete(left);
                    node_delete(right);
                    annuler_genere();}
                break;
            case '~':
                left=node_pop();
                node_push(node_create(left,0,c));
                break;
            case '=':
                left=node_pop();
                node_push(node_create(left,0,c));
                right=node_pop();
                node_generate(right);
                node_delete(right);
                break;
            case ' ':
            case '\t':
            case '\n':
                break;
            default:
                fprintf(stderr,"Mauvais caractere : %d '%c'.\n",c,c);
                annuler_genere();
                break;}}
        if(top>0){
            fprintf(stderr,"Erreur de syntaxe: pas assez d'operateurs\n");
            node_print(node_pop());
            fprintf(stderr,"\n");
            annuler_genere();}
        return(genere_queue());}


int main(void){
    if(compile()){
        system("cc -o npc.out npc.out.c");}
    return(0);}



//// THE END ////
ViewGit