Add string input interrupt from STDIN
This commit is contained in:
31
README.md
31
README.md
@@ -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.
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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');
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user