Website Summary Files Commits Branches @commit @diff @stats
path: root / homework / 81568 / BF_Interpreter / bf_interpreter.cpp
blob: 28d4c18962225f1c315d176f0fb831ad91a273fa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "bf_interpreter.h"

#include <cmath>
#include <cstring>
#include <iostream>
#include <stack>

#ifndef MEMSIZE
#define MEMSIZE 30000
#endif

BFInterpreter::BFInterpreter(const char *program, std::istream &input, std::ostream &output) :
  memory_blocks(nullptr), p(nullptr),
  program(nullptr), input(input), output(output),
  memory_size(MEMSIZE) {
  
  this->program = new char[strlen(program) + 1];
  strncpy(this->program, program, strlen(program) + 1);
  pp = this->program;

  memory_blocks = new uchar[memory_size];
  for (int i = 0; i < memory_size; ++i) {
    memory_blocks[i] = 0;
  }
  p = memory_blocks;
}

BFInterpreter::~BFInterpreter() {
  delete [] memory_blocks;
  delete [] program;
}

void BFInterpreter::addMemory() {
  uchar *new_memory = new uchar[memory_size + ((size_t) log2(memory_size))];
  for (int i = 0; i < memory_size; ++i) {
    new_memory[i] = memory_blocks[i];
  }
  delete [] memory_blocks;
  memory_blocks = new_memory;
  memory_size += log2(memory_size);
}

void BFInterpreter::compile() {
  while (*pp) {
    switch (*pp) {
    case '[':
      ++pp;
      loop();
      break;
    case ']': // that will only happen if code is wrong
      printf("Syntax error!\n");
      return;
    default:
      proccessNonLoopCmd(*pp);
    }
    ++pp;
  }
  output.put('\n');
}

void BFInterpreter::loop() {
  std::stack<char*> loops;
  loops.push(pp);
  
  char *body = loops.top();
  while (!loops.empty()) {
    while (*body != ']' && *body != '[') {
      proccessNonLoopCmd(*body);
      ++body;
    }
    if (*body == ']') {
      if (!*p) { /* End of a loop */
        loops.pop();
        ++body;
      } else { /* Loop has not ended. Return to the beginning of the current loop */
        body = loops.top();
      }
    } else { /* Start of a new loop */
      loops.push(body + 1);
      ++body;
    }
  }
  pp = --body;
  return;
}

void BFInterpreter::proccessNonLoopCmd(char c) {
  switch (c) {
  case '+':
    ++*p;
    break;
  case '-':
    --*p;
    break;
  case '.':
    output.put(*p);
    break;
  case ',':
    *p = input.get();
    break;
  case '<':
    if (p == memory_blocks)
      p = memory_blocks + (memory_size - 1);
    else 
      --p;
    break;
  case '>':
    if (p == memory_blocks + (memory_size - 1))
      p = memory_blocks;
    else
      ++p;
    break;
  }
}