mirror of
https://git.code.sf.net/p/newrpl/sources
synced 2024-11-16 19:51:25 +01:00
13e277fab9
Removing unneeded includes and adding needed includes to make headers self contained. Decimating double and degraded type definitions. Added missing variables to position dependent block. Conditional inclusion of headers to reduce, albeit not prevent, recursive inclusion of open files.
448 lines
14 KiB
C
448 lines
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 "cmdcodes.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 \"cmdcodes.h\"\n");
|
|
fprintf(f, "#include \"libraries.h\"\n");
|
|
fprintf(f, "#include \"newrpl.h\"\n");
|
|
fprintf(f, "#include \"firmware.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)
|
|
{}
|