#include #include #include #define NOP 0x0000 #define FREEZE 0x0100 #define RETURN 0x0200 #define LOAD 0x1000 #define STO 0x2000 #define MOV 0x3000 #define CST 0x4000 #define GOTO 0x5000 #define GOTC 0x60F0 #define GOSUB 0x7000 #define ADD 0x8000 #define SUB 0x9000 #define SHIFT 0xA000 #define NUL 0xB000 #define NOT 0xC000 #define OR 0xC100 #define AND 0xC200 #define XOR 0xC300 #define IN 0xD000 #define OUT 0xD100 #define HIGHCHAR 0xFF00 #define LOWCHAR 0x00FF #define OK 0 #define FIN -1 #define ERREUR 1 #define OPTION1 0x0100 #define OPTION2 0x0200 #define OPTION3 0x0400 #define OPTION4 0x0800 #define BITS16 0xFFFF #define RI 0xF #define RP 0x7 #define Rplus 0x3 #define RG 0xB /* Poids faibles d'abord !!! */ #define LONGUEUR_TAMPON 100 /* Permet de changer facilement les instructions d'entrée-sortie */ #define ENTREE getchar() typedef struct PILE { char *etiq; int n; struct PILE *next; } *pile; int passe_blanc(void); int lit_instruction(void); int lit_mot_cle(int c); int lit_registre(void); long lit_entier(int c); int alu(long l); int cst(void); int ret(void); int nf(long l); int go(long l); int io(long l); int label(void); int memory(long l); int mov(void); void ecrit(long l); void depile(pile *p); void sortie(FILE *f); long trouve_adresse(char *s); long rev(int n,long l); FILE *fichier; int mot=-1; pile labels=NULL; pile gotos=NULL; int main(void) { int i; /* On a besoin d'avoir des variables de 16 bits (des long) */ if (LONG_MAX<32767) { fprintf(stderr,"Ce programme ne fonctionne qu'avec des long codés sur 16 bits ou plus. Désolé.\n"); exit(ERREUR); } if ((fichier=fopen("temp_assemble.tmp","wb"))==NULL) { fprintf(stderr,"Erreur de création d'un fichier temporaire.\n"); exit(ERREUR); } /*CST RP hFFFF*/ ecrit(CST|(RP<<4)); ecrit(rev(16,0xFFFF)); /*CST R+ 1*/ ecrit(CST|(Rplus<<4)); ecrit(rev(16,1)); mot+=4; while ((i=lit_instruction())!=ERREUR && i!=FIN) ; fclose(fichier); if (i==ERREUR) { fprintf(stderr,"Erreur de syntaxe.\n"); exit(ERREUR); } if ((fichier=fopen("temp_assemble.tmp","r+b"))==NULL) { fprintf(stderr,"Erreur de réouverture du fichier temporaire.\n"); exit(ERREUR); } while (gotos!=NULL) { i=trouve_adresse(gotos->etiq); if (fseek(fichier,2*gotos->n,SEEK_SET)) { fprintf(stderr,"Erreur de positionnement du curseur de fichier.\n"); exit(ERREUR); } ecrit(rev(16,i)); /*Relatif : (i-gotos->n) % BITS16*/ depile(&gotos); } if (fseek(fichier,0,SEEK_SET)) { fprintf(stderr,"Erreur de positionnement du curseur de fichier.\n"); exit(ERREUR); } sortie(fichier); fclose(fichier); remove("temp_assemble.tmp"); while (labels!=NULL) depile(&labels); return OK; } int passe_blanc(void) { int c; while ((c=ENTREE)==' ' || c=='\n' || c=='\t' || c=='%' || c==0xd) /* Le charmant 0xd est là pour tenir compte du fait que le programme ASM a été conçu sur un PC pour lequel le code du retour chariot n'est pas le même... */ if (c=='%') while ((c=ENTREE)!='%' && c!=EOF) ; return c; } int lit_instruction(void) { int c; /* Passage des blancs initiaux */ c=passe_blanc(); /* Fin du fichier ? */ if (c==EOF) return FIN; return lit_mot_cle(c); } int lit_mot_cle(int c) /* Lecture du mot-clé (bourrine) */ { mot++; switch (c) { case 'A': switch (ENTREE) { case 'D': if (ENTREE=='D') return alu(ADD); break; case 'N': if (ENTREE=='D') return alu(AND); default: break; } break; case 'C': if (ENTREE=='S' && ENTREE=='T') return cst(); break; case 'F': if (ENTREE=='R' && ENTREE=='E' && ENTREE=='E'&& ENTREE=='Z' && ENTREE=='E') return nf(FREEZE); break; case 'G': if (ENTREE=='O') switch (ENTREE) { case 'S': if (ENTREE=='U' && ENTREE=='B') return go(GOSUB); break; case 'T': switch (ENTREE) { case 'O': return go(GOTO); case 'C': return go(GOTC); default: break; } default: break; } break; case 'I': if (ENTREE=='N') return io(IN); break; case 'L': switch (ENTREE) { case 'A': if (ENTREE=='B' && ENTREE=='E' && ENTREE=='L') return label(); break; case 'O': if (ENTREE=='A' && ENTREE=='D') return memory(LOAD); default: break; } break; case 'M': if (ENTREE=='O' && ENTREE =='V') return mov(); break; case 'N': switch (ENTREE) { case 'O': switch (ENTREE) { case 'P': return nf(NOP); case 'T': return alu(NOT); default: break; } break; case 'U': if (ENTREE=='L') return alu(NUL); default: break; } break; case 'O': switch (ENTREE) { case 'R': return alu(OR); case 'U': if (ENTREE=='T') return io(OUT); default: break; } break; case 'R': if (ENTREE=='E' && ENTREE=='T' && ENTREE=='U' && ENTREE=='R' && ENTREE=='N') return ret(); break; case 'S': switch (ENTREE) { case 'H': if (ENTREE=='I' && ENTREE=='F' && ENTREE=='T') return alu(SHIFT); break; case 'T': if (ENTREE=='O') return memory(STO); break; case 'U': if (ENTREE=='B') return alu(SUB); default: break; } break; case 'X': if (ENTREE=='O' && ENTREE=='R') return alu(XOR); default: break; } return ERREUR; } int alu(long l) { int c,i; long r=l; c=passe_blanc(); if (c=='+' && (l==ADD || l==SUB)) { r=r | OPTION1; c=passe_blanc(); } if (l==SHIFT) { if (c=='<') r=r | OPTION1; else if(c=='>') r=r & ~OPTION1; else return ERREUR; c=passe_blanc(); } if (c!='R') return ERREUR; if ((i=lit_registre())==-1) return ERREUR; r=r | (i << 4); if (l!=SHIFT && l!=NUL && l!=NOT) { if (passe_blanc()!='R') return ERREUR; if ((i=lit_registre())==-1) return ERREUR; r=r | i; } ecrit(r); return OK; } long lit_entier(int c) { int i=0; if (c=='b') while ((c=ENTREE)=='0' || c=='1') i=2*i+c-'0'; else if (c=='h') while (((c=ENTREE)>='0' && c<='9')||(c>='A' && c<='F')) { if (c>='0' && c<='9') i=16*i+c-'0'; else i=16*i+c-'A'+10; } else if (c>='0' && c<='9') { i=c-'0'; while ((c=ENTREE)>='0'&&c<='9') i=i*10+c-'0'; } else { fprintf(stderr,"Entier attendu...\n"); exit(ERREUR); } return i; } int cst(void) { int c; int i; int reg; if ((c=passe_blanc())!='R') return ERREUR; if ((reg=lit_registre())==-1) return ERREUR; i=lit_entier(passe_blanc()); ecrit(CST | (reg << 4)); ecrit(rev(16,i)); mot++; return OK; } int ret(void) /* RETURN */ { /* ADD RP R+ */ ecrit(ADD|(RP<<4)|Rplus); /* LOAD RI RP */ ecrit(LOAD|(RI<<4)|RP); return OK; } int nf(long l) /* NOP, FREEZE */ { ecrit(l); return OK; } int go(long l) { long i=NOP; int c; enum {reg,ent,lab} type; if (l==GOTC) { l = l & ~OPTION3; l = l & ~OPTION4; if (passe_blanc()!='(') return ERREUR; if ((c=passe_blanc())=='O') { l=l | OPTION3; if ((c=passe_blanc())=='&') { l = l | OPTION4; if (passe_blanc()!='E') return ERREUR; c=passe_blanc(); } else if (c=='|') { l = l & ~OPTION3; if (passe_blanc()!='E') return ERREUR; c=passe_blanc(); } } else if (c=='E') { l= l | OPTION4; if ((c=passe_blanc())=='&') { l = l | OPTION3; if (passe_blanc()!='O') return ERREUR; c=passe_blanc(); } else if (c=='|') { l= l & (~OPTION4); if (passe_blanc()!='O') return ERREUR; c=passe_blanc(); } } else return ERREUR; if (c!=')') return ERREUR; } if((c=passe_blanc())=='R'){ if((i=lit_registre())==-1) return ERREUR; type=reg; } else if((c>='0' && c<='9') || c=='b' || c=='h') { type=ent; i=rev(16,lit_entier(c)); } else { char tampon[LONGUEUR_TAMPON]; int i=0,j; char *p; pile new; type=lab; tampon[0]=c;; while ((c=ENTREE)!='\n' && c!=EOF && c!='\t' && c!='\n' && ++ietiq=p; new->n=-1; new->next=gotos; gotos=new; } if (l==GOTO) if (type==reg) /* MOV RI Ri */ ecrit(MOV | (RI<<4) | i); else { /* CST RI i */ ecrit(CST | (RI<<4)); ecrit(i); mot++; } else if (l==GOSUB) { /* MOV RG RI */ ecrit(MOV | (RG<<4) | RI); /* CST R+ (10 ou 9) */ ecrit(CST | (Rplus<<4)); ecrit(rev(16,10-(type==reg?1:0))); /* ADD RG R+ */ ecrit(ADD | (RG<<4) | Rplus); /* CST R+ 1 */ ecrit(CST | (Rplus<<4)); ecrit(rev(16,1)); /* STO RG RP */ ecrit(STO | (RG<<4) | RP); /* SUB RP Rplus */ ecrit(SUB | (RP<<4) | Rplus); mot+=8; if (type==reg) /* MOV RI Ri */ ecrit(MOV | (RI<<4) | i); else { /* CST RI i */ ecrit(CST | (RI<<4)); ecrit(i); mot++; } } else { /* GOTC */ if (type==reg) ecrit (l | i); else { ecrit(CST | (RG<<4)); ecrit(i); ecrit(l | RG); mot+=2; } } if (type==lab) gotos->n=mot-(((l&0xF0F0)==GOTC)?1:0); return OK; } int io(long l) { int r; if (passe_blanc()!='R') return ERREUR; if ((r=lit_registre())==-1) return ERREUR; ecrit((l|(r<<4))|rev(4,lit_entier(passe_blanc()))); return OK; } int label(void) { char tampon[LONGUEUR_TAMPON]; char c; int i=0,j; char *p; pile new; mot--; tampon[0]=passe_blanc();; while ((c=ENTREE)!='\n' && c!=EOF && c!='\t' && c!='\n' && ++i<=LONGUEUR_TAMPON) tampon[i]=c; if (i==LONGUEUR_TAMPON) return ERREUR; p=malloc((i+2)*sizeof(char)); for (j=0;j<=i;j++) p[j]=tampon[j]; p[i+1]='\0'; new=malloc(sizeof(struct PILE)); new->etiq=p; new->n=mot+1; new->next=labels; labels=new; return OK; } int memory(long l) { long r=l; long adr=0; int i; int c; if (passe_blanc()!='R') return ERREUR; if ((i=lit_registre())==-1) return ERREUR; r=r|(i<<4); if ((c=passe_blanc())=='R') { if ((i=lit_registre())==-1) return ERREUR; ecrit(r|i); } else { adr=lit_entier(c); ecrit(CST|(RG<<4)); ecrit(rev(16,lit_entier(c))); ecrit(r|RG); mot+=2; } return OK; } int mov(void) { long r; int i; if (passe_blanc()!='R') return ERREUR; if ((i=lit_registre())==-1) return ERREUR; r=MOV | (i << 4); if (passe_blanc()!='R') return ERREUR; if ((i=lit_registre())==-1) return ERREUR; r=r | i; ecrit(r); return OK; } void ecrit(long l) { fputc((l&HIGHCHAR)>>8,fichier); fputc((l&LOWCHAR),fichier); } int lit_registre(void) /* Lit un entier compris entre 1 et 12 ou I ou P ou + ou G et renvoie un entier entre 0 et 15 (numéro du registre), bits de poids faibles d'abord Renvoie -1 si erreur */ { int i; if ((i=ENTREE)=='I') return RI; else if (i=='P') return RP; else if (i=='G') return RG; else if (i=='+') return Rplus; else if (i>='2' && i<='9') return rev(4,(i-'0')-1); else if (i=='1') if ((i=ENTREE)>='0' && i<='2') return rev(4,10+(i-'0')-1); else return 0; else return -1; } void depile(pile *p) { pile q; q=(*p)->next; free ((*p)->etiq); free (*p); *p=q; } long trouve_adresse(char *s) { pile p=labels; int i=0; while (p!=NULL) { i=0; while (p->etiq[i]==s[i] && s[i]!='\0') i++; if (s[i]=='\0' && p->etiq[i]=='\0') return p->n; p=p->next; } fprintf(stderr,"L'étiquette %s est introuvable.",s); exit(ERREUR); } void sortie (FILE *f) { int c; while((c=fgetc(f))!=EOF) putchar(c); } long rev(int n,long l) { int i; long r=0; for (i=0;i>(n-1-i))%2)<