#include "asmln.h" #include #include #include // 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; }