Browse Source

finish lc rust conversion

master
Yuki Izumi 4 years ago
parent
commit
c6ab16b4e7
No known key found for this signature in database GPG Key ID: 44A3D2C95E26BB14
11 changed files with 102 additions and 287 deletions
  1. +0
    -1
      CMakeLists.txt
  2. +2
    -2
      Makefile
  3. +0
    -2
      in.s
  4. +0
    -58
      lc/CMakeLists.txt
  5. +7
    -0
      lc/Cargo.lock
  6. +1
    -0
      lc/Cargo.toml
  7. +0
    -115
      lc/codegen.c
  8. +0
    -8
      lc/codegen.h
  9. +0
    -95
      lc/main.c
  10. +91
    -5
      lc/src/codegen.rs
  11. +1
    -1
      lc/src/main.rs

+ 0
- 1
CMakeLists.txt View File

@@ -10,7 +10,6 @@ set(PROJECT_VERSION_PATCH 0)
set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} )

add_subdirectory(vm)
add_subdirectory(lc)

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "Release" CACHE STRING


+ 2
- 2
Makefile View File

@@ -5,7 +5,7 @@ BUILDDIR?=build
all: vm_build

vm_build: $(BUILDDIR)
make -C $(BUILDDIR)
(cd lc && cargo build) && make -C $(BUILDDIR)

$(BUILDDIR):
mkdir -p $(BUILDDIR); \
@@ -16,7 +16,7 @@ debug:
mkdir -p $(BUILDDIR); \
cd $(BUILDDIR); \
cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug; \
$(MAKE)
(cd ../lc && cargo build) && $(MAKE)

leakcheck: vm_build
valgrind --leak-check=full build/vm


+ 0
- 2
in.s View File

@@ -1,5 +1,3 @@
x = "no"

x = "a"
y = "b"
z = x + y + "c"


+ 0
- 58
lc/CMakeLists.txt View File

@@ -1,58 +0,0 @@
cmake_minimum_required(VERSION 2.8)
set(PROGRAM "lc")
set(PROGRAM_SOURCES
main.c
ast.c
ast.h
codegen.c
codegen.h
parser.y
lexer.l
cfu.c
cfu.h
cfuhash.c
cfuhash.h
cfustring.c
cfustring.h)

if(APPLE)
list(INSERT CMAKE_PREFIX_PATH 0 /usr/local/opt/flex)
endif(APPLE)

find_package(BISON)
find_package(FLEX)

BISON_TARGET(parser parser.y ${CMAKE_CURRENT_BINARY_DIR}/parser.c)
FLEX_TARGET(lexer lexer.l ${CMAKE_CURRENT_BINARY_DIR}/lexer.c)

set_source_files_properties(${FLEX_lexer_OUTPUTS} PROPERTIES COMPILE_FLAGS "-Wno-implicit-function-declaration -Wno-unused-function -Wno-sign-compare")

include_directories(. ${CMAKE_CURRENT_BINARY_DIR})

add_executable(${PROGRAM}
${PROGRAM_SOURCES}
${BISON_parser_OUTPUTS}
${FLEX_lexer_OUTPUTS})

target_link_libraries(${PROGRAM} ${FLEX_LIBRARIES} ${BISON_LIBRARIES})

install(TARGETS ${PROGRAM}
EXPORT ${PROGRAM}
RUNTIME DESTINATION bin
)

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=gnu99")

include(CheckIncludeFile)
include(CheckSymbolExists)

CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
CHECK_SYMBOL_EXISTS(strncasecmp strings.h HAVE_STRNCASECMP)
CHECK_SYMBOL_EXISTS(snprintf stdio.h HAVE_SNPRINTF)
CHECK_SYMBOL_EXISTS(vsnprintf stdio.h HAVE_VSNPRINTF)

CONFIGURE_FILE(
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
${CMAKE_CURRENT_BINARY_DIR}/config.h)

add_definitions(-DHAVE_CONFIG_H)

+ 7
- 0
lc/Cargo.lock View File

