Add string input interrupt from STDIN

This commit is contained in:
2020-05-17 14:13:15 +02:00
parent 2d820e7028
commit fc2870ca74
5 changed files with 92 additions and 16 deletions

View File

@@ -89,22 +89,22 @@ There is currently no strict checking, so be careful.
## Directives ## Directives
- `DECLARE` declares the first label argument to equal the second, immediate - `DECLARE` declares the first label argument to equal the second, immediate
value, argument and is used to declare a constant for the virtual machine. value, argument and is used to declare a constant for the virtual machine.
### Operands ### Operands
- `addi` add the first to the second argument and store the result in the third - `addi` add the first to the second argument and store the result in the third
argument argument
- `subi` subtract the first from the second argument and store the result in - `subi` subtract the first from the second argument and store the result in
the third argument the third argument
- `divi` divide the first by the second argument and store the result in the - `divi` divide the first by the second argument and store the result in the
third argument third argument
- `muli` multiply the first by the second argument and store the result in the - `muli` multiply the first by the second argument and store the result in the
third argument third argument
- `shli` shift left the first argument by the number of positions given by the - `shli` shift left the first argument by the number of positions given by the
second argument and store the result in the third argument second argument and store the result in the third argument
- `shri` shift right the first argument by the number of positions given by the - `shri` shift right the first argument by the number of positions given by the
second argument and store the result in the third argument second argument and store the result in the third argument
- `seti` set the first register argument to the second argument - `seti` set the first register argument to the second argument
- `int` calls the interrupt specified by the first (integer) argument - `int` calls the interrupt specified by the first (integer) argument
@@ -112,15 +112,15 @@ second argument and store the result in the third argument
- `jmp` jump to the label given by the first argument - `jmp` jump to the label given by the first argument
- `call` put the next statement to execute on the stack and jump to the label - `call` put the next statement to execute on the stack and jump to the label
given by the first argument given by the first argument
- `ret` pop the the next statement to execute off the stack, e.g. returning to - `ret` pop the the next statement to execute off the stack, e.g. returning to
the next execution statement before calling `call` the next execution statement before calling `call`
- `lti` execute next statement if argument 1 is less than argument 2 else skip - `lti` execute next statement if argument 1 is less than argument 2 else skip
the next statement the next statement
- `gti` execute next statement if argument 1 is greater than argument 2 else - `gti` execute next statement if argument 1 is greater than argument 2 else
skip the next statement skip the next statement
- `eqi` execute the next statement if argument 1 is equal to argument 2 else - `eqi` execute the next statement if argument 1 is equal to argument 2 else
skip the next statement skip the next statement
## Memory ## Memory
@@ -137,5 +137,8 @@ the first argument
- `2` put value of register A as hexadecimal integer on stdout - `2` put value of register A as hexadecimal integer on stdout
- `3` put the string pointed at by register A for the amount of characters - `3` put the string pointed at by register A for the amount of characters
defined by register B on stdout defined by register B on stdout
- [4..4] Input from STDIN - [4..5] Input from STDIN
- `4` get a single ASCII character from STDIN and store it in register A - `4` get a single ASCII character from STDIN and store it in register A
- `5` get a string of a maximum length determined by register B and store it
in the address specified by register A. After execution register B will
contain the number of characters actually read.

View File

@@ -88,12 +88,22 @@ seti %A $900;
seti %B $4; seti %B $4;
int $3; int $3;
# Jump over the interrupt # Call a function
call noop_function; call noop_function;
# Echo a character # Echo a character
int $4; int $4;
int $0; int $0;
seti %A $10; # newline
int $0;
# Echo a string
seti %A $0;
seti %B $10;
int $5;
int $3;
exit; exit;
noop_function: noop_function:

View File

@@ -39,6 +39,12 @@ namespace Execute
InterruptIndexOutOfRange(int const index); InterruptIndexOutOfRange(int const index);
}; };
class OutOfMemory : public RuntimeError
{
public:
OutOfMemory(int const memoryLocation, int const memorySize);
};
namespace Internal namespace Internal
{ {
class BadValueType : public RuntimeError class BadValueType : public RuntimeError

View File

@@ -41,6 +41,15 @@ namespace Execute
message += " is out of range"; message += " is out of range";
} }
OutOfMemory::OutOfMemory(int const memoryLocation, int const memorySize)
{
message = "Attempted interaction at memory location ";
message += std::to_string(memoryLocation);
message += " with size ";
message += std::to_string(memorySize);
message += " failed";
}
namespace Internal namespace Internal
{ {
BadValueType::BadValueType() BadValueType::BadValueType()

View File

@@ -1,4 +1,5 @@
#include <cstdio> #include <cstdio>
#include <execute/error.hpp>
#include <execute/interrupts.hpp> #include <execute/interrupts.hpp>
namespace Execute namespace Execute
@@ -18,6 +19,11 @@ namespace Execute
[](Execute::Registers & registers, std::vector<std::uint8_t> & memory) [](Execute::Registers & registers, std::vector<std::uint8_t> & memory)
{ {
unsigned const end = registers.A + registers.B; unsigned const end = registers.A + registers.B;
if (end >= memory.size())
{
throw OutOfMemory(registers.A, registers.B);
}
for(unsigned i = registers.A; i < end; ++i) for(unsigned i = registers.A; i < end; ++i)
{ {
std::putc(memory[i], stdout); std::putc(memory[i], stdout);
@@ -29,7 +35,49 @@ namespace Execute
[](Execute::Registers & registers, std::vector<std::uint8_t> & memory) [](Execute::Registers & registers, std::vector<std::uint8_t> & memory)
{ {
registers.A = std::getchar(); registers.A = std::getchar();
} if (registers.A == '\n')
{
return;
}
while(std::getchar() != '\n');
},
// 11 get string from STDIN
[](Execute::Registers & registers, std::vector<std::uint8_t> & memory)
{
if (registers.B <= 0)
{
registers.B = 0;
return;
}
if (registers.A < 0 || static_cast<unsigned>(registers.A + registers.B) >= memory.size())
{
throw OutOfMemory(registers.A, registers.B);
}
int charactersRead = 0;
bool newlineRead = false;
while(charactersRead < registers.B)
{
char result = std::getchar();
if (result == '\n')
{
newlineRead = true;
break;
}
memory[registers.A + charactersRead] = result;
++charactersRead;
}
registers.B = charactersRead;
if (!newlineRead)
{
while(std::getchar() != '\n');
}
},
}; };
} }
} }