newrpl/newrpl-comp.c
Stefan Achatz 9c8e6da348 Renamed mutex functions and fixed comp build.
It seems there will be need for other mutexes therefore the mutex_* functions have been renamed usb_mutex_*.
Also newrpl-comp was missing an (empty) implementation which prohibited compilation.
2020-01-29 09:39:50 +01:00

444 lines
No EOL
14 KiB
C

/*
* Copyright (c) 2014-2015, Claudio Lapilli and the newRPL Team
* All rights reserved.
* This file is released under the 3-clause BSD license.
* See the file LICENSE.txt that shipped with this distribution.
*/
#include "newrpl.h"
#include "libraries.h"
#include "ui.h"
#include <stdio.h>
#include <string.h>
extern void lib4079_handler();
// DISPLAY AN ERROR MESSAGE
// USES ERROR CODE FROM SYSTEM Exceptions
// OUTPUTS THE ERROR TO THE GIVEN STREAM (USUALLY stderr)
void compShowErrorMsg(char *inputfile, char *mainbuffer, FILE * stream)
{
int errbit;
if(!Exceptions)
return;
char *position = (char *)TokenStart;
char *linestart = NULL;
// COMPUTE LINE NUMBER
int linenum = 1;
while(position > mainbuffer) {
--position;
if(*position == '\n') {
++linenum;
if(!linestart)
linestart = position + 1;
}
}
// COUNT CHARACTERS FROM START OF LINE
position = (char *)TokenStart;
while(*linestart == '\r')
++linestart;
int posnum = utf8nlen(linestart, position) + 1;
fprintf(stream, "%s:%d:%d:", inputfile, linenum, posnum);
if(Exceptions != EX_ERRORCODE) {
if(ExceptionPointer && (*ExceptionPointer != 0)) // ONLY IF THERE'S A VALID COMMAND TO BLAME
{
WORDPTR cmdname = halGetCommandName(ExceptionPointer);
if(cmdname) {
BYTEPTR start = (BYTEPTR) (cmdname + 1);
BYTEPTR end = start + rplStrSize(cmdname);
fwrite(start, 1, end - start, stream);
}
}
fprintf(stream, " Exception: ");
BINT ecode;
for(errbit = 0; errbit < 8; ++errbit) // THERE'S ONLY A FEW EXCEPTIONS IN THE NEW ERROR MODEL
{
if(Exceptions & (1 << errbit)) {
ecode = MAKEMSG(0, errbit);
WORDPTR message = uiGetLibMsg(ecode);
fwrite((char *)(message + 1), 1, rplStrSize(message), stream);
break;
}
}
}
else {
// TRY TO DECOMPILE THE OPCODE THAT CAUSED THE ERROR
if(ExceptionPointer && (*ExceptionPointer != 0)) // ONLY IF THERE'S A VALID COMMAND TO BLAME
{
WORDPTR cmdname = halGetCommandName(ExceptionPointer);
if(cmdname) {
BYTEPTR start = (BYTEPTR) (cmdname + 1);
BYTEPTR end = start + rplStrSize(cmdname);
fwrite(start, 1, end - start, stream);
}
}
fprintf(stream, " error: ");
// TODO: GET NEW TRANSLATABLE MESSAGES
WORDPTR message = uiGetLibMsg(ErrorCode);
if(!message)
fprintf(stream, " %d in library %d\n", ErrorCode & 0x7f,
LIBFROMMSG(ErrorCode));
else
fwrite((char *)(message + 1), 1, rplStrSize(message), stream);
}
fprintf(stream, "\n");
}
enum
{
OUTPUT_BINARY,
OUTPUT_C
};
int main(int argc, char *argv[])
{
char *mainbuffer;
if(argc < 2) {
printf("NewRPL standalone compiler - Version 1.0\n");
printf("Usage: newrpl-comp [-c] [-o <outputfile>] <filename.nrpl>\n");
printf("\nOptions:\n");
printf("\t\t-c\tOutput will be as C source code.\n");
printf("\t\t-o <file>\tSpecify a output file name (defaults to filename.c or filename.binrpl)\n\n\n");
return 0;
}
int argidx = 1;
int outputtype = OUTPUT_BINARY;
int needoutputname = 0;
int needcleanup = 0;
char *outputfile = NULL;
char *inputfile = NULL;
while(argidx < argc) {
if(needoutputname) {
outputfile = argv[argidx];
needoutputname = 0;
}
else if((argv[argidx][0] == '-') && (argv[argidx][1] == 'c')
&& (argv[argidx][2] == 0))
outputtype = OUTPUT_C;
else if((argv[argidx][0] == '-') && (argv[argidx][1] == 'o')) {
if(argv[argidx][2] == 0)
needoutputname = 1;
else
outputfile = argv[argidx] + 2;
}
else
inputfile = argv[argidx];
++argidx;
}
// HERE WE HAVE ALL ARGUMENTS PROCESSED
if(!inputfile) {
fprintf(stderr, "Error: No input file\n");
return 1;
}
if(!outputfile) {
// CREATE AN OUTPUT FILE NAME FROM THE INPUT FILE
char *end = inputfile + strlen(inputfile) - 1;
while((end > inputfile) && (*end != '.') && (*end != '/')
&& (*end != '\\'))
--end;
if(end <= inputfile)
end = inputfile + strlen(inputfile);
else if(*end != '.')
end = inputfile + strlen(inputfile);
needcleanup++;
outputfile = malloc(end - inputfile + 10);
if(!outputfile) {
fprintf(stderr, "error: Memory allocation error\n");
return 1;
}
memmove(outputfile, inputfile, end - inputfile);
strcpy(outputfile + (end - inputfile),
(outputtype == OUTPUT_C) ? ".c" : ".binrpl");
}
// READ THE INPUT FILE INTO A BUFFER
FILE *f = fopen(inputfile, "rb");
if(f == NULL) {
fprintf(stderr, "error: File not found %s\n", inputfile);
if(needcleanup)
free(outputfile);
return 1;
}
fseek(f, 0, SEEK_END);
long long length = ftell(f);
fseek(f, 0, SEEK_SET);
mainbuffer = malloc(length);
if(!mainbuffer) {
fprintf(stderr, "error: Memory allocation error\n");
if(needcleanup)
free(outputfile);
return 1;
}
if(fread(mainbuffer, 1, length, f) != (size_t)length) {
fprintf(stderr, "error: Can't read from input file\n");
if(needcleanup)
free(outputfile);
free(mainbuffer);
return 1;
}
fclose(f);
// HERE WE HAVE THE MAIN FILE
rplInitMemoryAllocator();
rplInit();
rplSetSystemFlag(FL_STRIPCOMMENTS);
rplInstallLibrary(lib4079_handler);
// IDENTIFY CHUNKS OF CODE
char *chunk = mainbuffer;
int numchunks = 0;
char *chunkstart[65537]; // MAXIMUM NUMBER OF VARIABLES IN A SINGLE FILE
while(chunk - mainbuffer < length) {
if(!utf8ncmp2(chunk, mainbuffer + length, "@#name", 6)) {
// FOUND START OF CHUNK
chunkstart[numchunks] = chunk;
++numchunks;
if(numchunks > 65535) {
fprintf(stderr, "error: Too many chunks in same file.\n");
if(needcleanup)
free(outputfile);
free(mainbuffer);
return 1;
}
}
//SKIP TO THE NEXT LINE
while((*chunk != '\n') && (*chunk != '\r')
&& (chunk - mainbuffer < length))
++chunk;
while(((*chunk == '\n') || (*chunk == '\r'))
&& (chunk - mainbuffer < length))
++chunk;
}
if(numchunks == 0) {
chunkstart[numchunks] = mainbuffer;
++numchunks;
}
chunkstart[numchunks] = chunk;
f = fopen(outputfile, "wb");
if(f == NULL) {
fprintf(stderr, "error: Can't open %s for writing.\n", outputfile);
if(needcleanup)
free(outputfile);
free(mainbuffer);
return 1;
}
if(outputtype == OUTPUT_BINARY) {
// WRITE THE BINARY FILE MARKER
WORD marker[3] = {
MKPROLOG(HEXBINT, 2), // PROLOG OF A 64-BIT BINT
0x4c50526e, // STRING "nRPL"
1 // VERSION OF THE newRPL BINARY FORMAT
};
fwrite(marker, 4, 3, f);
}
else {
fprintf(f, "// newRPL binary version 1.0\n\n");
fprintf(f, "#include \"libraries.h\"\n\n");
}
// COMPILE ALL CHUNKS
int k;
char *start, *end;
for(k = 0; k < numchunks; ++k) {
start = chunkstart[k];
end = chunkstart[k + 1];
if(!utf8ncmp2(start, end, "@#name", 6)) {
// SKIP TO THE NEXT LINE FOR THE REAL DATA
while((*start != '\n') && (*start != '\r') && (start < end))
++start;
while(((*start == '\n') || (*start == '\r')) && (start < end))
++start;
}
if(end > start) {
WORDPTR newobject = rplCompile((BYTEPTR) start, end - start, 1);
if(Exceptions) {
compShowErrorMsg(inputfile, mainbuffer, stderr);
fclose(f);
remove(outputfile);
if(needcleanup)
free(outputfile);
free(mainbuffer);
return 1;
}
// OUTPUT THE CHUNK
if(outputtype == OUTPUT_C) {
if(rplObjSize(newobject) > 2) {
// OUTPUT C FORMATTED CODE
char *objname;
char *nameend;
if(!utf8ncmp2(chunkstart[k], chunkstart[k + 1], "@#name",
6)) {
objname = chunkstart[k] + 6;
while((*objname == ' ') || (*objname == '\t'))
++objname;
nameend = objname;
while((*nameend != '\n') && (*nameend != '\r')
&& (*nameend != ' ') && (*nameend != '\t'))
++nameend;
}
else {
nameend = objname = NULL;
}
fprintf(f, "ROMOBJECT ");
if(nameend <= objname)
fprintf(f, "chunk%05d", k + 1);
else
fwrite(objname, 1, nameend - objname, f);
fprintf(f, "[]= {\n");
WORDPTR p = newobject + 1, endp = rplSkipOb(newobject) - 1;
int wordcount = 0;
while(p < endp) {
if(LIBNUM(*p) == 4079) {
// THIS IS A PSEUDO-OBJECT, NEEDS TO BE REPLACED WITH TEXT
int textoffset;
int givenwords, storedwords;
if(ISPROLOG(*p)) {
textoffset = p[1];
storedwords = OBJSIZE(*p) + 1;
}
else {
textoffset = OBJSIZE(*p);
storedwords = 1;
}
if(textoffset > 0) {
char *foundtext = end - textoffset, *endtext;
if(foundtext >= start) {
// IT'S A VALID POINTER INTO THE TEXT!
// FIND THE END OF THE TEXT
givenwords = 1;
endtext = foundtext;
while(endtext < end) {
if(*endtext == ',')
++givenwords;
if(*endtext == ' ')
break;
if(*endtext == '\t')
break;
if(*endtext == '\n')
break;
if(*endtext == '\r')
break;
++endtext;
}
// REMOVED THIS CHECK TO ALLOW FOR C MACROS THAT EXPAND TO MORE THAN ONE WORD
//if(givenwords==storedwords) {
// IT'S A VALID SPECIAL OBJECT
fwrite(foundtext, 1, endtext - foundtext,
f);
p += storedwords;
if(p != endp)
fprintf(f, ",");
if((wordcount & 7) + storedwords > 7)
fprintf(f, "\n");
wordcount += storedwords;
continue;
//}
}
rplError(ERR_SYNTAXERROR);
TokenStart = (WORDPTR) foundtext;
compShowErrorMsg(inputfile, mainbuffer, stderr);
}
// IF IT FALLS THROUGH, THEN IT'S AN INVALID SPECIAL SEQUENCE
// JUST CONTINUE NORMALLY, AS IT COULD BE RANDOM DATA
}
fprintf(f, "0x%08X", *p);
if(p != endp - 1)
fprintf(f, ",");
wordcount++;
if((wordcount & 7) == 0)
fprintf(f, "\n");
++p;
}
if((wordcount & 7) != 0)
fprintf(f, "\n");
fprintf(f, "};\n\n\n");
}
}
else {
if(rplObjSize(newobject) > 2) {
// RAW BINARY OUTPUT
fwrite(newobject + 1, 4, rplObjSize(newobject) - 2, f);
}
}
}
// AND MOVE ON TO THE NEXT ONE
}
// CLOSE THE OUTPUT FILE
fclose(f);
return 0;
}
void usb_mutex_lock_implementation(void)
{}
void usb_mutex_unlock_implementation(void)
{}