add interpreter

This commit is contained in:
Arnaud Vergnet 2021-04-13 09:35:14 +02:00
parent a1c0f7a19f
commit e3ea8ee709
7 changed files with 310 additions and 3 deletions

9
.gitignore vendored
View file

@ -1,6 +1,9 @@
/as.tab.c
/as.tab.h
/compilateur
/lex.yy.c
/as.output
/instruction_table.txt
/test
/interpreter/interpreter
*.tab.c
*.tab.h
*.yy.c

8
interpreter/input.txt Normal file
View file

@ -0,0 +1,8 @@
AFC 0 1
AFC 10 20
ADD 0 0 10
AFC 1 8888
SUP 2 0 1
JMF 2 7
PRI 1
PRI 0

14
interpreter/makefile Executable file
View file

@ -0,0 +1,14 @@
SRCC:= ./src/*.c
all: interpreter
interpreter: ./src/interpreter.y ./src/interpreter.l ./src/instructions.c
yacc -d ./src/interpreter.y
lex ./src/interpreter.l
gcc lex.yy.c y.tab.c ./src/instructions.c -Isrc -o interpreter
run: interpreter
./interpreter < input.txt
clean:
rm -f lex.yy.c interpreter y.tab.h y.tab.c *.o

145
interpreter/src/instructions.c Executable file
View file

@ -0,0 +1,145 @@
#include <stdio.h>
#include "instructions.h"
struct instruction {
char ins;
int arg1;
int arg2;
int arg3;
};
struct instruction instructions[MAX_INSTRUCTIONS_SIZE];
int current_line;
int has_error;
int memory[MAX_MEMORY_SIZE];
int exec(int ip);
int valid_memory_addr(int address);
/***** Public funciton *****/
void asm_init() {
current_line = 0;
has_error = 0;
}
void asm_add_3(char ins, int arg1, int arg2, int arg3) {
if (current_line >= MAX_INSTRUCTIONS_SIZE) {
fprintf(stderr, "ERROR readfile : Too much instructions, please modify value of MAX_INSTRUCTIONS_SIZE.\n");
has_error = 1;
return;
}
// ip are validated at runtime; memory addr are validated here
if (ins == AFC || ins == JMF) {
if (!valid_memory_addr(arg1)) {
fprintf(stderr, "ERROR readfile : INVALID addr at line %d, please verify that addr is in range 0 to MAX_MEMORY_SIZE\n", current_line);
has_error = 1;
return;
}
} else if (ins == JMP) {
// do nothing
} else {
if (!(valid_memory_addr(arg1) && valid_memory_addr(arg2)
&& valid_memory_addr(arg3))) {
fprintf(stderr, "ERROR readfile : INVALID addr at line %d, please verify that addr is in range 0 to MAX_MEMORY_SIZE\n", current_line);
has_error = 1;
return;
}
}
// When OK
instructions[current_line].ins = ins;
instructions[current_line].arg1 = arg1;
instructions[current_line].arg2 = arg2;
instructions[current_line].arg3 = arg3;
current_line++;
}
void asm_add_2(char ins, int arg1, int arg2) {
asm_add_3(ins, arg1, arg2, 0);
}
void asm_add_1(char ins, int arg1) {
asm_add_3(ins, arg1, 0, 0);
}
void asm_run() {
int ip = 0;
if (has_error) {
fprintf(stderr, "ERROR run : abandoned due to previous error.\n");
return;
}
printf("INFO run : begin\n");
while (ip >= 0 && ip < current_line) {
// wait for user input
//getchar();
// execution
ip = exec(ip);
}
printf("INFO run : end\n");
}
/***** Private funciton *****/
int valid_memory_addr(int addr) {
return addr >= 0 && addr < MAX_MEMORY_SIZE;
}
int exec(int ip) {
int next_ip = ip + 1;
char ins = instructions[ip].ins;
int arg1 = instructions[ip].arg1;
int arg2 = instructions[ip].arg2;
int arg3 = instructions[ip].arg3;
printf("%d : ", ip);
// execute inst
switch (ins) {
case ADD:
printf("ADD @%d = @%d[%d] + @%d[%d]\n", arg1, arg2, memory[arg2], arg3, memory[arg3]);
memory[arg1] = memory[arg2] + memory[arg3]; break;
case MUL:
printf("MUL @%d = @%d[%d] * @%d[%d]\n", arg1, arg2, memory[arg2], arg3, memory[arg3]);
memory[arg1] = memory[arg2] * memory[arg3]; break;
case SOU:
printf("SOU @%d = @%d[%d] - @%d[%d]\n", arg1, arg2, memory[arg2], arg3, memory[arg3]);
memory[arg1] = memory[arg2] - memory[arg3]; break;
case DIV:
printf("DIV @%d = @%d[%d] / @%d[%d]\n", arg1, arg2, memory[arg2], arg3, memory[arg3]);
memory[arg1] = memory[arg2] / memory[arg3]; break;
case COP:
printf("COP @%d = @%d[%d]\n", arg1, arg2, memory[arg2]);
memory[arg1] = memory[arg2]; break;
case AFC:
printf("AFC @%d = %d\n", arg1, arg2);
memory[arg1] = arg2; break;
case JMP:
printf("JMP to %d\n", arg1);
next_ip = arg1; break;
case JMF:
printf("JMF cond@%d[%d] to %d\n", arg1, memory[arg1], arg2);
if (memory[arg1] == 0) next_ip = arg2;
break;
case INF:
printf("INF @%d = @%d[%d] < @%d[%d] ? 1 : 0\n", arg1, arg2, memory[arg2], arg3, memory[arg3]);
memory[arg1] = memory[arg2] < memory[arg3] ? 1 : 0;
break;
case SUP:
printf("SUP @%d = @%d[%d] > @%d[%d] ? 1 : 0\n", arg1, arg2, memory[arg2], arg3, memory[arg3]);
memory[arg1] = memory[arg2] > memory[arg3] ? 1 : 0;
break;
case EQU:
printf("EQU @%d = @%d[%d] == @%d[%d] ? 1 : 0\n", arg1, arg2, memory[arg2], arg3, memory[arg3]);
memory[arg1] = memory[arg2] == memory[arg3] ? 1 : 0;
break;
case PRI:
printf("PRI @%d[%d]\n", arg1, memory[arg1]);
break;
default:
fprintf(stderr, "ERROR run : unknown inst.\n");
}
return next_ip;
}

