slas/asmln.c

389 lines
10 KiB
C

#include "asmln.h"
#include <memory.h>
#include <stdlib.h>
#include <stdio.h> // TODO: Remove this, it's only for debugging/testing..
static int32_t asmln_strlen_(const char* str) {
if (str == NULL) {
return 0;
}
int32_t l = 0;
while (str[l] != 0) {
l++;
}
return l;
}
static char* asmln_strndup_(char* str, int maxlen) {
char* result = calloc(maxlen + 1, 1);
if (result != NULL && str != NULL) {
int32_t i;
for (i = 0; i < maxlen; i++) {
if (str[i] == 0) {
return (char*)result;
}
result[i] = str[i];
}
}
return (char*)result;
}
static char* asmln_strdup_(char* str) {
return asmln_strndup_(str, asmln_strlen_(str));
}
static char* asmln_tokendup_(asmt_t* asmt) {
int32_t t = asmt_tokentype(asmt);
int32_t len = asmt_tokenlength(asmt);
if (len <= 0) {
return NULL;
}
if (t == ASMT_TOKENTYPE_STRING) {
return asmln_strndup_(asmt->input + (asmt->index + 1), len - 2); // Skip quotes
}
if (t == ASMT_TOKENTYPE_LABEL) {
len--;
}
//printf("Duplicating token type %d length %d\n", t, len);
const char* result = asmln_strndup_(asmt->input + asmt->index, len);
//printf("Got '%s'\n", result);
return result;
}
bool asmlnx_parse_subexpression(asmln_t* asmln, asmt_t* asmt, int32_t* type_var, char** copy_var, asmlnx_t** x_var, int32_t* incr_var) {
bool mayhavemoreparams = true;
int32_t tt = asmt_tokentype(asmt);
int32_t subc = 0;
//fprintf(stderr, "Got token type #%d\n", tt);
switch (tt)
{
case ASMT_TOKENTYPE_OPENBR:
x_var[0] = calloc(1, sizeof(asmlnx_t));
if (x_var[0] == NULL) {
fprintf(stderr, "MEMORY FAILURE\n");
return false; // TODO: Better error handling here?
}
type_var[0] = tt;
copy_var[0] = asmln_strdup_("(...)"); // TODO: Copy the whole expression source for debugging? (Probably not worthwhile.)
incr_var[0]++;
asmt_skiptoken(asmt);
if (asmlnx_parse_subexpression(asmln, asmt, &(x_var[0]->lhstype), &(x_var[0]->lhscopy), &(x_var[0]->lhsx), &subc)) {
fprintf(stderr, "BAD LHS\n");
return false;
}
if (asmt_tokentype(asmt) != ASMT_TOKENTYPE_NAME) {
fprintf(stderr, "NOT A NAME\n");
return false;
}
x_var[0]->opcopy = asmln_tokendup_(asmt);
//fprintf(stderr, "GOT OPERATOR '%s'\n", x_var[0]->opcopy);
asmt_skiptoken(asmt);
if (asmlnx_parse_subexpression(asmln, asmt, &(x_var[0]->rhstype), &(x_var[0]->rhscopy), &(x_var[0]->rhsx), &subc)) {
fprintf(stderr, "BAD RHS\n");
return false;
}
if (asmt_tokentype(asmt) != ASMT_TOKENTYPE_CLOSEBR) {
fprintf(stderr, "MISSING CLOSE\n");
return false;
}
asmt_skiptoken(asmt);
if (asmt_tokentype(asmt) == ASMT_TOKENTYPE_COMMA) {
//printf("I got a comma\n");
asmt_skiptoken(asmt);
}
else {
mayhavemoreparams = false;
}
break;
case ASMT_TOKENTYPE_NAME:
case ASMT_TOKENTYPE_NUMBER:
case ASMT_TOKENTYPE_STRING:
type_var[0] = tt;
copy_var[0] = asmln_tokendup_(asmt);
x_var[0] = NULL;
incr_var[0]++;
asmt_skiptoken(asmt);
// A hack to allow GNU-style offsets like in ld a0, 0(sp)
// This translates e.g. 0(sp) to (0 OFF sp)
if (/*tt == ASMT_TOKENTYPE_NUMBER && */asmt_tokentype(asmt) == ASMT_TOKENTYPE_OPENBR) {
asmt_skiptoken(asmt);
x_var[0] = calloc(1, sizeof(asmlnx_t));
x_var[0]->lhstype = type_var[0];
x_var[0]->lhscopy = asmln_strdup_(copy_var[0]);
x_var[0]->lhsx = NULL;
x_var[0]->opcopy = asmln_strdup_("OFF");
//printf("Copied '%s'\n", x_var[0]->lhscopy);
copy_var[0] = NULL;
type_var[0] = ASMT_TOKENTYPE_OPENBR;
if (asmlnx_parse_subexpression(asmln, asmt, &(x_var[0]->rhstype), &(x_var[0]->rhscopy), &(x_var[0]->rhsx), &subc)) {
fprintf(stderr, "BAD RHS\n");
return false;
}
if (asmt_tokentype(asmt) != ASMT_TOKENTYPE_CLOSEBR) {
fprintf(stderr, "MISSING CLOSE\n");
return false;
}
asmt_skiptoken(asmt);
}
if (asmt_tokentype(asmt) == ASMT_TOKENTYPE_COMMA) {
//printf("I got a comma\n");
asmt_skiptoken(asmt);
} else {
mayhavemoreparams = false;
}
break;
default:
mayhavemoreparams = false;
break;
}
return mayhavemoreparams;
}
// Parses a C-style string
static char* asmt_cstringhack(asmt_t* asmt) {
asmt_skipspaces(asmt);
if (asmt_isend(asmt) || !asmt_isstringstart(asmt)) {
return NULL;
}
asmt->index++;
if (asmt_isend(asmt)) {
return NULL;
}
char* result = calloc(asmt->length+1,1);
if (result == NULL) {
return NULL;
}
result[0] = '\"';
int resulti = 1;
bool finished = false;
while (!asmt_isend(asmt) && !finished) {
if (asmt->input[asmt->index] == '\\') {
asmt->index++;
if (asmt_isend(asmt)) break;
switch (asmt->input[asmt->index]) {
case 'r':
result[resulti] = '\r';
resulti++;
break;
case 'n':
result[resulti] = '\n';
resulti++;
break;
case 't':
result[resulti] = '\t';
resulti++;
break;
case '\'':
result[resulti] = '\n';
resulti++;
break;
case '\"':
result[resulti] = '\"';
resulti++;
break;
case '\\':
result[resulti] = '\\';
resulti++;
break;
default:
result[resulti] = asmt->input[asmt->index];
resulti++;
}
asmt->index++;
} else {
result[resulti] = asmt->input[asmt->index];
if (result[resulti] == '\"') {
finished = true;
}
resulti++;
asmt->index++;
}
}
result[resulti] = 0;
if (!finished) {
free(result);
return NULL;
}
return result;
}
static void asmln_parse_inner(asmln_t* asmln, const char* sourceline) {
if (asmln->errorcopy != NULL || asmln->instrcopy != NULL || asmln->labelcopy != NULL || asmln->commentcopy != NULL || asmln->nparams != 0) {
asmln->errorcopy = asmln_strdup_("Assembler structure reused improperly");
return;
}
if (sourceline == NULL) {
asmln->errorcopy = asmln_strdup_("Source line is NULL");
return;
}
asmt_t asmt;
asmt.input = sourceline;
asmt.length = asmln_strlen_(sourceline);
asmt.index = 0;
if (asmt_tokentype(&asmt) == ASMT_TOKENTYPE_LABEL) {
asmln->labelcopy = asmln_tokendup_(&asmt);
asmt_skiptoken(&asmt);
}
else {
asmln->labelcopy = NULL;
}
asmln->nparams = 0;
if (asmt_tokentype(&asmt) == ASMT_TOKENTYPE_NAME) {
asmln->instrcopy = asmln_tokendup_(&asmt);
asmt_skiptoken(&asmt);
bool mayhavemoreparams = true;
// For compatibility with .string "Hello\n" type strings
if (asmln->instrcopy[0] == '.'
&& asmln->instrcopy[1] == 's'
&& asmln->instrcopy[2] == 't'
&& asmln->instrcopy[3] == 'r'
&& asmln->instrcopy[4] == 'i'
&& asmln->instrcopy[5] == 'n'
&& asmln->instrcopy[6] == 'g'
&& asmln->instrcopy[7] == 0) {
asmln->paramcopy[0] = asmt_cstringhack(&asmt);
if (asmln->paramcopy[0] != NULL) {
asmln->paramtype[0] = ASMT_TOKENTYPE_STRING;
asmln->nparams = 1;
mayhavemoreparams = false;
}
}
int32_t tt;
while (mayhavemoreparams) {
if (asmln->nparams >= ASMLN_MAXPARAMS) {
asmln->errorcopy = asmln_strdup_("Too many parameters");
return;
}
mayhavemoreparams = asmlnx_parse_subexpression(asmln, &asmt, &asmln->paramtype[asmln->nparams], &asmln->paramcopy[asmln->nparams], &asmln->paramx[asmln->nparams], &asmln->nparams);
/*switch (tt = asmt_tokentype(&asmt))
{
case ASMT_TOKENTYPE_OPENBR:
case ASMT_TOKENTYPE_NAME:
case ASMT_TOKENTYPE_NUMBER:
case ASMT_TOKENTYPE_STRING:
if (asmln->nparams >= ASMLN_MAXPARAMS) {
asmln->errorcopy = asmln_strdup_("Too many parameters");
return;
}
asmln->paramtype[asmln->nparams] = tt;
asmln->paramcopy[asmln->nparams] = asmln_tokendup_(&asmt);
asmln->nparams++;
asmt_skiptoken(&asmt);
if (asmt_tokentype(&asmt) == ASMT_TOKENTYPE_COMMA) {
//printf("I got a comma\n");
asmt_skiptoken(&asmt);
} else {
mayhavemoreparams = false;
}
break;
default:
mayhavemoreparams = false;
break;
}*/
}
}
else {
asmln->instrcopy = NULL;
}
if (asmt_tokentype(&asmt) == ASMT_TOKENTYPE_COMMENT) {
asmln->commentcopy = asmln_tokendup_(&asmt);
asmt_skiptoken(&asmt);
}
else {
asmln->commentcopy = NULL;
}
if (asmt_tokentype(&asmt) != ASMT_TOKENTYPE_END) {
asmln->errorcopy = asmln_strdup_("Unexpected token (the source doesn't seem to be a line of valid assembler)");
return;
}
}
asmln_t* asmln_new(const char* sourceline) {
asmln_t* result = calloc(1, sizeof(asmln_t));
if (result != NULL) {
asmln_parse_inner(result, sourceline);
}
return result;
}
void* asmlnx_delete(asmlnx_t* asmlnx) {
if (asmlnx->lhscopy != NULL) {
free(asmlnx->lhscopy);
}
if (asmlnx->lhsx != NULL) {
asmlnx_delete(asmlnx->lhsx);
}
if (asmlnx->opcopy != NULL) {
free(asmlnx->opcopy);
}
if (asmlnx->rhscopy != NULL) {
free(asmlnx->rhscopy);
}
if (asmlnx->rhsx != NULL) {
asmlnx_delete(asmlnx->rhsx);
}
free(asmlnx);
return NULL;
}
void* asmln_delete(asmln_t* asmln) {
if (asmln != NULL) {
if (asmln->labelcopy != NULL) {
free(asmln->labelcopy);
asmln->labelcopy = NULL;
}
if (asmln->instrcopy != NULL) {
free(asmln->instrcopy);
asmln->instrcopy = NULL;
}
if (asmln->errorcopy != NULL) {
free(asmln->errorcopy);
asmln->errorcopy = NULL;
}
if (asmln->commentcopy != NULL) {
free(asmln->commentcopy);
asmln->commentcopy = NULL;
}
int32_t i;
for (i = 0; i < asmln->nparams; i++) {
asmln->paramtype[i] = ASMT_TOKENTYPE_END;
if (asmln->paramcopy[i] != NULL) {
free(asmln->paramcopy[i]);
asmln->paramcopy[i] = NULL;
}
if (asmln->paramx[i] != NULL) {
asmlnx_delete(asmln->paramx[i]);
asmln->paramx[i] = NULL;
}
}
asmln->nparams = 0;
free(asmln);
}
return NULL;
}