@@ -2,6 +2,7 @@
name = "lc"
version = "0.1.0"
dependencies = [
"byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"plex 0.0.2 (git+https://github.com/goffrie/plex.git)",
]

@@ -18,6 +19,11 @@ name = "bit-vec"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "byteorder"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"

[[package]]
name = "lalr"
version = "0.0.1"
@@ -49,6 +55,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum bit-set 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e6e1e6fb1c9e3d6fcdec57216a74eaa03e41f52a22f13a16438251d8e88b89da"
"checksum bit-vec 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5b97c2c8e8bbb4251754f559df8af22fb264853c7d009084a576cdf12565089d"
"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855"
"checksum lalr 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c3f005e993fb11b348b5bf3ac83084a17dba1e7c315d0c241e716025f162cbec"
"checksum plex 0.0.2 (git+https://github.com/goffrie/plex.git)" = "<none>"
"checksum redfa 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a49f58aa92cb44d9cc27cf7080fdbcb37b65ab0f69f16b126cd0edd01b2f9883"


+ 1
- 0
lc/Cargo.toml View File

@@ -5,3 +5,4 @@ authors = ["Yuki Izumi <kivikakk@github.com>"]

[dependencies]
plex = { git = "https://github.com/goffrie/plex.git" }
byteorder = "0.5.3"

+ 0
- 115
lc/codegen.c View File

@@ -1,115 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include "codegen.h"
#include "cfuhash.h"

enum {
NOP,
LDu8,
LDu32,
ADD,
LOCAL,
ENDLOCAL,
STOu8,
RCu8,
DROP,
LDstr,
RET = 0xFF,
};

static void put8(FILE *f, uint8_t n) {
fputc(n, f);
}

static void put32(FILE *f, uint32_t n) {
n = htonl(n);
fwrite(&n, sizeof(n), 1, f);
}

static void putd(FILE *f, void *data, size_t len) {
put32(f, len);
fwrite(data, len, 1, f);
}

static cfuhash_table_t *vars;

void emit(FILE *f, expr const *e) {
switch (e->type) {
case E_IMM_U8:
put8(f, LDu8);
put8(f, e->as.imm_u8);
break;
case E_IMM_STRING:
put8(f, LDstr);
putd(f, e->as.imm_string, strlen(e->as.imm_string));
break;
case E_ASSIGN: {
emit(f, e->as.assign.rhs);
put8(f, STOu8);
void *ix;
cfuhash_get_data(vars, e->as.assign.lhs, -1, &ix, NULL);
put8(f, (uint8_t) ix);
break;
}
case E_REF: {
put8(f, RCu8);
void *ix;
cfuhash_get_data(vars, e->as.ref, -1, &ix, NULL);
put8(f, (uint8_t) ix);
break;
}
case E_BINOP: {
emit(f, e->as.binop.lhs);
emit(f, e->as.binop.rhs);
put8(f, ADD);
break;
}
default:
abort();
}
}

void codegen(FILE *f, ast const *ast) {
// scan function for variable assignments
vars = cfuhash_new();

uint8_t i = 0;
for (expr_list const *it = ast->start; it; it = it->next) {
expr const *e = it->expr;
if (e->type == E_ASSIGN) {
if (!cfuhash_exists_data(vars, e->as.assign.lhs, -1)) {
cfuhash_put_data(vars, e->as.assign.lhs, -1, (void *) (intptr_t) i, 0, NULL);
++i;
}
}
}

size_t num_keys;
void **keys = cfuhash_keys_data(vars, &num_keys, NULL, 1);
for (size_t i = 0; i < num_keys; ++i)
printf("key: %s\n", keys[i]);
free(keys);

if (num_keys > 255)
abort();

// emit

if (num_keys) {
put8(f, LOCAL);
put8(f, num_keys);
}

for (expr_list const *it = ast->start; it; it = it->next) {
emit(f, it->expr);
if (it != ast->end)
put8(f, DROP);
}

if (num_keys)
put8(f, ENDLOCAL);

put8(f, RET);

cfuhash_destroy(vars);
}

+ 0
- 8
lc/codegen.h View File

@@ -1,8 +0,0 @@
#ifndef LC_CODEGEN_H
#define LC_CODEGEN_H

#include "ast.h"

void codegen(FILE *f, ast const *ast);

#endif

+ 0
- 95
lc/main.c View File

@@ -1,95 +0,0 @@
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include "ast.h"
#include "codegen.h"

static void usage(int exit_code);
static char *read_all(FILE *f);

int main(int argc, char **argv) {
char *out_file = NULL;

static struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "output", required_argument, NULL, 'o' },
{ NULL, 0, NULL, 0 },
};

int ch;
while ((ch = getopt_long(argc, argv, "ho:", longopts, NULL)) != -1) {
switch (ch) {
case 'h':
usage(0);
case 'o':
out_file = alloca(strlen(optarg) + 1);
strcpy(out_file, optarg);
break;
default:
usage(1);
}
}

argc -= optind;
argv += optind;
if (argc != 1)
usage(1);

FILE *f = fopen(argv[0], "r");
if (!f) {
perror("failed to open file for reading");
return 1;
}
char *buffer = read_all(f);
fclose(f);

