first commit
This commit is contained in:
commit
0fd66745c8
27 changed files with 735 additions and 0 deletions
BIN
.cache/clangd/index/codegen.h.B28082C1C1D042BA.idx
Normal file
BIN
.cache/clangd/index/codegen.h.B28082C1C1D042BA.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/compiler.h.D712E1B2AB94B380.idx
Normal file
BIN
.cache/clangd/index/compiler.h.D712E1B2AB94B380.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/helpers.h.F9575AB77341F585.idx
Normal file
BIN
.cache/clangd/index/helpers.h.F9575AB77341F585.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/lexer.h.4F141419C0AC5007.idx
Normal file
BIN
.cache/clangd/index/lexer.h.4F141419C0AC5007.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/main.c.2393E5B60B02EEC0.idx
Normal file
BIN
.cache/clangd/index/main.c.2393E5B60B02EEC0.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/node.h.714EF12F6C2AA1A8.idx
Normal file
BIN
.cache/clangd/index/node.h.714EF12F6C2AA1A8.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/parser.h.AB8FD292E884B1D7.idx
Normal file
BIN
.cache/clangd/index/parser.h.AB8FD292E884B1D7.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/regex_helpers.h.468BB76668FECF71.idx
Normal file
BIN
.cache/clangd/index/regex_helpers.h.468BB76668FECF71.idx
Normal file
Binary file not shown.
BIN
.cache/clangd/index/token.h.06BA855CD31E4C24.idx
Normal file
BIN
.cache/clangd/index/token.h.06BA855CD31E4C24.idx
Normal file
Binary file not shown.
25
.clang-format
Normal file
25
.clang-format
Normal file
|
@ -0,0 +1,25 @@
|
|||
BasedOnStyle: WebKit
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignTrailingComments: true
|
||||
ColumnLimit: 105
|
||||
BreakBeforeBraces: Attach
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AllowShortLambdasOnASingleLine: false
|
||||
PointerAlignment: Left
|
||||
SpaceBeforeParens: Never
|
||||
SpacesInParentheses: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
PenaltyBreakAssignment: 1000
|
||||
NamespaceIndentation: All
|
||||
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
# Xmake cache
|
||||
.xmake/
|
||||
build/
|
||||
|
||||
# MacOS Cache
|
||||
.DS_Store
|
||||
|
||||
|
6
compile_commands.json
Normal file
6
compile_commands.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
[
|
||||
{
|
||||
"directory": "/home/sam/Documents/Projects/compiler-c",
|
||||
"arguments": ["/usr/bin/gcc", "-c", "-fvisibility=hidden", "-O3", "-I", "/home/sam/.xmake/packages/s/stc/v4.2/bfec6d3335d54b48969cc50946a9b5ac/include", "-DNDEBUG", "-o", "build/.objs/compiler-c/linux/arm64/release/src/main.c.o", "src/main.c"],
|
||||
"file": "src/main.c"
|
||||
}]
|
87
src/codegen.c
Normal file
87
src/codegen.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
#include "codegen.h"
|
||||
#include "helpers.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void codegen(Node node) {
|
||||
switch(node.type) {
|
||||
case NODE_FUNCTION_CALL:
|
||||
codegen_function_call(node);
|
||||
break;
|
||||
case NODE_FUNCTION_DECL:
|
||||
codegen_function_decl(node);
|
||||
break;
|
||||
case NODE_FUNCTION_IMPL:
|
||||
codegen_function_impl(node);
|
||||
break;
|
||||
case NODE_ARG_DECL:
|
||||
codegen_arg_decl(node);
|
||||
break;
|
||||
case NODE_NUMBER:
|
||||
codegen_number(node);
|
||||
break;
|
||||
default:
|
||||
syntax_error("unexpected node %c", node.type);
|
||||
}
|
||||
}
|
||||
|
||||
void codegen_function_call(Node node) {
|
||||
printf("FunctionCall(%s", node.function_call.name);
|
||||
if(Nodes_size(&node.function_call.args) > 0)
|
||||
printf(", ");
|
||||
for(size_t i = 0; i < Nodes_size(&node.function_call.args); i++) {
|
||||
const Node* arg = Nodes_at(&node.function_call.args, i);
|
||||
codegen(*arg);
|
||||
|
||||
if(arg != Nodes_back(&node.function_call.args)) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf(")\n");
|
||||
}
|
||||
|
||||
void codegen_function_decl(Node node) {
|
||||
printf("FunctionDecl(%s, %s, ", node.function_decl.type, node.function_decl.name);
|
||||
for(size_t i = 0; i < Nodes_size(&node.function_decl.args); i++) {
|
||||
const Node* arg = Nodes_at(&node.function_decl.args, i);
|
||||
codegen(*arg);
|
||||
|
||||
if(arg != Nodes_back(&node.function_decl.args)) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf(")\n");
|
||||
}
|
||||
|
||||
void codegen_function_impl(Node node) {
|
||||
printf("FunctionImpl(%s, %s", node.function_impl.type, node.function_impl.name);
|
||||
if(Nodes_size(&node.function_impl.args) > 0)
|
||||
printf(", ");
|
||||
for(size_t i = 0; i < Nodes_size(&node.function_impl.args); i++) {
|
||||
const Node* arg = Nodes_at(&node.function_impl.args, i);
|
||||
codegen(*arg);
|
||||
|
||||
if(arg != Nodes_back(&node.function_impl.args)) {
|
||||
printf(", ");
|
||||
}
|
||||
}
|
||||
printf(") {\n\t");
|
||||
|
||||
for(size_t i = 0; i < Nodes_size(&node.function_impl.body); i++) {
|
||||
const Node* n = Nodes_at(&node.function_impl.body, i);
|
||||
codegen(*n);
|
||||
|
||||
if(n != Nodes_back(&node.function_impl.body)) {
|
||||
printf("\t");
|
||||
}
|
||||
}
|
||||
|
||||
printf("}\n");
|
||||
}
|
||||
|
||||
void codegen_arg_decl(Node node) {
|
||||
printf("ArgDecl(%s, %s)", node.arg_decl.type, node.arg_decl.name);
|
||||
}
|
||||
|
||||
void codegen_number(Node node) {
|
||||
printf("Number(%llu)", node.number.value);
|
||||
}
|
13
src/codegen.h
Normal file
13
src/codegen.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#ifndef CODEGEN_H
|
||||
#define CODEGEN_H
|
||||
|
||||
#include "node.h"
|
||||
|
||||
void codegen(Node node);
|
||||
void codegen_function_call(Node node);
|
||||
void codegen_function_decl(Node node);
|
||||
void codegen_arg_decl(Node node);
|
||||
void codegen_function_impl(Node node);
|
||||
void codegen_number(Node node);
|
||||
|
||||
#endif
|
21
src/compiler.c
Normal file
21
src/compiler.c
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "compiler.h"
|
||||
|
||||
bool next(Compiler* compiler, Token* token) {
|
||||
if(!lexer_next(compiler->lexer, token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch(token->type) {
|
||||
case TOKEN_WHITESPACE:
|
||||
return next(compiler, token);
|
||||
case TOKEN_IDENTIFIER:
|
||||
if(cmap_str_contains(&compiler->types, token->value)) {
|
||||
token->type = TOKEN_TYPEIDENTIFIER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
printf("tok: %c, val: %s\n", token->type, token->value);
|
||||
|
||||
return true;
|
||||
}
|
39
src/compiler.h
Normal file
39
src/compiler.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
#ifndef COMPILER_H
|
||||
#define COMPILER_H
|
||||
|
||||
#include "lexer.h"
|
||||
|
||||
typedef enum {
|
||||
TOKEN_IDENTIFIER = 'I',
|
||||
TOKEN_STRING = 'S',
|
||||
TOKEN_NUMBER = 'N',
|
||||
TOKEN_TYPEIDENTIFIER = 'T',
|
||||
TOKEN_WHITESPACE = 'W',
|
||||
TOKEN_OPAREN = '(',
|
||||
TOKEN_CPAREN = ')',
|
||||
TOKEN_OBRACE = '{',
|
||||
TOKEN_CBRACE = '}',
|
||||
TOKEN_SEMICOLON = ';',
|
||||
TOKEN_COMMA = ','
|
||||
} TokenType;
|
||||
|
||||
#include <stc/ccommon.h>
|
||||
#include <stc/cstr.h>
|
||||
|
||||
#define i_key_str
|
||||
#define i_val_str
|
||||
#include <stc/cmap.h>
|
||||
|
||||
#define i_type Tokens
|
||||
#define i_val Token
|
||||
#define i_opt c_no_cmp
|
||||
#include <stc/cvec.h>
|
||||
|
||||
typedef struct {
|
||||
Lexer* lexer;
|
||||
cmap_str types;
|
||||
} Compiler;
|
||||
|
||||
bool next(Compiler* compiler, Token* token);
|
||||
|
||||
#endif
|
44
src/helpers.c
Normal file
44
src/helpers.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
#include "helpers.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void regex_error(const regex_t* regex, int status) {
|
||||
if(status > REG_NOMATCH) {
|
||||
char error_msg[100];
|
||||
regerror(status, regex, error_msg, sizeof(error_msg));
|
||||
fprintf(stderr, "Regex compilation failed: %s\n", error_msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
regex_t regex(const char* pattern) {
|
||||
regex_t regex;
|
||||
regex_error(®ex, regcomp(®ex, pattern, REG_EXTENDED));
|
||||
|
||||
return regex;
|
||||
}
|
||||
|
||||
bool regex_search(regmatch_t* match, const regex_t* regex, const char* string) {
|
||||
int status = regexec(regex, string, 1, match, 0);
|
||||
regex_error(regex, status);
|
||||
|
||||
return !status;
|
||||
}
|
||||
|
||||
const char* read_file(const char* filename) {
|
||||
FILE* file = fopen(filename, "r");
|
||||
if(file == NULL) {
|
||||
perror("Failed to open file");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
char* buffer = malloc(size + 1);
|
||||
fread(buffer, size, 1, file);
|
||||
fclose(file);
|
||||
|
||||
return buffer;
|
||||
}
|
20
src/helpers.h
Normal file
20
src/helpers.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef HELPERS_H
|
||||
#define HELPERS_H
|
||||
|
||||
#include <regex.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define syntax_error(...) \
|
||||
{ \
|
||||
fprintf(stderr, "Syntax error: " __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
exit(EXIT_FAILURE); \
|
||||
}
|
||||
|
||||
void regex_error(const regex_t* regex, int status);
|
||||
regex_t regex(const char* pattern);
|
||||
bool regex_search(regmatch_t* match, const regex_t* regex, const char* string);
|
||||
|
||||
const char* read_file(const char* filename);
|
||||
|
||||
#endif
|
51
src/lexer.c
Normal file
51
src/lexer.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "lexer.h"
|
||||
#include "helpers.h"
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
Lexer lexer_create(const TokenRule* rules, size_t num_rules) {
|
||||
return (Lexer){
|
||||
.text = NULL,
|
||||
.offset = 0,
|
||||
.rules = rules,
|
||||
.num_rules = num_rules,
|
||||
};
|
||||
}
|
||||
|
||||
void lexer_feed(Lexer* lexer, const char* text) {
|
||||
assert(lexer != NULL);
|
||||
lexer->text = text;
|
||||
}
|
||||
|
||||
bool lexer_next(Lexer* lexer, Token* token) {
|
||||
assert(lexer != NULL);
|
||||
assert(lexer->text != NULL);
|
||||
|
||||
if(lexer->offset >= strlen(lexer->text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
regmatch_t match;
|
||||
for(int i = 0; i < lexer->num_rules; i++) {
|
||||
TokenRule rule = lexer->rules[i];
|
||||
|
||||
if(regex_search(&match, &rule.regex, lexer->text + lexer->offset)) {
|
||||
int length = match.rm_eo;
|
||||
|
||||
char* slice = malloc(length);
|
||||
strncpy(slice, lexer->text + lexer->offset, length);
|
||||
slice[length] = '\0';
|
||||
|
||||
lexer->offset += length;
|
||||
|
||||
token->type = rule.token_type;
|
||||
token->value = slice;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "Unrecognized character: %c\n", *(lexer->text + lexer->offset));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
24
src/lexer.h
Normal file
24
src/lexer.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef LEXER_H
|
||||
#define LEXER_H
|
||||
|
||||
#include "token.h"
|
||||
#include <regex.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct {
|
||||
regex_t regex;
|
||||
int token_type;
|
||||
} TokenRule;
|
||||
|
||||
typedef struct {
|
||||
int offset;
|
||||
const char* text;
|
||||
const TokenRule* rules;
|
||||
size_t num_rules;
|
||||
} Lexer;
|
||||
|
||||
Lexer lexer_create(const TokenRule* rules, size_t num_rules);
|
||||
void lexer_feed(Lexer* lexer, const char* text);
|
||||
bool lexer_next(Lexer* lexer, Token* token);
|
||||
|
||||
#endif
|
51
src/main.c
Normal file
51
src/main.c
Normal file
|
@ -0,0 +1,51 @@
|
|||
#include "codegen.h"
|
||||
#include "compiler.h"
|
||||
#include "helpers.h"
|
||||
#include "lexer.h"
|
||||
#include "node.h"
|
||||
#include "parser.h"
|
||||
#include "token.h"
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
assert(argc > 1);
|
||||
const char* text = read_file(argv[1]);
|
||||
|
||||
TokenRule rules[] = {
|
||||
{ regex("^[A-Za-z][A-Za-z0-9]*"), TOKEN_IDENTIFIER },
|
||||
{ regex("^[ \r\n]+"), TOKEN_WHITESPACE },
|
||||
{ regex("^\".*?\""), TOKEN_STRING },
|
||||
{ regex("^[0-9]+"), TOKEN_NUMBER },
|
||||
{ regex("^;"), TOKEN_SEMICOLON },
|
||||
{ regex("^\\("), TOKEN_OPAREN },
|
||||
{ regex("^\\{"), TOKEN_OBRACE },
|
||||
{ regex("^\\)"), TOKEN_CPAREN },
|
||||
{ regex("^\\}"), TOKEN_CBRACE },
|
||||
};
|
||||
|
||||
Lexer lexer = lexer_create(rules, c_arraylen(rules));
|
||||
lexer_feed(&lexer, text);
|
||||
|
||||
Compiler compiler = {
|
||||
.lexer = &lexer,
|
||||
.types = c_make(cmap_str,
|
||||
{
|
||||
{ "i8", "b" },
|
||||
{ "i16", "h" },
|
||||
{ "i32", "w" },
|
||||
{ "i64", "l" },
|
||||
{ "void", "" },
|
||||
}),
|
||||
};
|
||||
|
||||
Token token;
|
||||
while(next(&compiler, &token)) {
|
||||
// printf("%c: %s\n", token.type, token.value);
|
||||
Node node = parse_token(&compiler, token);
|
||||
codegen(node);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
63
src/node.h
Normal file
63
src/node.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#ifndef NODE_H
|
||||
#define NODE_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <stc/forward.h>
|
||||
typedef struct Node Node;
|
||||
forward_cvec(Nodes, struct Node);
|
||||
|
||||
typedef enum {
|
||||
NODE_FUNCTION_CALL = 'C',
|
||||
NODE_FUNCTION_DECL = 'D',
|
||||
NODE_FUNCTION_IMPL = 'I',
|
||||
NODE_ARG_DECL = 'A',
|
||||
NODE_NUMBER = 'N',
|
||||
} NodeType;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
Nodes args;
|
||||
} FunctionCall;
|
||||
|
||||
typedef struct {
|
||||
const char* type;
|
||||
const char* name;
|
||||
Nodes args;
|
||||
} FunctionDecl;
|
||||
|
||||
typedef struct {
|
||||
const char* type;
|
||||
const char* name;
|
||||
Nodes args;
|
||||
Nodes body;
|
||||
} FunctionImpl;
|
||||
|
||||
typedef struct {
|
||||
const char* type;
|
||||
const char* name;
|
||||
} ArgDecl;
|
||||
|
||||
typedef struct {
|
||||
long long int value;
|
||||
} Number;
|
||||
|
||||
struct Nodes;
|
||||
typedef struct Node {
|
||||
NodeType type;
|
||||
union {
|
||||
FunctionCall function_call;
|
||||
FunctionDecl function_decl;
|
||||
FunctionImpl function_impl;
|
||||
ArgDecl arg_decl;
|
||||
Number number;
|
||||
};
|
||||
} Node;
|
||||
|
||||
#define i_type Nodes
|
||||
#define i_is_forward
|
||||
#define i_val Node
|
||||
#define i_opt c_no_cmp
|
||||
#include <stc/cvec.h>
|
||||
|
||||
#endif
|
164
src/parser.c
Normal file
164
src/parser.c
Normal file
|
@ -0,0 +1,164 @@
|
|||
#include "parser.h"
|
||||
#include "helpers.h"
|
||||
|
||||
Node parse_token(Compiler* self, Token token) {
|
||||
switch(token.type) {
|
||||
case TOKEN_TYPEIDENTIFIER:
|
||||
return parse_type(self, token.value);
|
||||
case TOKEN_IDENTIFIER:
|
||||
return parse_identifier(self, token.value);
|
||||
case TOKEN_NUMBER:
|
||||
return parse_number(self, token.value);
|
||||
default:
|
||||
syntax_error("unexpected token \"%s\"", token.value);
|
||||
}
|
||||
}
|
||||
|
||||
Nodes parse_until(Compiler* self, TokenType end_token) {
|
||||
Nodes collected = { 0 };
|
||||
|
||||
Token token;
|
||||
while(next(self, &token)) {
|
||||
if(token.type == end_token) {
|
||||
break;
|
||||
}
|
||||
|
||||
Nodes_push(&collected, parse_token(self, token));
|
||||
}
|
||||
|
||||
return collected;
|
||||
}
|
||||
|
||||
Node parse_type(Compiler* self, const char* type) {
|
||||
printf("parse type %s\n", type);
|
||||
Token token;
|
||||
next(self, &token);
|
||||
|
||||
switch(token.type) {
|
||||
case TOKEN_IDENTIFIER:
|
||||
return parse_type_ident_pair(self, type, token.value);
|
||||
break;
|
||||
default:
|
||||
syntax_error("unexpected token \"%s\" after type \"%s\"", token.value, type);
|
||||
}
|
||||
}
|
||||
|
||||
Node parse_identifier(Compiler* self, const char* name) {
|
||||
Token token;
|
||||
next(self, &token);
|
||||
|
||||
switch(token.type) {
|
||||
case TOKEN_OPAREN:
|
||||
return parse_function_call(self, name);
|
||||
break;
|
||||
default:
|
||||
syntax_error("unexpected token \"%s\" after identifier \"%s\"", token.value, name);
|
||||
}
|
||||
}
|
||||
|
||||
Node parse_number(Compiler* self, const char* value) {
|
||||
return (Node){
|
||||
.type = NODE_NUMBER,
|
||||
.number = atoll(value),
|
||||
};
|
||||
}
|
||||
|
||||
Node parse_type_ident_pair(Compiler* self, const char* type, const char* name) {
|
||||
printf("parse type ident pair %s %s\n", type, name);
|
||||
Token token;
|
||||
next(self, &token);
|
||||
|
||||
switch(token.type) {
|
||||
case TOKEN_OPAREN:
|
||||
return parse_function(self, type, name);
|
||||
default:
|
||||
syntax_error("unexpected token \"%s\" after \"%s %s\"", token.value, type, name);
|
||||
}
|
||||
}
|
||||
|
||||
Node parse_function(Compiler* self, const char* type, const char* name) {
|
||||
printf("parse function %s %s\n", type, name);
|
||||
Nodes args = { 0 };
|
||||
while(true) {
|
||||
Token arg_type;
|
||||
next(self, &arg_type);
|
||||
if(arg_type.type == TOKEN_CPAREN) {
|
||||
break;
|
||||
}
|
||||
|
||||
Token arg_name;
|
||||
next(self, &arg_name);
|
||||
|
||||
Nodes_push(&args,
|
||||
(Node){
|
||||
.type = NODE_ARG_DECL,
|
||||
.arg_decl = { .type = arg_type.value, .name = arg_name.value },
|
||||
});
|
||||
|
||||
Token token;
|
||||
next(self, &token);
|
||||
switch(token.type) {
|
||||
case TOKEN_COMMA:
|
||||
continue;
|
||||
case TOKEN_CPAREN:
|
||||
break;
|
||||
default:
|
||||
syntax_error("expected comma or closing parenthesis, found %s", token.value);
|
||||
}
|
||||
|
||||
break; // only reached if didnt continue or error
|
||||
}
|
||||
|
||||
Token token;
|
||||
if(next(self, &token)) {
|
||||
switch(token.type) {
|
||||
case TOKEN_SEMICOLON:
|
||||
return parse_function_decl(self, type, name, args);
|
||||
case TOKEN_OBRACE:
|
||||
return parse_function_impl(self, type, name, args);
|
||||
default:
|
||||
syntax_error("expected semicolon or opening brace found, %s", token.value);
|
||||
}
|
||||
} else {
|
||||
syntax_error("expected token, found eof");
|
||||
}
|
||||
}
|
||||
|
||||
Node parse_function_decl(Compiler* self, const char* type, const char* name, Nodes args) {
|
||||
return (Node){
|
||||
.type = NODE_FUNCTION_DECL,
|
||||
.function_decl = { .type = type, .name = name, .args = args },
|
||||
};
|
||||
}
|
||||
|
||||
Node parse_function_impl(Compiler* self, const char* type, const char* name, Nodes args) {
|
||||
Nodes body = parse_until(self, TOKEN_CBRACE);
|
||||
|
||||
return (Node){
|
||||
.type = NODE_FUNCTION_IMPL,
|
||||
.function_impl = { .type = type, .name = name, .args = args, .body = body },
|
||||
};
|
||||
}
|
||||
|
||||
Node parse_function_call(Compiler* self, const char* name) {
|
||||
printf("parse function call %s\n", name);
|
||||
Nodes args = parse_until(self, TOKEN_CPAREN);
|
||||
|
||||
parse_semicolon(self);
|
||||
return (Node){
|
||||
.type = NODE_FUNCTION_CALL,
|
||||
.function_call = { .name = name, .args = args },
|
||||
};
|
||||
}
|
||||
|
||||
void parse_semicolon(Compiler* self) {
|
||||
Token token;
|
||||
next(self, &token);
|
||||
|
||||
switch(token.type) {
|
||||
case TOKEN_SEMICOLON:
|
||||
return;
|
||||
default:
|
||||
syntax_error("expected semicolon, found \"%s\"", token.value);
|
||||
}
|
||||
}
|
21
src/parser.h
Normal file
21
src/parser.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include "compiler.h"
|
||||
#include "node.h"
|
||||
#include "token.h"
|
||||
|
||||
Node parse_token(Compiler* self, Token token);
|
||||
Nodes parse_until(Compiler* self, TokenType end_token);
|
||||
Node parse_type(Compiler* self, const char* type);
|
||||
Node parse_identifier(Compiler* self, const char* name);
|
||||
Node parse_number(Compiler* self, const char* value);
|
||||
Node parse_type_ident_pair(Compiler* self, const char* type, const char* name);
|
||||
Node parse_arg_decl(Compiler* self, const char* type, const char* name);
|
||||
Node parse_function(Compiler* self, const char* type, const char* name);
|
||||
Node parse_function_decl(Compiler* self, const char* type, const char* name, Nodes args);
|
||||
Node parse_function_impl(Compiler* self, const char* type, const char* name, Nodes args);
|
||||
Node parse_function_call(Compiler* self, const char* name);
|
||||
void parse_semicolon(Compiler* self);
|
||||
|
||||
#endif
|
9
src/token.h
Normal file
9
src/token.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef TOKEN_H
|
||||
#define TOKEN_H
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
const char* value;
|
||||
} Token;
|
||||
|
||||
#endif
|
10
test.txt
Normal file
10
test.txt
Normal file
|
@ -0,0 +1,10 @@
|
|||
hey "bob \"mr goonman\" gooner"
|
||||
|
||||
i32 putchar(i32 char);
|
||||
|
||||
void sayhi() {
|
||||
putchar(72);
|
||||
putchar(105);
|
||||
}
|
||||
|
||||
sayhi();
|
79
xmake.lua
Normal file
79
xmake.lua
Normal file
|
@ -0,0 +1,79 @@
|
|||
add_rules("mode.debug", "mode.release")
|
||||
|
||||
add_requires("stc")
|
||||
|
||||
target("compiler-c")
|
||||
set_kind("binary")
|
||||
add_files("src/*.c")
|
||||
add_packages("stc")
|
||||
set_rundir(".")
|
||||
|
||||
--
|
||||
-- If you want to known more usage about xmake, please see https://xmake.io
|
||||
--
|
||||
-- ## FAQ
|
||||
--
|
||||
-- You can enter the project directory firstly before building project.
|
||||
--
|
||||
-- $ cd projectdir
|
||||
--
|
||||
-- 1. How to build project?
|
||||
--
|
||||
-- $ xmake
|
||||
--
|
||||
-- 2. How to configure project?
|
||||
--
|
||||
-- $ xmake f -p [macosx|linux|iphoneos ..] -a [x86_64|i386|arm64 ..] -m [debug|release]
|
||||
--
|
||||
-- 3. Where is the build output directory?
|
||||
--
|
||||
-- The default output directory is `./build` and you can configure the output directory.
|
||||
--
|
||||
-- $ xmake f -o outputdir
|
||||
-- $ xmake
|
||||
--
|
||||
-- 4. How to run and debug target after building project?
|
||||
--
|
||||
-- $ xmake run [targetname]
|
||||
-- $ xmake run -d [targetname]
|
||||
--
|
||||
-- 5. How to install target to the system directory or other output directory?
|
||||
--
|
||||
-- $ xmake install
|
||||
-- $ xmake install -o installdir
|
||||
--
|
||||
-- 6. Add some frequently-used compilation flags in xmake.lua
|
||||
--
|
||||
-- @code
|
||||
-- -- add debug and release modes
|
||||
-- add_rules("mode.debug", "mode.release")
|
||||
--
|
||||
-- -- add macro definition
|
||||
-- add_defines("NDEBUG", "_GNU_SOURCE=1")
|
||||
--
|
||||
-- -- set warning all as error
|
||||
-- set_warnings("all", "error")
|
||||
--
|
||||
-- -- set language: c99, c++11
|
||||
-- set_languages("c99", "c++11")
|
||||
--
|
||||
-- -- set optimization: none, faster, fastest, smallest
|
||||
-- set_optimize("fastest")
|
||||
--
|
||||
-- -- add include search directories
|
||||
-- add_includedirs("/usr/include", "/usr/local/include")
|
||||
--
|
||||
-- -- add link libraries and search directories
|
||||
-- add_links("tbox")
|
||||
-- add_linkdirs("/usr/local/lib", "/usr/lib")
|
||||
--
|
||||
-- -- add system link libraries
|
||||
-- add_syslinks("z", "pthread")
|
||||
--
|
||||
-- -- add compilation and link flags
|
||||
-- add_cxflags("-stdnolib", "-fno-strict-aliasing")
|
||||
-- add_ldflags("-L/usr/local/lib", "-lpthread", {force = true})
|
||||
--
|
||||
-- @endcode
|
||||
--
|
||||
|
Loading…
Add table
Reference in a new issue