mirror of
https://git.code.sf.net/p/newrpl/sources
synced 2024-11-16 19:51:25 +01:00
9c8e6da348
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.
444 lines
No EOL
14 KiB
C
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)
|
|
{} |