mirror of
https://github.com/chrim05/nds-console.git
synced 2025-06-18 13:45:33 -04:00
added readme
This commit is contained in:
parent
d54ebd1f71
commit
d91682c3dc
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
build/
|
||||
.vscode/
|
||||
*.elf
|
||||
*.nds
|
10
.vscode/c_cpp_properties.json
vendored
10
.vscode/c_cpp_properties.json
vendored
@ -3,15 +3,15 @@
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"/opt/devkitpro/devkitARM/arm-none-eabi/include",
|
||||
"/opt/devkitpro/libnds/include",
|
||||
"C:/devkitpro/devkitARM/arm-none-eabi/include",
|
||||
"C:/devkitpro/libnds/include",
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/gcc",
|
||||
"defines": ["ARM9"],
|
||||
"compilerPath": "C:/devkitPro/devkitARM/bin/arm-none-eabi-g++.exe",
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "linux-gcc-x64"
|
||||
"intelliSenseMode": "windows-gcc-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
|
61
readme.md
Normal file
61
readme.md
Normal file
@ -0,0 +1,61 @@
|
||||
# why
|
||||
* for fun
|
||||
* having a terminal application on your ds which gets more control over it
|
||||
|
||||
# requirements
|
||||
* devkitpro
|
||||
* make
|
||||
* desmume (optional)
|
||||
|
||||
# how to compile it
|
||||
```
|
||||
clone https://github.com/christallo/nds-console
|
||||
cd nds-console
|
||||
make
|
||||
```
|
||||
|
||||
# how to run it
|
||||
* on desmume (for debugging)
|
||||
```
|
||||
make && desmume nds-console.nds
|
||||
```
|
||||
* on physical nintendo ds console (for distrubution)
|
||||
* * `make`
|
||||
* * move `nds-console.nds` to your R4 or your modded sd
|
||||
|
||||
# how to edit it in vscode
|
||||
* create a configuration json file for c/cpp
|
||||
* open `.vscode\c_cpp_properties.json`
|
||||
* write
|
||||
```json
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Win32", // for windows
|
||||
"name": "Linux", // for linux
|
||||
|
||||
"includePath": [
|
||||
"C:/devkitpro/devkitARM/arm-none-eabi/include", // for windows
|
||||
"/opt/devkitpro/devkitARM/arm-none-eabi/include", // for linux
|
||||
|
||||
"C:/devkitpro/libnds/include", // for windows
|
||||
"/opt/devkitpro/libnds/include", // for linux
|
||||
|
||||
"${workspaceFolder}/**"
|
||||
],
|
||||
|
||||
"defines": ["ARM9"],
|
||||
|
||||
"compilerPath": "C:/devkitPro/devkitARM/bin/arm-none-eabi-g++.exe", // for windows
|
||||
"compilerPath": "/opt/devkitPro/devkitARM/bin/arm-none-eabi-g++.exe", // for linux
|
||||
|
||||
"cStandard": "gnu17",
|
||||
"cppStandard": "gnu++14",
|
||||
"intelliSenseMode": "windows-gcc-x64", // for windows
|
||||
"intelliSenseMode": "linux-gcc-x64", // for linux
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
```
|
||||
* delete the line you don't care with comments about your os
|
@ -1,12 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
// Compiling for ARM9
|
||||
|
||||
#undef ARM7
|
||||
#undef ARM9
|
||||
|
||||
#define ARM9
|
||||
|
||||
#include <nds.h>
|
||||
#include <nds/arm9/console.h>
|
||||
#include <c++/12.1.0/vector>
|
||||
|
@ -1,10 +1,3 @@
|
||||
// Compiling for ARM9
|
||||
|
||||
#undef ARM7
|
||||
#undef ARM9
|
||||
|
||||
#define ARM9
|
||||
|
||||
// Devkitpro headers and ARM9 libc++
|
||||
|
||||
#include <nds.h>
|
||||
@ -23,7 +16,7 @@ int main()
|
||||
// initialize video
|
||||
videoSetMode(MODE_0_2D);
|
||||
videoSetModeSub(MODE_0_2D);
|
||||
|
||||
|
||||
// initialize vram
|
||||
vramSetPrimaryBanks(VRAM_A_MAIN_BG, VRAM_B_MAIN_SPRITE, VRAM_C_SUB_BG, VRAM_D_SUB_SPRITE);
|
||||
|
||||
@ -62,6 +55,7 @@ int main()
|
||||
case KEY_A: console.returnPrompt(); break;
|
||||
}
|
||||
|
||||
// printing the prompt
|
||||
console.flushPromptBuffer(frame, true);
|
||||
swiWaitForVBlank();
|
||||
}
|
||||
|
@ -276,4 +276,180 @@ std::string NScript::Parser::escapesToEscaped(std::string s, Position pos)
|
||||
t.push_back(s[i]);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::expectType(Node node, NodeKind type, Position pos)
|
||||
{
|
||||
if (node.kind != type)
|
||||
throw Error({"expected a value with type ", Node::kindToString(type), " (found ", Node::kindToString(node.kind), ")"}, pos);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void NScript::Evaluator::expectArgsCount(CallNode call, uint64_t count)
|
||||
{
|
||||
if (call.args.size() != count)
|
||||
throw Error({"expected args ", std::to_string(count), " (found ", std::to_string(call.args.size()), ")"}, call.name.pos);
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::builtinFloor(CallNode call)
|
||||
{
|
||||
expectArgsCount(call, 1);
|
||||
|
||||
// truncating the float value
|
||||
auto expr = expectType(evaluateNode(call.args[0]), NodeKind::Num, call.args[0].pos);
|
||||
expr.value.num = uint64_t(expr.value.num);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::builtinPrint(CallNode call, Position pos)
|
||||
{
|
||||
// printing all arguments without separation and flushing
|
||||
for (auto arg : call.args)
|
||||
iprintf("%s", arg.toString().c_str());
|
||||
|
||||
fflush(stdout);
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::evaluateCallProcess(CallNode call, Position pos)
|
||||
{
|
||||
panic("evaluateCallProcess not implemented yet");
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::evaluateCall(CallNode call, Position pos)
|
||||
{
|
||||
// when the call's name is a string, searches for a process with that filename
|
||||
if (call.name.kind == NodeKind::String)
|
||||
return evaluateCallProcess(call, pos);
|
||||
|
||||
// otherwise searches for a builtin function with that name
|
||||
auto name = std::string(call.name.value.str);
|
||||
|
||||
if (name == "print")
|
||||
return builtinPrint(call, pos);
|
||||
else if (name == "floor")
|
||||
return builtinFloor(call);
|
||||
else
|
||||
throw Error({"unknown builtin function"}, call.name.pos);
|
||||
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::evaluateAssign(AssignNode assign, Position pos)
|
||||
{
|
||||
auto name = std::string(assign.name.value.str);
|
||||
auto expr = evaluateNode(assign.expr);
|
||||
|
||||
for (uint64_t i = 0; i < map.size(); i++)
|
||||
if (map[i].key == name)
|
||||
{
|
||||
// the variable is already declared (overwrites old value)
|
||||
map[i].val = expr;
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
// the variable is not declared yet (appends a new definition)
|
||||
map.push_back(KeyPair<std::string, Node>(name, expr));
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::evaluateUna(UnaNode una)
|
||||
{
|
||||
auto term = evaluateNode(una.term);
|
||||
|
||||
// unary can only be applied to numbers
|
||||
if (term.kind != NodeKind::Num)
|
||||
throw Error({"type `", Node::kindToString(term.kind), "` does not support unary `", Node::kindToString(una.op.kind), "`"}, term.pos);
|
||||
|
||||
term.value.num *= una.op.kind == NodeKind::Minus ? -1 : +1;
|
||||
return term;
|
||||
}
|
||||
|
||||
cstring_t NScript::Evaluator::evaluateOperationStr(Node op, cstring_t l, cstring_t r)
|
||||
{
|
||||
// string only supports `+` op
|
||||
if (op.kind != NodeKind::Plus)
|
||||
throw Error({"string does not support bin `", Node::kindToString(op.kind), "`"}, op.pos);
|
||||
|
||||
return cstringRealloc((std::string(l) + r).c_str());
|
||||
}
|
||||
|
||||
float64 NScript::Evaluator::evaluateOperationNum(NodeKind op, float64 l, float64 r, Position rPos)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case NodeKind::Plus: return l + r;
|
||||
case NodeKind::Minus: return l - r;
|
||||
case NodeKind::Star: return l * r;
|
||||
case NodeKind::Slash:
|
||||
if (r == 0)
|
||||
throw Error({"dividing by 0"}, rPos);
|
||||
|
||||
return l / r;
|
||||
|
||||
default: panic("unreachable"); return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::evaluateBin(BinNode bin)
|
||||
{
|
||||
auto left = evaluateNode(bin.left);
|
||||
auto right = evaluateNode(bin.right);
|
||||
|
||||
// every bin op can only be applied to values of same type
|
||||
if (left.kind != right.kind)
|
||||
throw Error(
|
||||
{"unkwnon bin `", bin.op.toString(), "` between different types (`", Node::kindToString(left.kind), "` and `", Node::kindToString(right.kind), "`)"},
|
||||
bin.op.pos
|
||||
);
|
||||
|
||||
// recognizing the values' types
|
||||
switch (left.kind)
|
||||
{
|
||||
case NodeKind::Num:
|
||||
left.value.num = evaluateOperationNum(bin.op.kind, left.value.num, right.value.num, right.pos);
|
||||
break;
|
||||
|
||||
case NodeKind::String:
|
||||
left.value.str = evaluateOperationStr(bin.op, left.value.str, right.value.str);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error(
|
||||
{"type `", Node::kindToString(left.kind), "` does not support bin"},
|
||||
bin.op.pos
|
||||
);
|
||||
}
|
||||
|
||||
// the returning value is gonna have the same pos of the entire bin node
|
||||
left.pos.endPos = right.pos.endPos;
|
||||
return left;
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::evaluateIdentifier(Node identifier)
|
||||
{
|
||||
for (const auto& kv : map)
|
||||
if (kv.key == std::string(identifier.value.str))
|
||||
return kv.val;
|
||||
|
||||
throw Error({"unknown variable"}, identifier.pos);
|
||||
}
|
||||
|
||||
NScript::Node NScript::Evaluator::evaluateNode(Node node)
|
||||
{
|
||||
switch (node.kind)
|
||||
{
|
||||
case NodeKind::Num:
|
||||
case NodeKind::String:
|
||||
case NodeKind::None: return node;
|
||||
case NodeKind::Bin: return evaluateBin(*node.value.bin);
|
||||
case NodeKind::Una: return evaluateUna(*node.value.una);
|
||||
case NodeKind::Identifier: return evaluateIdentifier(node);
|
||||
case NodeKind::Assign: return evaluateAssign(*node.value.assign, node.pos);
|
||||
case NodeKind::Call: return evaluateCall(*node.value.call, node.pos);
|
||||
default: panic("unimplemented evaluateNode for some NodeKind"); return Node::none(node.pos);
|
||||
}
|
||||
}
|
179
source/nscript.h
179
source/nscript.h
@ -1,12 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
// Compiling for ARM9
|
||||
|
||||
#undef ARM7
|
||||
#undef ARM9
|
||||
|
||||
#define ARM9
|
||||
|
||||
#include <nds.h>
|
||||
#include <c++/12.1.0/string>
|
||||
#include <c++/12.1.0/vector>
|
||||
@ -405,176 +398,30 @@ namespace NScript
|
||||
this->map = std::vector<KeyPair<std::string, Node>>();
|
||||
}
|
||||
|
||||
public: Node evaluateNode(Node node)
|
||||
{
|
||||
switch (node.kind)
|
||||
{
|
||||
case NodeKind::Num:
|
||||
case NodeKind::String:
|
||||
case NodeKind::None: return node;
|
||||
case NodeKind::Bin: return evaluateBin(*node.value.bin);
|
||||
case NodeKind::Una: return evaluateUna(*node.value.una);
|
||||
case NodeKind::Identifier: return evaluateIdentifier(node);
|
||||
case NodeKind::Assign: return evaluateAssign(*node.value.assign, node.pos);
|
||||
case NodeKind::Call: return evaluateCall(*node.value.call, node.pos);
|
||||
default: panic("unimplemented evaluateNode for some NodeKind"); return Node::none(node.pos);
|
||||
}
|
||||
}
|
||||
public: Node evaluateNode(Node node);
|
||||
|
||||
private: Node evaluateIdentifier(Node identifier)
|
||||
{
|
||||
for (const auto& kv : map)
|
||||
if (kv.key == std::string(identifier.value.str))
|
||||
return kv.val;
|
||||
|
||||
throw Error({"unknown variable"}, identifier.pos);
|
||||
}
|
||||
private: Node evaluateIdentifier(Node identifier);
|
||||
|
||||
private: Node evaluateBin(BinNode bin)
|
||||
{
|
||||
auto left = evaluateNode(bin.left);
|
||||
auto right = evaluateNode(bin.right);
|
||||
private: Node evaluateBin(BinNode bin);
|
||||
|
||||
if (left.kind != right.kind)
|
||||
throw Error(
|
||||
{"unkwnon bin `", bin.op.toString(), "` between different types (`", Node::kindToString(left.kind), "` and `", Node::kindToString(right.kind), "`)"},
|
||||
bin.op.pos
|
||||
);
|
||||
|
||||
switch (left.kind)
|
||||
{
|
||||
case NodeKind::Num:
|
||||
left.value.num = evaluateOperationNum(bin.op.kind, left.value.num, right.value.num, right.pos);
|
||||
break;
|
||||
|
||||
case NodeKind::String:
|
||||
left.value.str = evaluateOperationStr(bin.op, left.value.str, right.value.str);
|
||||
break;
|
||||
private: float64 evaluateOperationNum(NodeKind op, float64 l, float64 r, Position rPos);
|
||||
|
||||
default:
|
||||
throw Error(
|
||||
{"type `", Node::kindToString(left.kind), "` does not support bin"},
|
||||
bin.op.pos
|
||||
);
|
||||
}
|
||||
private: cstring_t evaluateOperationStr(Node op, cstring_t l, cstring_t r);
|
||||
|
||||
left.pos.endPos = right.pos.endPos;
|
||||
return left;
|
||||
}
|
||||
private: Node evaluateUna(UnaNode una);
|
||||
|
||||
private: float64 evaluateOperationNum(NodeKind op, float64 l, float64 r, Position rPos)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
case NodeKind::Plus: return l + r;
|
||||
case NodeKind::Minus: return l - r;
|
||||
case NodeKind::Star: return l * r;
|
||||
case NodeKind::Slash:
|
||||
if (r == 0)
|
||||
throw Error({"dividing by 0"}, rPos);
|
||||
private: Node evaluateAssign(AssignNode assign, Position pos);
|
||||
|
||||
return l / r;
|
||||
|
||||
default: panic("unreachable"); return 0;
|
||||
}
|
||||
}
|
||||
private: Node evaluateCall(CallNode call, Position pos);
|
||||
|
||||
private: cstring_t evaluateOperationStr(Node op, cstring_t l, cstring_t r)
|
||||
{
|
||||
if (op.kind != NodeKind::Plus)
|
||||
throw Error({"string does not support bin `", Node::kindToString(op.kind), "`"}, op.pos);
|
||||
private: Node evaluateCallProcess(CallNode call, Position pos);
|
||||
|
||||
return cstringRealloc((std::string(l) + r).c_str());
|
||||
}
|
||||
private: Node builtinPrint(CallNode call, Position pos);
|
||||
|
||||
private: Node evaluateUna(UnaNode una)
|
||||
{
|
||||
auto term = evaluateNode(una.term);
|
||||
private: Node builtinFloor(CallNode call);
|
||||
|
||||
if (term.kind != NodeKind::Num)
|
||||
throw Error({"type `", Node::kindToString(term.kind), "` does not support unary `", Node::kindToString(una.op.kind), "`"}, term.pos);
|
||||
|
||||
term.value.num *= una.op.kind == NodeKind::Minus ? -1 : +1;
|
||||
return term;
|
||||
}
|
||||
private: void expectArgsCount(CallNode call, uint64_t count);
|
||||
|
||||
private: Node evaluateAssign(AssignNode assign, Position pos)
|
||||
{
|
||||
auto name = std::string(assign.name.value.str);
|
||||
auto expr = evaluateNode(assign.expr);
|
||||
|
||||
for (uint64_t i = 0; i < map.size(); i++)
|
||||
if (map[i].key == name)
|
||||
{
|
||||
// the variable is already declared (overwrites old value)
|
||||
map[i].val = expr;
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
// the variable is not declared yet (appends a new definition)
|
||||
map.push_back(KeyPair<std::string, Node>(name, expr));
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
private: Node evaluateCall(CallNode call, Position pos)
|
||||
{
|
||||
// when the call's name is a string, searches for a process with that filename
|
||||
if (call.name.kind == NodeKind::String)
|
||||
return evaluateCallProcess(call, pos);
|
||||
|
||||
// otherwise searches for a builtin function with that name
|
||||
|
||||
auto name = std::string(call.name.value.str);
|
||||
|
||||
if (name == "print")
|
||||
return builtinPrint(call, pos);
|
||||
else if (name == "floor")
|
||||
return builtinFloor(call);
|
||||
else
|
||||
throw Error({"unknown builtin function"}, call.name.pos);
|
||||
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
private: Node evaluateCallProcess(CallNode call, Position pos)
|
||||
{
|
||||
panic("evaluateCallProcess not implemented yet");
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
private: Node builtinPrint(CallNode call, Position pos)
|
||||
{
|
||||
// printing all arguments without separation and flushing
|
||||
for (auto arg : call.args)
|
||||
iprintf("%s", arg.toString().c_str());
|
||||
|
||||
fflush(stdout);
|
||||
return Node::none(pos);
|
||||
}
|
||||
|
||||
private: Node builtinFloor(CallNode call)
|
||||
{
|
||||
expectArgsCount(call, 1);
|
||||
|
||||
// truncating the float value
|
||||
auto expr = expectType(evaluateNode(call.args[0]), NodeKind::Num, call.args[0].pos);
|
||||
expr.value.num = uint64_t(expr.value.num);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
private: void expectArgsCount(CallNode call, uint64_t count)
|
||||
{
|
||||
if (call.args.size() != count)
|
||||
throw Error({"expected args ", std::to_string(count), " (found ", std::to_string(call.args.size()), ")"}, call.name.pos);
|
||||
}
|
||||
|
||||
private: Node expectType(Node node, NodeKind type, Position pos)
|
||||
{
|
||||
if (node.kind != type)
|
||||
throw Error({"expected a value with type ", Node::kindToString(type), " (found ", Node::kindToString(node.kind), ")"}, pos);
|
||||
|
||||
return node;
|
||||
}
|
||||
private: Node expectType(Node node, NodeKind type, Position pos);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user