-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compile Trilangle to C #26
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
dced08a
Compiler rough draft
bbrk24 09af84c
Improve linting and testing
bbrk24 0d7bea0
fix some things
bbrk24 2243f9a
derp
bbrk24 d7fc9ae
uh
bbrk24 d722bca
documentation
bbrk24 564b81e
more refactors
bbrk24 c32cab2
improve disassembler::to_str
bbrk24 fe25bce
fix formatting
bbrk24 91eecb1
add compiler to changelog
bbrk24 5a05d31
Add UTF-8 parsing to compiled code
bbrk24 7a4953e
how did I forget that
bbrk24 5836185
C is not C++
bbrk24 165d8b2
Add test for -a
bbrk24 241d1ee
Well.
bbrk24 3356dc7
Change up CLI/compiler tests
bbrk24 e5303d1
Apparently stdin doesn't work like that
bbrk24 995994c
forgot to update the windows script
bbrk24 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,3 +20,4 @@ wasm/*.css | |
*.obj | ||
trilangle | ||
*.nativecodeanalysis.xml | ||
out.c |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
// This file is not in the compiler folder because the MSVC build script requires this folder to contain all the .cpp | ||
// files. | ||
#include "compiler.hh" | ||
#include <iostream> | ||
#include "compiler/strings.hh" | ||
|
||
using std::cerr; | ||
using std::endl; | ||
|
||
void compiler::write_state(std::ostream& os) { | ||
if (m_fragments == nullptr) { | ||
build_state(); | ||
} | ||
|
||
os << header; | ||
|
||
for (size_t i = 0; i < m_fragments->size(); ++i) { | ||
const std::vector<instruction>& frag = *m_fragments->at(i); | ||
for (size_t j = 0; j < frag.size(); ++j) { | ||
os << "\nlbl" << i << '_' << j << ": "; | ||
get_c_code(frag[j], os, m_flags.assume_ascii); | ||
} | ||
} | ||
|
||
os << footer << std::flush; | ||
} | ||
|
||
void compiler::get_c_code(const instruction& i, std::ostream& os, bool assume_ascii) { | ||
using op = instruction::operation; | ||
|
||
switch (i.m_op) { | ||
case op::BNG: { | ||
os << "if (lws_top(stack) < 0) goto lbl"; | ||
const auto& choice = i.m_arg.choice; | ||
const auto &dest1 = choice.first, &dest2 = choice.second; | ||
os << dest2.first << '_' << dest2.second << "; goto lbl" << dest1.first << '_' << dest1.second << ';'; | ||
return; | ||
} | ||
case op::JMP: { | ||
os << "goto lbl"; | ||
const auto& dest = i.m_arg.next; | ||
os << dest.first << '_' << dest.second << ';'; | ||
return; | ||
} | ||
case op::TKL: | ||
case op::EXT: | ||
os << "lws_deinit(stack); return 0;"; | ||
return; | ||
case op::TJN: | ||
case op::TSP: | ||
cerr << "Threading is not supported for compiled programs." << endl; | ||
exit(EXIT_FAILURE); | ||
case op::NOP: | ||
break; | ||
case op::ADD: | ||
os << "lws_push(stack, lws_pop(stack) + lws_pop(stack));"; | ||
return; | ||
case op::SUB: | ||
// The calls need to be well-ordered | ||
os << "{ int32_t tmp = lws_pop(stack); lws_push(stack, lws_pop(stack) - tmp); }"; | ||
return; | ||
case op::MUL: | ||
os << "lws_push(stack, lws_pop(stack) * lws_pop(stack));"; | ||
return; | ||
case op::DIV: | ||
os << "{ int32_t tmp = lws_pop(stack); lws_push(stack, lws_pop(stack) / tmp); }"; | ||
return; | ||
case op::MOD: | ||
os << "{ int32_t tmp = lws_pop(stack); lws_push(stack, lws_pop(stack) % tmp); }"; | ||
return; | ||
case op::PSC: { | ||
os << "lws_push(stack,"; | ||
const auto value = i.m_arg.number; | ||
os << static_cast<int32_t>(value) << ");"; | ||
return; | ||
} | ||
case op::PSI: { | ||
os << "lws_push(stack,"; | ||
const auto value = i.m_arg.number; | ||
os << static_cast<int32_t>(value - (int24_t)'0') << ");"; | ||
return; | ||
} | ||
case op::POP: | ||
os << "(void)lws_pop(stack);"; | ||
return; | ||
case op::INC: | ||
os << "lws_push(stack, (lws_pop(stack) + 1) << 8 >> 8);"; | ||
return; | ||
case op::DEC: | ||
os << "lws_push(stack, (lws_pop(stack) - 1) << 8 >> 8);"; | ||
return; | ||
case op::AND: | ||
os << "lws_push(stack, lws_pop(stack) & lws_pop(stack));"; | ||
return; | ||
case op::IOR: | ||
os << "lws_push(stack, lws_pop(stack) | lws_pop(stack));"; | ||
return; | ||
case op::XOR: | ||
os << "lws_push(stack, lws_pop(stack) ^ lws_pop(stack));"; | ||
return; | ||
case op::NOT: | ||
os << "lws_push(stack, ~lws_pop(stack));"; | ||
return; | ||
case op::GTC: | ||
if (assume_ascii) { | ||
os << "{ int temp = getchar(); lws_push(stack, temp == EOF ? -1 : temp); }"; | ||
} else { | ||
os << "lws_push(stack, get_unichar());"; | ||
} | ||
return; | ||
case op::PTC: | ||
if (assume_ascii) { | ||
os << "putchar"; | ||
} else { | ||
os << "print_unichar"; | ||
} | ||
os << "(lws_top(stack));"; | ||
return; | ||
case op::GTI: | ||
os << "{" | ||
"int32_t i = -1;" | ||
"while (!(feof(stdin) || scanf(\"%\" SCNi32, &i))) (void)getchar();" | ||
"lws_push(stack, i);" | ||
"}"; | ||
return; | ||
case op::PTI: | ||
os << R"( printf("%" PRId32 "\n", lws_top(stack)); )"; | ||
return; | ||
case op::IDX: | ||
os << "lws_push(stack, lws_index(stack, lws_pop(stack)));"; | ||
return; | ||
case op::DUP: | ||
os << "lws_push(stack, lws_top(stack));"; | ||
return; | ||
case op::DP2: { | ||
const char* str = "lws_push(stack, lws_index(stack, 1));"; | ||
os << str << str; | ||
return; | ||
} | ||
case op::RND: | ||
case op::GDT: | ||
case op::GTM: | ||
cerr << "Nondeterministic instructions are not yet supported for compiled programs." << endl; | ||
exit(EXIT_FAILURE); | ||
case op::EXP: | ||
os << "lws_push(stack, 1 << lws_pop(stack));"; | ||
return; | ||
case op::SWP: | ||
os << "{" | ||
"int32_t temp1 = lws_pop(stack);" | ||
"int32_t temp2 = lws_pop(stack);" | ||
"lws_push(stack, temp1);" | ||
"lws_push(stack, temp2);" | ||
"}"; | ||
return; | ||
default: | ||
cerr << "Unknown opcode." << endl; | ||
exit(EXIT_FAILURE); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#pragma once | ||
|
||
#include "instruction_scanner.hh" | ||
|
||
class compiler : public instruction_scanner { | ||
public: | ||
CONSTEXPR_VECTOR compiler(NONNULL_PTR(const program) p, flags f) : instruction_scanner(p), m_flags(f) {} | ||
void write_state(std::ostream& os); | ||
private: | ||
flags m_flags; | ||
static void get_c_code(const instruction& i, std::ostream& os, bool assume_ascii); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
// This entire file is a string. Comment out the opening quote marker to get syntax highlighting while editing. | ||
R"( | ||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <stdint.h> | ||
|
||
#ifndef __GNUC__ | ||
#define __builtin_expect(exp, c) exp | ||
#endif | ||
|
||
struct lightweight_stack_s { | ||
int32_t* base; | ||
size_t length; | ||
size_t capacity; | ||
}; | ||
|
||
typedef struct lightweight_stack_s* lws; | ||
|
||
static inline int32_t lws_pop(lws stack) { | ||
return stack->base[--stack->length]; | ||
} | ||
|
||
static inline int lws_push(lws stack, int32_t value) { | ||
if (__builtin_expect(stack->length == stack->capacity, 0L)) { | ||
bbrk24 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
size_t new_cap = stack->capacity * 7 / 4; | ||
int32_t* new_ptr = (int32_t*)realloc(stack->base, new_cap * sizeof(int32_t)); | ||
if (new_ptr == NULL) { | ||
return 0; | ||
} | ||
stack->base = new_ptr; | ||
stack->capacity = new_cap; | ||
} | ||
stack->base[stack->length++] = value; | ||
return 1; | ||
} | ||
|
||
static inline int32_t lws_index(const lws stack, int32_t index) { | ||
return stack->base[stack->length - index - 1]; | ||
} | ||
|
||
static inline int32_t lws_top(const lws stack) { | ||
return lws_index(stack, 0); | ||
} | ||
|
||
static inline void lws_init(lws stack) { | ||
stack->length = 0; | ||
stack->base = (int32_t*)calloc(4, sizeof(int32_t)); | ||
// Note: actually handling errors prevents the compiler from doing optimizations we want | ||
stack->capacity = 4; | ||
} | ||
|
||
static inline void lws_deinit(const lws stack) { | ||
free(stack->base); | ||
} | ||
|
||
#define INVALID_CHAR 0xfffd | ||
// Basically copied from parse_unichar in string_processing.hh | ||
static inline int32_t get_unichar() { | ||
unsigned char buf[4]; | ||
size_t buf_max = 4; | ||
for (size_t i = 0; i < buf_max; ++i) { | ||
int c = getchar(); | ||
if (c == EOF) { | ||
if (i == 0) { | ||
return -1; | ||
} else { | ||
return INVALID_CHAR; | ||
} | ||
} | ||
buf[i] = c; | ||
if (i != 0 && (buf[i] & 0xc0) != 0x80) { | ||
return INVALID_CHAR; | ||
} | ||
if (i == 0) { | ||
if (buf[0] < 0x80) { | ||
return buf[0]; | ||
} else if ((buf[0] & 0xe0) == 0xc0) { | ||
buf_max = 2; | ||
} else if ((buf[0] & 0xf0) == 0xe0) { | ||
buf_max = 3; | ||
} else if ((buf[0] & 0xf8) != 0xf0) { | ||
return INVALID_CHAR; | ||
} | ||
} | ||
} | ||
switch (buf_max) { | ||
case 2: | ||
return ((buf[0] & 0x1f) << 6) | (buf[1] & 0x3f); | ||
case 3: | ||
return ((buf[0] & 0x0f) << 12) | ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f); | ||
case 4: | ||
return ((buf[0] & 0x07) << 18) | ((buf[1] & 0x3f) << 12) | ((buf[2] & 0x3f) << 6) | (buf[3] & 0x3f); | ||
} | ||
} | ||
|
||
static inline void print_unichar(int32_t c) { | ||
if (c <= 0x7f) { | ||
putchar(c); | ||
} else if (c <= 0x07ff) { | ||
char buffer[] = { 0xc0 | (c >> 6), 0x80 | (c & 0x3f), 0 }; | ||
printf(buffer); | ||
} else if (c <= 0xffff) { | ||
char buffer[] = { 0xe0 | (c >> 12), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f), 0 }; | ||
printf(buffer); | ||
} else { | ||
char buffer[] = { 0xf0 | (c >> 18), 0x80 | ((c >> 12) & 0x3f), 0x80 | ((c >> 6) & 0x3f), 0x80 | (c & 0x3f), 0 }; | ||
printf(buffer); | ||
} | ||
} | ||
//)" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#pragma once | ||
|
||
constexpr const char* header = | ||
"#include <inttypes.h>" | ||
#include "lightweight_stack.h" | ||
R"#( | ||
int main(int argc, const char** argv) { | ||
struct lightweight_stack_s stack_storage; | ||
lws stack = &stack_storage; | ||
lws_init(stack);)#"; | ||
|
||
constexpr const char* footer = "}\n"; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be doable with
time()
andrand()
, but seeding the RNG is a problemThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
time()
doesn't provide sub-second precision however, so it might work forGDT
but notGTM
.