This commit is contained in:
parent
616de523cf
commit
5997f06bd0
@ -30,7 +30,7 @@ Some of the supported features are:
|
|||||||
- Integer conversion(`$`);
|
- Integer conversion(`$`);
|
||||||
- Bitwise operations(`{`, `}`, `l`, `L`, `m`, `M`);
|
- Bitwise operations(`{`, `}`, `l`, `L`, `m`, `M`);
|
||||||
- Stack operations:
|
- Stack operations:
|
||||||
- Print top element(`p`, `P`);
|
- Print top element(`p`, `P`, `p.`);
|
||||||
- Clear the stack(`c`);
|
- Clear the stack(`c`);
|
||||||
- Remove top element(`R`);
|
- Remove top element(`R`);
|
||||||
- Swap order of top two elements(`r`);
|
- Swap order of top two elements(`r`);
|
||||||
@ -281,9 +281,8 @@ lL x 0 ;A lN /
|
|||||||
lV FF { 0 :A # Blue
|
lV FF { 0 :A # Blue
|
||||||
lV 8 M FF { 1 :A # Green
|
lV 8 M FF { 1 :A # Green
|
||||||
lV 10 M FF { 2 :A # Red
|
lV 10 M FF { 2 :A # Red
|
||||||
[ RED: ] P R 2 ;A p
|
[ , ] sc
|
||||||
[ GREEN: ] P R 1 ;A p
|
[ [ RGB( ] P 2 ;A P lc p. 1 ;A P lc p. 0 ;A P [ ) ] p. [ = ] p. lV ph ] x
|
||||||
[ BLUE: ] P R 0 ;A p
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
25
man.md
25
man.md
@ -3,7 +3,7 @@ title: dc
|
|||||||
section: 1
|
section: 1
|
||||||
header: General Commands Manual
|
header: General Commands Manual
|
||||||
footer: Marco Cetica
|
footer: Marco Cetica
|
||||||
date: March 20, 2024
|
date: March 25, 2024
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
@ -378,11 +378,21 @@ the array `r`, indexed by the top-of-stack value.
|
|||||||
Pops the top-of-stack and uses it as an index into array `r`. The selected value
|
Pops the top-of-stack and uses it as an index into array `r`. The selected value
|
||||||
is then pushed onto the stack.
|
is then pushed onto the stack.
|
||||||
|
|
||||||
## Strings
|
## Strings/Macros
|
||||||
|
|
||||||
_dc_ has a limited ability to operate on strings as well as on numbers; the only things you can do with strings are print them and execute them as macros (which means that the content of a string can execute as a _dc_ program). Any kind of stack can hold strings, and _dc_ always knows whether any given object is a string or a number.
|
_dc_ has a limited ability to operate on strings as well as on numbers; strings can be printed or executed as a macro, that is as a dc program.
|
||||||
Some commands such as arithmetic operations demand numbers as arguments and print errors if given strings.
|
Strings can be nested, i.e. a string can contain another string. For example:
|
||||||
Other commands can accept either a number or a string; for example, the **p** command can accept either and prints the object according to its type.
|
|
||||||
|
- **\[ 1 \] p**: Prints the string(note: `1` is a string and not a number);
|
||||||
|
- **\[ \[ Hello World \] p \] x**: pushes a string containing another string and a command and execute it;
|
||||||
|
- **\[ Executing: \] p \[ 2 p 10 p \[ r / p \] p x \] x**: Prints the ongoing operation and execute it using homoiconicity property.
|
||||||
|
|
||||||
|
When a string is used as a macro, dc *lazily evaluate* it; that is, the evaluation of subprograms is delayed until the evaluator requires their values.
|
||||||
|
Avoiding eagerly evaluation allows the programmer to take advantage of DC's homoiconicity and to make macro evaluation more lightweight.
|
||||||
|
|
||||||
|
Any kind of stack can hold strings, and _dc_ always knows whether any given object is a string or a number. Some commands such as arithmetic operations demand
|
||||||
|
numbers as arguments and print errors if given strings. Other commands can accept either a number or a string; for example, the **p**
|
||||||
|
command can accept either and prints the object according to its type.
|
||||||
|
|
||||||
**[ characters ]**
|
**[ characters ]**
|
||||||
|
|
||||||
@ -568,9 +578,8 @@ lL x 0 ;A lN /
|
|||||||
lV FF { 0 :A # Blue
|
lV FF { 0 :A # Blue
|
||||||
lV 8 M FF { 1 :A # Green
|
lV 8 M FF { 1 :A # Green
|
||||||
lV 10 M FF { 2 :A # Red
|
lV 10 M FF { 2 :A # Red
|
||||||
[ RED: ] P R 2 ;A p
|
[ , ] sc
|
||||||
[ GREEN: ] P R 1 ;A p
|
[ [ RGB( ] P 2 ;A P lc p. 1 ;A P lc p. 0 ;A P [ ) ] p. [ = ] p. lV ph ] x
|
||||||
[ BLUE: ] P R 0 ;A p
|
|
||||||
```
|
```
|
||||||
|
|
||||||
# AUTHORS
|
# AUTHORS
|
||||||
|
29
src/eval.cpp
29
src/eval.cpp
@ -52,6 +52,7 @@ void Evaluate::init_environment() {
|
|||||||
this->op_factory.emplace("M", MAKE_UNIQUE_PTR(Bitwise, OPType::BSR));
|
this->op_factory.emplace("M", MAKE_UNIQUE_PTR(Bitwise, OPType::BSR));
|
||||||
// Stack operations
|
// Stack operations
|
||||||
this->op_factory.emplace("p", MAKE_UNIQUE_PTR(Stack, OPType::PCG));
|
this->op_factory.emplace("p", MAKE_UNIQUE_PTR(Stack, OPType::PCG));
|
||||||
|
this->op_factory.emplace("p.", MAKE_UNIQUE_PTR(Stack, OPType::PWS));
|
||||||
this->op_factory.emplace("pb", MAKE_UNIQUE_PTR(Stack, OPType::PBB));
|
this->op_factory.emplace("pb", MAKE_UNIQUE_PTR(Stack, OPType::PBB));
|
||||||
this->op_factory.emplace("ph", MAKE_UNIQUE_PTR(Stack, OPType::PBH));
|
this->op_factory.emplace("ph", MAKE_UNIQUE_PTR(Stack, OPType::PBH));
|
||||||
this->op_factory.emplace("po", MAKE_UNIQUE_PTR(Stack, OPType::PBO));
|
this->op_factory.emplace("po", MAKE_UNIQUE_PTR(Stack, OPType::PBO));
|
||||||
@ -137,17 +138,21 @@ std::optional<std::string> Evaluate::parse_base_n(const std::string& token) {
|
|||||||
std::optional<std::string> Evaluate::parse_macro(std::size_t &idx) {
|
std::optional<std::string> Evaluate::parse_macro(std::size_t &idx) {
|
||||||
// A macro is any string surrounded by square brackets
|
// A macro is any string surrounded by square brackets
|
||||||
std::string dc_macro;
|
std::string dc_macro;
|
||||||
bool closing_bracket = false;
|
std::int8_t brackets_count = 1;
|
||||||
|
|
||||||
// Scan next token
|
// Scan next token
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
// Parse the macro
|
// Parse the macro
|
||||||
while(idx < this->expr.size()) {
|
while(idx < this->expr.size()) {
|
||||||
// Continue to parse until the clsoing square brackets
|
// Parse nested macros as well
|
||||||
if(this->expr.at(idx) == "]") {
|
if(this->expr.at(idx) == "[") {
|
||||||
closing_bracket = true;
|
brackets_count++;
|
||||||
break;
|
} else if(this->expr.at(idx) == "]") {
|
||||||
|
brackets_count--;
|
||||||
|
if(brackets_count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise append the token to the macro.
|
// Otherwise append the token to the macro.
|
||||||
@ -164,7 +169,7 @@ std::optional<std::string> Evaluate::parse_macro(std::size_t &idx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if macro is properly formatted
|
// Check if macro is properly formatted
|
||||||
if(!closing_bracket) {
|
if(brackets_count != 0) {
|
||||||
return "Unbalanced parenthesis";
|
return "Unbalanced parenthesis";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,37 +206,37 @@ std::optional<std::string> Evaluate::parse_macro_command(std::string token) {
|
|||||||
// execute register's content as a macro
|
// execute register's content as a macro
|
||||||
std::optional<std::string> err = std::nullopt;
|
std::optional<std::string> err = std::nullopt;
|
||||||
if(operation == ">") {
|
if(operation == ">") {
|
||||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GT, dc_register);
|
auto macro = std::make_unique<Macro>(OPType::CMP, MacroOP::GT, dc_register);
|
||||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||||
if(err != std::nullopt) {
|
if(err != std::nullopt) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if(operation == "<") {
|
} else if(operation == "<") {
|
||||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LT, dc_register);
|
auto macro = std::make_unique<Macro>(OPType::CMP, MacroOP::LT, dc_register);
|
||||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||||
if(err != std::nullopt) {
|
if(err != std::nullopt) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if(operation == "=") {
|
} else if(operation == "=") {
|
||||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::EQ, dc_register);
|
auto macro = std::make_unique<Macro>(OPType::CMP, MacroOP::EQ, dc_register);
|
||||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||||
if(err != std::nullopt) {
|
if(err != std::nullopt) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if(operation == ">=") {
|
} else if(operation == ">=") {
|
||||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::GEQ, dc_register);
|
auto macro = std::make_unique<Macro>(OPType::CMP, MacroOP::GEQ, dc_register);
|
||||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||||
if(err != std::nullopt) {
|
if(err != std::nullopt) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if(operation == "<=") {
|
} else if(operation == "<=") {
|
||||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::LEQ, dc_register);
|
auto macro = std::make_unique<Macro>(OPType::CMP, MacroOP::LEQ, dc_register);
|
||||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||||
if(err != std::nullopt) {
|
if(err != std::nullopt) {
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
} else if(operation == "!=") {
|
} else if(operation == "!=") {
|
||||||
auto macro = std::make_unique<Macro>(OPType::CMP, Operator::NEQ, dc_register);
|
auto macro = std::make_unique<Macro>(OPType::CMP, MacroOP::NEQ, dc_register);
|
||||||
err = macro->exec(this->stack, this->parameters, this->regs);
|
err = macro->exec(this->stack, this->parameters, this->regs);
|
||||||
if(err != std::nullopt) {
|
if(err != std::nullopt) {
|
||||||
return err;
|
return err;
|
||||||
|
@ -70,7 +70,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc::Stack<std::string> &stac
|
|||||||
auto second = std::stod(second_str);
|
auto second = std::stod(second_str);
|
||||||
|
|
||||||
switch(this->op) {
|
switch(this->op) {
|
||||||
case Operator::GT: {
|
case MacroOP::GT: {
|
||||||
if(head > second) {
|
if(head > second) {
|
||||||
std::vector<std::string> tokens = split(dc_macro);
|
std::vector<std::string> tokens = split(dc_macro);
|
||||||
Evaluate evaluator(tokens, regs, stack, parameters);
|
Evaluate evaluator(tokens, regs, stack, parameters);
|
||||||
@ -82,7 +82,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc::Stack<std::string> &stac
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Operator::LT: {
|
case MacroOP::LT: {
|
||||||
if(head < second) {
|
if(head < second) {
|
||||||
std::vector<std::string> tokens = split(dc_macro);
|
std::vector<std::string> tokens = split(dc_macro);
|
||||||
Evaluate evaluator(tokens, regs, stack, parameters);
|
Evaluate evaluator(tokens, regs, stack, parameters);
|
||||||
@ -94,7 +94,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc::Stack<std::string> &stac
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Operator::EQ: {
|
case MacroOP::EQ: {
|
||||||
if(head == second) {
|
if(head == second) {
|
||||||
std::vector<std::string> tokens = split(dc_macro);
|
std::vector<std::string> tokens = split(dc_macro);
|
||||||
Evaluate evaluator(tokens, regs, stack, parameters);
|
Evaluate evaluator(tokens, regs, stack, parameters);
|
||||||
@ -106,7 +106,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc::Stack<std::string> &stac
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Operator::GEQ: {
|
case MacroOP::GEQ: {
|
||||||
if(head >= second) {
|
if(head >= second) {
|
||||||
std::vector<std::string> tokens = split(dc_macro);
|
std::vector<std::string> tokens = split(dc_macro);
|
||||||
Evaluate evaluator(tokens, regs, stack, parameters);
|
Evaluate evaluator(tokens, regs, stack, parameters);
|
||||||
@ -118,7 +118,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc::Stack<std::string> &stac
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Operator::LEQ: {
|
case MacroOP::LEQ: {
|
||||||
if(head <= second) {
|
if(head <= second) {
|
||||||
std::vector<std::string> tokens = split(dc_macro);
|
std::vector<std::string> tokens = split(dc_macro);
|
||||||
Evaluate evaluator(tokens, regs, stack, parameters);
|
Evaluate evaluator(tokens, regs, stack, parameters);
|
||||||
@ -130,7 +130,7 @@ std::optional<std::string> Macro::fn_evaluate_macro(dc::Stack<std::string> &stac
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Operator::NEQ: {
|
case MacroOP::NEQ: {
|
||||||
if(head != second) {
|
if(head != second) {
|
||||||
std::vector<std::string> tokens = split(dc_macro);
|
std::vector<std::string> tokens = split(dc_macro);
|
||||||
Evaluate evaluator(tokens, regs, stack, parameters);
|
Evaluate evaluator(tokens, regs, stack, parameters);
|
||||||
|
@ -2,13 +2,13 @@
|
|||||||
|
|
||||||
#include "operation.h"
|
#include "operation.h"
|
||||||
|
|
||||||
enum class Operator {
|
enum class MacroOP {
|
||||||
GT, LT, EQ, GEQ, LEQ, NEQ
|
GT, LT, EQ, GEQ, LEQ, NEQ
|
||||||
};
|
};
|
||||||
|
|
||||||
class Macro : public IOperation {
|
class Macro : public IOperation {
|
||||||
public:
|
public:
|
||||||
Macro(const OPType op_t, const Operator o, const char dc_r) : op_type(op_t), op(o), dc_register(dc_r) {}
|
Macro(const OPType op_t, const MacroOP o, const char dc_r) : op_type(op_t), op(o), dc_register(dc_r) {}
|
||||||
explicit Macro(const OPType op_t) : op_type(op_t) {}
|
explicit Macro(const OPType op_t) : op_type(op_t) {}
|
||||||
std::optional<std::string> exec(dc::Stack<std::string> &stack, dc::Parameters ¶meters, std::unordered_map<char, dc::Register> ®s) override;
|
std::optional<std::string> exec(dc::Stack<std::string> &stack, dc::Parameters ¶meters, std::unordered_map<char, dc::Register> ®s) override;
|
||||||
static std::vector<std::string> split(const std::string& str);
|
static std::vector<std::string> split(const std::string& str);
|
||||||
@ -20,6 +20,6 @@ private:
|
|||||||
static std::optional<std::string> fn_evaluate_file(dc::Stack<std::string> &stack, dc::Parameters ¶meters, std::unordered_map<char, dc::Register> ®s);
|
static std::optional<std::string> fn_evaluate_file(dc::Stack<std::string> &stack, dc::Parameters ¶meters, std::unordered_map<char, dc::Register> ®s);
|
||||||
|
|
||||||
OPType op_type;
|
OPType op_type;
|
||||||
Operator op{};
|
MacroOP op{};
|
||||||
char dc_register{};
|
char dc_register{};
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,7 @@ enum class OPType {
|
|||||||
// Bitwise operations
|
// Bitwise operations
|
||||||
BAND, BOR, BNOT, BXOR, BSL, BSR,
|
BAND, BOR, BNOT, BXOR, BSL, BSR,
|
||||||
// Stack operations
|
// Stack operations
|
||||||
PCG, P, PBB, PBH, PBO, CLR, PH, SO, DP, PS, CH, CS,
|
PCG, PWS, P, PBB, PBH, PBO, CLR, PH, SO, DP, PS, CH, CS,
|
||||||
SP, GP, SOR, GOR, SIR, GIR, LX, LY, LZ,
|
SP, GP, SOR, GOR, SIR, GIR, LX, LY, LZ,
|
||||||
// Macro operations
|
// Macro operations
|
||||||
EX, CMP, RI, LF
|
EX, CMP, RI, LF
|
||||||
|
@ -13,15 +13,16 @@ std::optional<std::string> Stack::exec(dc::Stack<std::string> &stack, dc::Parame
|
|||||||
auto print_oradix = [&stack, ¶meters, this](dc::radix_base base) {
|
auto print_oradix = [&stack, ¶meters, this](dc::radix_base base) {
|
||||||
auto old_rdx = parameters.oradix;
|
auto old_rdx = parameters.oradix;
|
||||||
parameters.oradix = base;
|
parameters.oradix = base;
|
||||||
auto res = fn_print(stack, parameters, false);
|
auto res = fn_print(stack, parameters, StackOP::P);
|
||||||
parameters.oradix = old_rdx;
|
parameters.oradix = old_rdx;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch(this->op_type) {
|
switch(this->op_type) {
|
||||||
case OPType::PCG: err = fn_print(stack, parameters, true); break;
|
case OPType::PCG: err = fn_print(stack, parameters, StackOP::PNL); break;
|
||||||
case OPType::P: err = fn_print(stack, parameters, false); break;
|
case OPType::P: err = fn_print(stack, parameters, StackOP::P); break;
|
||||||
|
case OPType::PWS: err = fn_print(stack, parameters, StackOP::PS); break;
|
||||||
case OPType::PBB: err = print_oradix(dc::radix_base::BIN); break;
|
case OPType::PBB: err = print_oradix(dc::radix_base::BIN); break;
|
||||||
case OPType::PBO: err = print_oradix(dc::radix_base::OCT); break;
|
case OPType::PBO: err = print_oradix(dc::radix_base::OCT); break;
|
||||||
case OPType::PBH: err = print_oradix(dc::radix_base::HEX); break;
|
case OPType::PBH: err = print_oradix(dc::radix_base::HEX); break;
|
||||||
@ -47,7 +48,7 @@ std::optional<std::string> Stack::exec(dc::Stack<std::string> &stack, dc::Parame
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<std::string> Stack::fn_print(dc::Stack<std::string> &stack, dc::Parameters ¶meters, bool new_line) {
|
std::optional<std::string> Stack::fn_print(dc::Stack<std::string> &stack, dc::Parameters ¶meters, const StackOP op) {
|
||||||
// Check if the stack is empty
|
// Check if the stack is empty
|
||||||
if(stack.empty()) {
|
if(stack.empty()) {
|
||||||
return "Cannot print empty stack";
|
return "Cannot print empty stack";
|
||||||
@ -60,10 +61,10 @@ std::optional<std::string> Stack::fn_print(dc::Stack<std::string> &stack, dc::Pa
|
|||||||
|
|
||||||
switch(parameters.oradix) {
|
switch(parameters.oradix) {
|
||||||
case dc::radix_base::DEC: {
|
case dc::radix_base::DEC: {
|
||||||
if(new_line) {
|
switch(op) {
|
||||||
std::cout << stack.pop(false) << std::endl;
|
case StackOP::PNL: std::cout << stack.pop(false) << std::endl; break;
|
||||||
} else {
|
case StackOP::P: std::cout << stack.pop(false); break;
|
||||||
std::cout << stack.pop(false);
|
case StackOP::PS: std::cout << stack.pop(false) << ' '; break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,17 @@
|
|||||||
|
|
||||||
#include "operation.h"
|
#include "operation.h"
|
||||||
|
|
||||||
|
enum class StackOP {
|
||||||
|
P, PNL, PS
|
||||||
|
};
|
||||||
|
|
||||||
class Stack : public IOperation {
|
class Stack : public IOperation {
|
||||||
public:
|
public:
|
||||||
explicit Stack(const OPType op_t) : op_type(op_t) {}
|
explicit Stack(const OPType op_t) : op_type(op_t) {}
|
||||||
std::optional<std::string> exec(dc::Stack<std::string> &stack, dc::Parameters ¶meters, std::unordered_map<char, dc::Register> ®s) override;
|
std::optional<std::string> exec(dc::Stack<std::string> &stack, dc::Parameters ¶meters, std::unordered_map<char, dc::Register> ®s) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<std::string> fn_print(dc::Stack<std::string> &stack, dc::Parameters ¶meters, bool new_line);
|
std::optional<std::string> fn_print(dc::Stack<std::string> &stack, dc::Parameters ¶meters, const StackOP op);
|
||||||
static std::optional<std::string> fn_pop_head(dc::Stack<std::string> &stack);
|
static std::optional<std::string> fn_pop_head(dc::Stack<std::string> &stack);
|
||||||
static std::optional<std::string> fn_swap_xy(dc::Stack<std::string> &stack);
|
static std::optional<std::string> fn_swap_xy(dc::Stack<std::string> &stack);
|
||||||
static std::optional<std::string> fn_dup_head(dc::Stack<std::string> &stack);
|
static std::optional<std::string> fn_dup_head(dc::Stack<std::string> &stack);
|
||||||
|
@ -90,9 +90,28 @@ test_print_no_newline() {
|
|||||||
assert_eq "$EXPECTED" "$ACTUAL"
|
assert_eq "$EXPECTED" "$ACTUAL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test_print_space() {
|
||||||
|
PROGRAM="$PWD/build/dc"
|
||||||
|
EXPECTED="0 1"
|
||||||
|
ACTUAL=$("$PROGRAM" -e '1 0 p. R P')
|
||||||
|
assert_eq "$EXPECTED" "$ACTUAL"
|
||||||
|
|
||||||
|
# Test empty stack
|
||||||
|
EXPECTED="Cannot print empty stack"
|
||||||
|
ACTUAL=$("$PROGRAM" -e 'p.' 2>&1) || true
|
||||||
|
assert_eq "$EXPECTED" "$ACTUAL"
|
||||||
|
|
||||||
|
# Test non numerical values
|
||||||
|
EXPECTED="foo "
|
||||||
|
ACTUAL=$("$PROGRAM" -e '[ foo ] p.' 2>&1) || true
|
||||||
|
assert_eq "$EXPECTED" "$ACTUAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
utest() {
|
utest() {
|
||||||
test_print
|
test_print
|
||||||
test_print_no_newline
|
test_print_no_newline
|
||||||
|
test_print_space
|
||||||
test_print_bin
|
test_print_bin
|
||||||
test_print_hex
|
test_print_hex
|
||||||
test_print_oct
|
test_print_oct
|
||||||
|
Loading…
Reference in New Issue
Block a user