Browse Source

Start working on assembler.

master
Ben Kurtovic 9 years ago
parent
commit
b89f5fa1bf
5 changed files with 189 additions and 9 deletions
  1. +2
    -2
      crater.c
  2. +167
    -3
      src/assembler.c
  3. +18
    -2
      src/assembler.h
  4. +1
    -1
      src/disassembler.c
  5. +1
    -1
      src/disassembler.h

+ 2
- 2
crater.c View File

@@ -33,9 +33,9 @@ int main(int argc, char *argv[])
config->assemble ? "assembler" : "disassembler",
config->src_path, config->dst_path);
if (config->assemble)
retval = assemble(config->src_path, config->dst_path);
retval = assemble_file(config->src_path, config->dst_path);
else
retval = disassemble(config->src_path, config->dst_path);
retval = disassemble_file(config->src_path, config->dst_path);
retval = retval ? EXIT_SUCCESS : EXIT_FAILURE;
} else {
ROM *rom;


+ 167
- 3
src/assembler.c View File

@@ -1,16 +1,180 @@
/* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
Released under the terms of the MIT License. See LICENSE for details. */

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

#include "assembler.h"
#include "logging.h"

/*
Deallocate a LineBuffer previously created with read_source_file().
*/
static void free_line_buffer(LineBuffer *buffer)
{
for (size_t i = 0; i < buffer->length; i++)
free(buffer->lines[i].data);
free(buffer->lines);
free(buffer);
}

/*
Read the contents of the source file at the given path into a line buffer.

Return the buffer if reading was successful; it must be freed with
free_line_buffer() when done. Return NULL if an error occurred while
reading. A message will be printed to stderr in this case.
*/
static LineBuffer* read_source_file(const char *path)
{
FILE* fp;
struct stat st;

if (!(fp = fopen(path, "r"))) {
ERROR_ERRNO("couldn't open source file")
return NULL;
}

if (fstat(fileno(fp), &st)) {
fclose(fp);
ERROR_ERRNO("couldn't open source file")
return NULL;
}
if (!(st.st_mode & S_IFREG)) {
fclose(fp);
ERROR("couldn't open source file: %s", st.st_mode & S_IFDIR ?
"Is a directory" : "Is not a regular file")
return NULL;
}

size_t capacity = 16;
LineBuffer *source = malloc(sizeof(LineBuffer));
if (!source)
OUT_OF_MEMORY()

source->length = 0;
source->lines = malloc(sizeof(Line) * capacity);
if (!source->lines)
OUT_OF_MEMORY()

while (1) {
char *line = NULL;
size_t lcap = 0;
ssize_t len;

if ((len = getline(&line, &lcap, fp)) < 0) {
if (feof(fp))
break;
if (errno == ENOMEM)
OUT_OF_MEMORY()
ERROR_ERRNO("couldn't read source file")
free_line_buffer(source);
source = NULL;
break;
}

if (capacity <= source->length + 1) {
capacity <<= 2;
source->lines = realloc(source->lines, sizeof(Line) * capacity);
if (!source->lines)
OUT_OF_MEMORY()
}

source->lines[source->length++] = (Line) {line, len};
if (feof(fp)) {
source->lines[source->length].length--;
break;
}
}

fclose(fp);
return source;
}

/*
Write an assembled binary file to the given path.

Return whether the file was written successfully. On error, a message is
printed to stderr.
*/
static bool write_binary_file(const char *path, const uint8_t *data, size_t size)
{
// TODO
return false;
}

/*
Assemble the z80 source code at the input path into a binary.
Print an ErrorInfo object returned by assemble() to the given file.

The same LineBuffer passed to assemble() should be passed to this function.
Passing NULL if it is unavailable will still work, but source code snippets
where errors were noted will not be printed.
*/
void error_info_print(const ErrorInfo *error_info, FILE *file, const LineBuffer *source)
{
// TODO
}

/*
Destroy an ErrorInfo object created by assemble().
*/
void error_info_destroy(ErrorInfo *error_info)
{
if (!error_info)
return;

// TODO
free(error_info);
}

/*
Assemble the z80 source code in the source code buffer into binary data.

If successful, return the size of the assembled binary data and change
*binary_ptr to point to the assembled ROM data buffer. *binary_ptr must be
free()'d when finished.

If an error occurred, return 0 and update *ei_ptr to point to an ErrorInfo
object which can be shown to the user with error_info_print(). The
ErrorInfo object must be destroyed with error_info_destroy() when finished.

In either case, only one of *binary_ptr and *ei_ptr is modified.
*/
size_t assemble(const LineBuffer *source, uint8_t **binary_ptr, ErrorInfo **ei_ptr)
{
// TODO
return 0;
}

/*
Assemble the z80 source code at the input path into a binary file.

Return true if the operation was a success and false if it was a failure.
Errors are printed to STDOUT; if the operation was successful then nothing
is printed.
*/
bool assemble(const char* src_path, const char* dst_path)
bool assemble_file(const char *src_path, const char *dst_path)
{
return true;
LineBuffer *source = read_source_file(src_path);
if (!source)
return false;

uint8_t *binary;
ErrorInfo *error_info;
size_t size = assemble(source, &binary, &error_info);

if (!size) {
error_info_print(error_info, stderr, source);
error_info_destroy(error_info);
free_line_buffer(source);
return false;
}

bool success = write_binary_file(dst_path, binary, size);
free(binary);
free_line_buffer(source);
return success;
}

+ 18
- 2
src/assembler.h View File

@@ -4,11 +4,27 @@
#pragma once

#include <stdbool.h>
#include <stdint.h>

/* Structs */

// ...
typedef struct {
char *data;
size_t length;
} Line;

typedef struct {
Line *lines;
size_t length;
} LineBuffer;

typedef struct {
//
} ErrorInfo;

/* Functions */

bool assemble(const char*, const char*);
void error_info_print(const ErrorInfo*, FILE*, const LineBuffer*);
void error_info_destroy(ErrorInfo*);
size_t assemble(const LineBuffer*, uint8_t**, ErrorInfo**);
bool assemble_file(const char*, const char*);

+ 1
- 1
src/disassembler.c View File

@@ -10,7 +10,7 @@
Errors are printed to STDOUT; if the operation was successful then nothing
is printed.
*/
bool disassemble(const char* src_path, const char* dst_path)
bool disassemble_file(const char *src_path, const char *dst_path)
{
return true;
}

+ 1
- 1
src/disassembler.h View File

@@ -11,4 +11,4 @@

/* Functions */

bool disassemble(const char*, const char*);
bool disassemble_file(const char*, const char*);

Loading…
Cancel
Save