View file

@ -0,0 +1,26 @@
#ifndef __INSTRUCTIONS_H__
#define __INSTRUCTIONS_H__
#define ADD 1
#define MUL 2
#define SOU 3
#define DIV 4
#define COP 5
#define AFC 6
#define JMP 7
#define JMF 8
#define INF 9
#define SUP 10
#define EQU 11
#define PRI 12
#define MAX_INSTRUCTIONS_SIZE 256
#define MAX_MEMORY_SIZE 256
void asm_init();
void asm_add_3(char ins, int arg1, int arg2, int arg3);
void asm_add_2(char ins, int arg1, int arg2);
void asm_add_1(char ins, int arg1);
void asm_run();
#endif // #ifndef __INSTRUCTIONS_H__

38
interpreter/src/interpreter.l Executable file
View file

@ -0,0 +1,38 @@
%{
#include "y.tab.h"
%}
vSEP [ \t\r\n]
%%
ADD {return tADD;}
MUL {return tMUL;}
SOU {return tSOU;}
DIV {return tDIV;}
COP {return tCOP;}
AFC {return tAFC;}
JMP {return tJMP;}
JMF {return tJMF;}
INF {return tINF;}
SUP {return tSUP;}
EQU {return tEQU;}
PRI {return tPRI;}
-?[0-9]+ {
yylval.nb = atoi(yytext);
return tNB;
}
{vSEP} {}
. {
fprintf(stderr, "ERROR lex : Unknown pattern %s", yytext);
exit(1);
}
%%
int yywrap(void) { return 1; }
//int main(int argc, char *argv[]) { while (yylex()!=0) ; return 0; }

73
interpreter/src/interpreter.y Executable file
View file

@ -0,0 +1,73 @@
%{
#include <stdio.h>
#include "instructions.h"
int yylex();
void yyerror(char*);
int yydebug = 1;
extern int yylineno;
%}
/* Union for yylval */
%union {
int nb;
}
%token tADD tMUL tSOU tDIV tCOP tAFC tJMP tJMF tINF tSUP tEQU tPRI
%token <nb> tNB
%%
%start File;
File:
Instructions;
Instructions:
/* epsilon */
| Instructions Instruction
;
Instruction:
tADD tNB tNB tNB
{asm_add_3(ADD, $2, $3, $4);}
| tMUL tNB tNB tNB
{asm_add_3(MUL, $2, $3, $4);}
| tSOU tNB tNB tNB
{asm_add_3(SOU, $2, $3, $4);}
| tDIV tNB tNB tNB
{asm_add_3(DIV, $2, $3, $4);}
| tCOP tNB tNB
{asm_add_2(COP, $2, $3);}
| tAFC tNB tNB
{asm_add_2(AFC, $2, $3);}
| tJMP tNB
{asm_add_1(JMP, $2);}
| tJMF tNB tNB
{asm_add_2(JMF, $2, $3);}
| tINF tNB tNB tNB
{asm_add_3(INF, $2, $3, $4);}
| tSUP tNB tNB tNB
{asm_add_3(SUP, $2, $3, $4);}
| tEQU tNB tNB tNB
{asm_add_3(EQU, $2, $3, $4);}
| tPRI tNB
{asm_add_1(PRI, $2);}
;
%%
void yyerror(char* str) {
extern int yylineno;
fprintf(stderr, "ERROR yyparse : Line %d: %s\n", yylineno, str);
}
int main(int argc, char *argv[]) {
asm_init();
yyparse();
printf("INFO yyparse : Parsing End\n");
asm_run();
return 0;
}