begin_scan(buffer);
ast *ast = make_ast();
yyparse(ast);
finish_scan();

free(buffer);

ast_pp(stdout, ast);

f = fopen(out_file ? out_file : "a.out", "w");
codegen(f, ast);
fclose(f);

ast_free(ast);

return 0;
}

static void usage(int exit_code) {
printf(
"\n"
"Usage: lc [OPTIONS] PATH\n"
"\n"
" Compile the code in PATH.\n"
"\n"
"Options:\n"
" -o --output PATH Specify the output path (Default: a.out)\n"
" -h --help This help.\n"
"\n");
exit(exit_code);
}

static char *read_all(FILE *f) {
int alloc, sz = 0;
char *out = calloc(1, alloc = 1024);
char buffer[1024];
while (!feof(f)) {
int n = fread(buffer, 1, 1024, f);
if (n == 0)
break;
while (sz + n > alloc)
out = realloc(out, alloc = alloc * 3 / 2);
memcpy(out + sz, buffer, n);
sz += n;
}
if (sz + 1 > alloc)
out = realloc(out, ++alloc);
out[sz] = 0;
return out;
}

+ 91
- 5
lc/src/codegen.rs View File

@@ -1,17 +1,34 @@
extern crate byteorder;

use std::io;
use std::collections::BTreeMap;
use self::byteorder::{BigEndian, WriteBytesExt};

use ast;

pub fn codegen<W>(writer: &mut W, es: Vec<ast::Expr>)
enum Ins {
NOP = 0,
LDu8,
LDu32,
ADD,
LOCAL,
ENDLOCAL,
STOu8,
RCu8,
DROP,
LDstr,
RET = 0xFF,
}

pub fn codegen<W>(writer: &mut W, es: Vec<ast::Expr>) -> io::Result<()>
where W: io::Write {
let mut vars: BTreeMap<String, u32> = BTreeMap::new();
let mut i: u32 = 0;

for e in es {
for e in &es {
match e.node {
ast::Expr_::Assign(lhs, _) => {
vars.entry(lhs).or_insert_with(|| {
ast::Expr_::Assign(ref lhs, _) => {
vars.entry(lhs.clone()).or_insert_with(|| {
let r = i;
i += 1;
r
@@ -21,5 +38,74 @@ pub fn codegen<W>(writer: &mut W, es: Vec<ast::Expr>)
}
}

println!("{:?}", vars);
if i > 0 {
try!(writer.write(&[
Ins::LOCAL as u8,
i as u8,
]));
}

let mut first = true;
for e in es {
if first {
first = false;
} else {
try!(writer.write(&[
Ins::DROP as u8,
]));
}
try!(emit(writer, &vars, e.node));
}

if i > 0 {
try!(writer.write(&[
Ins::ENDLOCAL as u8,
]));
}

try!(writer.write(&[
Ins::RET as u8,
]));

Ok(())
}

fn emit<W>(writer: &mut W, vars: &BTreeMap<String, u32>, e: ast::Expr_) -> io::Result<()>
where W: io::Write {
match e {
ast::Expr_::ImmNumber(i) => {
try!(writer.write(&[
Ins::LDu8 as u8,
i as u8,
]));
}
ast::Expr_::ImmString(s) => {
try!(writer.write(&[
Ins::LDstr as u8,
]));
try!(writer.write_u32::<BigEndian>(s.len() as u32));
try!(writer.write(s.as_bytes()));
}
ast::Expr_::Assign(lhs, rhs) => {
try!(emit(writer, &vars, (*rhs).node));
try!(writer.write(&[
Ins::STOu8 as u8,
*vars.get(&lhs).unwrap() as u8,
]));
}
ast::Expr_::Ref(r) => {
try!(writer.write(&[
Ins::RCu8 as u8,
*vars.get(&r).unwrap() as u8,
]));
}
ast::Expr_::BinOp(lhs, op, rhs) => {
try!(emit(writer, vars, (*lhs).node));
try!(emit(writer, vars, (*rhs).node));
try!(writer.write(&[
Ins::ADD as u8,
]));
}
}
Ok(())
}

+ 1
- 1
lc/src/main.rs View File

@@ -12,7 +12,7 @@ fn main() {
std::io::stdin().read_to_string(&mut s).unwrap();
let lexer = lexer::Lexer::new(&s);
let program = parser::parse(lexer).unwrap();
codegen::codegen(&mut std::io::stdout(), program);
codegen::codegen(&mut std::io::stdout(), program).unwrap();
}




Loading…
Cancel
Save