Skip to content

Commit

Permalink
add unions
Browse files Browse the repository at this point in the history
  • Loading branch information
MESYETI committed May 1, 2024
1 parent 6364b10 commit 0d3c681
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 2 deletions.
17 changes: 17 additions & 0 deletions examples/unions.cal
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
include "cores/select.cal"
include "std/io.cal"

union MyUnion
cell
Array
end

"MyUnion.sizeof = " printlstr MyUnion.sizeof printdec new_line

let MyUnion foo

65 foo !
foo @ printdec new_line

"Hello, world!\n" foo a<
foo printstr
14 changes: 14 additions & 0 deletions source/app.d
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Flags:
executable file (set by default)
-na - Disables the -a flag
--version - Shows the callisto version
-dp - Prints parser output
Backends:
rm86 - Real mode x86 and MS-DOS
Expand All @@ -52,6 +53,7 @@ int main(string[] args) {
bool runFinal = true;
CompilerBackend backend = new BackendLinux86();
bool doDebug;
bool debugParser;

for (size_t i = 1; i < args.length; ++ i) {
if (args[i][0] == '-') {
Expand Down Expand Up @@ -152,6 +154,10 @@ int main(string[] args) {
doDebug = true;
break;
}
case "-dp": {
debugParser = true;
break;
}
default: {
stderr.writefln("Unknown flag '%s'", args[i]);
return 1;
Expand All @@ -176,6 +182,14 @@ int main(string[] args) {
string[] included;
auto nodes = ParseFile(file);

if (debugParser) {
foreach (ref node ; nodes) {
writeln(node);
}

return 0;
}

auto compiler = new Compiler();
compiler.backend = backend;
compiler.backend.org = org;
Expand Down
28 changes: 28 additions & 0 deletions source/backends/linux86.d
Original file line number Diff line number Diff line change
Expand Up @@ -608,4 +608,32 @@ class BackendLinux86 : CompilerBackend {

output ~= format("jmp __while_%d_condition\n", currentLoop);
}

override void CompileUnion(UnionNode node) {
size_t maxSize = 0;

if (node.name in types) {
Error(node.error, "Type '%s' already exists", node.name);
}

string[] unionTypes;

foreach (ref type ; node.types) {
if (unionTypes.canFind(type)) {
Error(node.error, "Union type '%s' defined twice", type);
}
unionTypes ~= type;

if (type !in types) {
Error(node.error, "Type '%s' doesn't exist", type);
}

if (types[type].size > maxSize) {
maxSize = types[type].size;
}
}

types[node.name] = Type(maxSize);
NewConst(format("%s.sizeof", node.name), cast(long) maxSize);
}
}
28 changes: 28 additions & 0 deletions source/backends/rm86.d
Original file line number Diff line number Diff line change
Expand Up @@ -569,4 +569,32 @@ class BackendRM86 : CompilerBackend {

output ~= format("jmp __while_%d_condition\n", currentLoop);
}

override void CompileUnion(UnionNode node) {
size_t maxSize = 0;

if (node.name in types) {
Error(node.error, "Type '%s' already exists", node.name);
}

string[] unionTypes;

foreach (ref type ; node.types) {
if (unionTypes.canFind(type)) {
Error(node.error, "Union type '%s' defined twice", type);
}
unionTypes ~= type;

if (type !in types) {
Error(node.error, "Type '%s' doesn't exist", type);
}

if (types[type].size > maxSize) {
maxSize = types[type].size;
}
}

types[node.name] = Type(maxSize);
NewConst(format("%s.sizeof", node.name), cast(long) maxSize);
}
}
5 changes: 4 additions & 1 deletion source/compiler.d
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class CompilerBackend {
abstract void CompileEnum(EnumNode node);
abstract void CompileBreak(WordNode node);
abstract void CompileContinue(WordNode node);
abstract void CompileUnion(UnionNode node);

final void Error(Char, A...)(ErrorInfo error, in Char[] fmt, A args) {
ErrorBegin(error);
Expand Down Expand Up @@ -157,6 +158,7 @@ class Compiler {
case NodeType.Struct: backend.CompileStruct(cast(StructNode) inode); break;
case NodeType.Const: backend.CompileConst(cast(ConstNode) inode); break;
case NodeType.Enum: backend.CompileEnum(cast(EnumNode) inode); break;
case NodeType.Union: backend.CompileUnion(cast(UnionNode) inode); break;
default: {
backend.Error(inode.error, "Unimplemented node '%s'", inode.type);
}
Expand All @@ -181,7 +183,8 @@ class Compiler {
case NodeType.Requires:
case NodeType.Struct:
case NodeType.Const:
case NodeType.Enum: {
case NodeType.Enum:
case NodeType.Union: {
header ~= node;
break;
}
Expand Down
47 changes: 46 additions & 1 deletion source/parser.d
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ enum NodeType {
Struct,
Const,
Enum,
Restrict
Restrict,
Union
}

class Node {
Expand Down Expand Up @@ -361,6 +362,26 @@ class RestrictNode : Node {
override string toString() => format("restrict %s", ver);
}

class UnionNode : Node {
string name;
string[] types;

this(ErrorInfo perror) {
type = NodeType.Union;
error = perror;
}

override string toString() {
auto ret = format("union %s\n", name);

foreach (ref type ; types) {
ret ~= format(" %s\n", type);
}

return ret ~ "end";
}
}

class ParserError : Exception {
this() {
super("", "", 0);
Expand Down Expand Up @@ -838,6 +859,29 @@ class Parser {
return ret;
}

Node ParseUnion() {
auto ret = new UnionNode(GetError());
parsing = NodeType.Union;

Next();
Expect(TokenType.Identifier);
ret.name = tokens[i].contents;
Next();
Expect(TokenType.Identifier);

while (true) {
if ((tokens[i].type == TokenType.Identifier) && (tokens[i].contents == "end")) {
break;
}

ret.types ~= tokens[i].contents;
Next();
Expect(TokenType.Identifier);
}

return ret;
}

Node ParseStatement() {
switch (tokens[i].type) {
case TokenType.Integer: {
Expand All @@ -859,6 +903,7 @@ class Parser {
case "const": return ParseConst();
case "enum": return ParseEnum();
case "restrict": return ParseRestrict();
case "union": return ParseUnion();
default: return new WordNode(GetError(), tokens[i].contents);
}
}
Expand Down

0 comments on commit 0d3c681

Please sign in to comment.