1 module vm;
2 
3 import std.stdio;
4 import std.string;
5 import std.regex;
6 import std.array;
7 import std.conv;
8 import core.stdc.stdio;
9 
10 struct Instruction
11 {
12     void delegate(in size_t) dg;
13     size_t value;
14 }
15 
16 class VirtualMachine
17 {
18     private:
19         size_t pcnt;
20         size_t ptr;
21         ubyte[] memory;
22         string source;
23         Instruction[] instructions;
24 
25         void padd(in size_t n)
26         {
27             ptr += n;
28         }
29         void psub(in size_t n)
30         {
31             ptr -= n;
32         }
33         void dadd(in size_t n)
34         {
35             memory[ptr] += n;
36         }
37         void dsub(in size_t n)
38         {
39             memory[ptr] -= n;
40         }
41         void skip(in size_t n)
42         {
43             if(memory[ptr] == 0) pcnt = n;
44         }
45         void loop(in size_t n)
46         {
47             if(memory[ptr] != 0) pcnt = n;
48         }
49         void putc(in size_t n)
50         {
51             putchar(memory[ptr]);
52         }
53         void getc(in size_t n)
54         {
55             int tmp = getchar();
56             if(tmp == EOF) throw new Error("EOF");
57             memory[ptr] = tmp.to!ubyte;
58         }
59         void zero(in size_t n)
60         {
61             memory[ptr] = 0;
62         }
63         void end(in size_t n)
64         {
65             throw new Exception("end");
66         }
67     public:
68         this(string _source, size_t buffsize)
69         {
70             memory = new ubyte[](buffsize);
71             source = _source;
72         }
73         void parse()
74         {
75             string formatted;
76             foreach(c;source)
77             {
78                 if("+-<>[].,".indexOf(c) != -1) formatted ~= c;
79             }
80             formatted = formatted.replace(regex(r"\[-\]","g"),"z");
81             size_t[] loopstack;
82             auto prev = ' ';
83             foreach(c;formatted)
84             {
85                 switch(c)
86                 {
87                     case '>':
88                         if(prev == '>')
89                         {
90                             instructions.back.value++;
91                         }else{
92                             instructions ~= Instruction(&this.padd,1);
93                         }
94                         break;
95                     case '<':
96                         if(prev == '<')
97                         {
98                             instructions.back.value++;
99                         }else{
100                             instructions ~= Instruction(&this.psub,1);
101                         }
102                         break;
103                     case '+':
104                         if(prev == '+')
105                         {
106                             instructions.back.value++;
107                         }else{
108                             instructions ~= Instruction(&this.dadd,1);
109                         }
110                         break;
111                     case '-':
112                         if(prev == '-')
113                         {
114                             instructions.back.value++;
115                         }else{
116                             instructions ~= Instruction(&this.dsub,1);
117                         }
118                         break;
119                     case '[':
120                         loopstack ~= instructions.length;
121                         instructions ~= Instruction(&this.skip,0);
122                         break;
123                     case ']':
124                         instructions[loopstack.back].value = instructions.length;
125                         instructions ~= Instruction(&this.loop,loopstack.back);
126                         loopstack.popBack();
127                         break;
128                     case '.':
129                         instructions ~= Instruction(&this.putc,0);
130                         break;
131                     case ',':
132                         instructions ~= Instruction(&this.getc,0);
133                         break;
134                     case 'z':
135                         instructions ~= Instruction(&this.zero,0);
136                         break;
137                     default:
138                 }
139                 prev = c;
140             }
141             instructions ~= Instruction(&this.end,0);
142         }
143         void run()
144         {
145             pcnt = 0;
146             ptr = 0;
147             while(true)
148             {
149                 instructions[pcnt].dg(instructions[pcnt].value);
150                 pcnt++;
151             }
152         }
153 }