From 0b03fc66c198e21a8e310bbb8a5f540e4906e631 Mon Sep 17 00:00:00 2001 From: Zezombye Date: Wed, 28 Dec 2016 18:57:39 +0100 Subject: [PATCH] test --- B2C/.classpath | 6 + B2C/.gitignore | 1 + B2C/.project | 17 + .../org.eclipse.core.resources.prefs | 2 + B2C/.settings/org.eclipse.jdt.core.prefs | 11 + B2C/src/AddinInfo.txt | 12 + B2C/src/B2CFunctions.c | 611 ++++++++ B2C/src/Default.g1w | 17 + B2C/src/MainIcon.bmp | Bin 0 -> 138 bytes B2C/src/MonochromeLib.c | 1289 +++++++++++++++++ B2C/src/MonochromeLib.h | 151 ++ B2C/src/b2c/B2C.java | 214 +++ B2C/src/b2c/Constants.java | 72 + B2C/src/b2c/Functions.java | 203 +++ B2C/src/b2c/G1MParser.java | 67 + B2C/src/b2c/Header.java | 56 + B2C/src/b2c/IO.java | 90 ++ B2C/src/b2c/Parser.java | 1032 +++++++++++++ B2C/src/b2c/Syscalls.java | 40 + B2C/src/memory.c | 291 ++++ B2C/src/memory.h | 42 + 21 files changed, 4224 insertions(+) create mode 100644 B2C/.classpath create mode 100644 B2C/.gitignore create mode 100644 B2C/.project create mode 100644 B2C/.settings/org.eclipse.core.resources.prefs create mode 100644 B2C/.settings/org.eclipse.jdt.core.prefs create mode 100644 B2C/src/AddinInfo.txt create mode 100644 B2C/src/B2CFunctions.c create mode 100644 B2C/src/Default.g1w create mode 100644 B2C/src/MainIcon.bmp create mode 100644 B2C/src/MonochromeLib.c create mode 100644 B2C/src/MonochromeLib.h create mode 100644 B2C/src/b2c/B2C.java create mode 100644 B2C/src/b2c/Constants.java create mode 100644 B2C/src/b2c/Functions.java create mode 100644 B2C/src/b2c/G1MParser.java create mode 100644 B2C/src/b2c/Header.java create mode 100644 B2C/src/b2c/IO.java create mode 100644 B2C/src/b2c/Parser.java create mode 100644 B2C/src/b2c/Syscalls.java create mode 100644 B2C/src/memory.c create mode 100644 B2C/src/memory.h diff --git a/B2C/.classpath b/B2C/.classpath new file mode 100644 index 0000000..63b7e89 --- /dev/null +++ b/B2C/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/B2C/.gitignore b/B2C/.gitignore new file mode 100644 index 0000000..ae3c172 --- /dev/null +++ b/B2C/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/B2C/.project b/B2C/.project new file mode 100644 index 0000000..792c5e8 --- /dev/null +++ b/B2C/.project @@ -0,0 +1,17 @@ + + + B2C + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/B2C/.settings/org.eclipse.core.resources.prefs b/B2C/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..60e1369 --- /dev/null +++ b/B2C/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//src/b2c/B2C.java=UTF-8 diff --git a/B2C/.settings/org.eclipse.jdt.core.prefs b/B2C/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 0000000..bb35fa0 --- /dev/null +++ b/B2C/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,11 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/B2C/src/AddinInfo.txt b/B2C/src/AddinInfo.txt new file mode 100644 index 0000000..4827715 --- /dev/null +++ b/B2C/src/AddinInfo.txt @@ -0,0 +1,12 @@ +//------------------------------------------------------------------ +// Addin-Application header control file, created with the CASIO SDK +//------------------------------------------------------------------ +[OUTPUT] : "%PROG_NAME%.G1A" +[BINDATA] : "FXADDINror.bin" +[DISPNAME] : "%PROG_NAME%" +[APPNAME] : "@%PROG_NAME%" +[VERSION] : "01.00.0000" +[APL_ICON] : "MainIcon.bmp" +[MODULE_NUM] : 0 +[MOD1_TITLE] : "%PROG_NAME%" +[MOD1_ICON] : "eActivityIcon.bmp" diff --git a/B2C/src/B2CFunctions.c b/B2C/src/B2CFunctions.c new file mode 100644 index 0000000..c752323 --- /dev/null +++ b/B2C/src/B2CFunctions.c @@ -0,0 +1,611 @@ +BCDvar *B2C_add(BCDvar *buffer, BCDvar *a, BCDvar *b) { + int expA, expB, expDiff, carry = 0, tempadd, biggerExp_int; + unsigned char tempByte = 0; + int result[15] = {0}; + BCDvar *smallerExp, *biggerExp; + + //Determine if these numbers are negative + //If both are negative, add their opposites + //Ex: (-4)+(-3) -> -(4+3) + if ((*a)[0] > 0x30 && (*b)[0] > 0x30) { + BCDvar a2,b2; + memcpy(a2, *a, 9); + memcpy(b2, *b, 9); + a2[0] -= 0x50; + b2[0] -= 0x50; + B2C_add(buffer, &a2, &b2); + (*buffer)[0] += 0x50; + return buffer; + } + //If one of them is negative, substract them + //Ex: (-4)+3 -> 3-4 + if ((*a)[0] > 0x30) { + BCDvar a2; + memcpy(a2, *a, 9); + a2[0] -= 0x50; + return B2C_sub(buffer, b, &a2); + } + if ((*b)[0] > 0x30) { + BCDvar b2; + memcpy(b2, *b, 9); + b2[0] -= 0x50; + return B2C_sub(buffer, a, &b2); + } + + //First determine which number has a bigger exponent + expA = ((*a)[0]>>4) * 100 + ((*a)[0]&0x0F) * 10 + ((*a)[1]>>4) - 100; + expB = ((*b)[0]>>4) * 100 + ((*b)[0]&0x0F) * 10 + ((*b)[1]>>4) - 100; + if (expA > expB) { + smallerExp = b; + biggerExp = a; + expDiff = expA-expB; + biggerExp_int = expA; + } else { + smallerExp = a; + biggerExp = b; + expDiff = expB-expA; + biggerExp_int = expB; + } + + //Add the number with the smallest exponent to the one with the biggest + for (i = 14; i >= 0; i--) { + tempadd = 0; + if (i >= expDiff) tempadd += getDigit(smallerExp, i-expDiff); + tempadd += getDigit(biggerExp, i) + carry; + if (tempadd >= 10) { + result[i] = tempadd-10; + carry = 1; + } else { + result[i] = tempadd; + carry = 0; + } + //locate(i+1, 3); printChar(carry+'0'); + //locate(i+1, 4); printChar(tempadd+'0'); + } + //Increment exponent if necessary + if (carry == 1) { + biggerExp_int++; + } + biggerExp_int += 100; + //locate(1,6); printChar(biggerExp_int); + //locate(3,6); printChar(expA+'0'); + //locate(5,6); printChar(expB+'0'); + //Put exponent in buffer + (*buffer)[0] = (biggerExp_int/100 << 4) + (biggerExp_int%100)/10; + tempByte = (biggerExp_int%10 << 4) + carry; + if (carry == 1) { + (*buffer)[1] = tempByte; + } + //Put result in buffer + for (i=0; i < 15-carry; i++) { + if ((i+carry)%2) { + tempByte = result[i] << 4; + + } else { + (*buffer)[(i+carry+1)/2+1] = tempByte + result[i]; + + } + } + //locate(1,2); printBCDvarBytes(buffer); + //locate(1,1); + return buffer; +} + + +BCDvar *B2C_sub(BCDvar *buffer, BCDvar *a, BCDvar *b) { +//Substract a positive number B from a positive number A (A-B). +//A must be greater than B for the algorithm to function. +//However this function does the necessary checks so A and B can be any reals. + int expA, expB, expDiff, carry = 0, tempsub; + unsigned char tempByte; + int result[15] = {0}; + //Check for special cases + //a > 0 and b < 0 -> a+(-b) + //Ex: 3-(-4) -> 3+4 + if ((*a)[0] < 0x30 && (*b)[0] > 0x30) { + BCDvar b2; + memcpy(b2, b, 9); + b2[0] -= 0x50; + return B2C_add(buffer, a, &b2); + } + //a < 0 and b > 0 -> -(a+b) + //Ex: (-4)-3 -> -(4+3) + if ((*a)[0] > 0x30 && (*b)[0] < 0x30) { + BCDvar a2; + memcpy(a2, a, 9); + a2[0] -= 0x50; + B2C_add(buffer, &a2, b); + (*buffer)[0] += 0x50; + return buffer; + } + //a < 0 and b < 0 -> b-a + //Ex: (-4)-(-3) -> 3-4 + if ((*a)[0] > 0x30 && (*b)[0] > 0x30) { + BCDvar a2, b2; + memcpy(a2, a, 9); + memcpy(b2, b, 9); + a2[0] -= 0x50; + b2[0] -= 0x50; + return B2C_sub(buffer, &a2, &b2); + } + //if a < b sub b-a + if (B2C_greaterThan(b, a)) { + return B2C_sub(buffer, b, a); + } + + //Determine the exponent difference; A is always the biggest number + expA = ((*a)[0]>>4) * 100 + ((*a)[0]&0x0F) * 10 + ((*a)[1]>>4); + expB = ((*b)[0]>>4) * 100 + ((*b)[0]&0x0F) * 10 + ((*b)[1]>>4); + expDiff = expA-expB; + + //Substract + for (i = 14; i >= 0; i--) { + tempsub = getDigit(a, i) - carry; + if (i >= expDiff) tempsub -= getDigit(b, i-expDiff); + if (tempsub < 0) { + tempsub += 10; + carry = 1; + } else { + carry = 0; + } + result[i] = tempsub; + } + + //Determine new exponent, reuse the var expA and expDiff + //For example: 34-32 (3.4e1 - 3.2e1) will yield 2 (0.2e1) which must be converted to 2e0 + for (i = 0; result[i] == 0 && i < 15; i++) { + expA--; + } + expDiff = i; + + //Put exponent in buffer + (*buffer)[0] = (expA/100 << 4) + (expA%100)/10; + tempByte = (expA%10 << 4); + + //Put result in buffer + for (i = 0; i < 15; i++) { + if (i%2) { + tempByte = (i < 15-expDiff ? result[i+expDiff] << 4 : 0); + } else { + (*buffer)[(i+1)/2+1] = tempByte + (i < 15-expDiff ? result[i+expDiff] : 0); + } + } + + return buffer; + +} + +int B2C_greaterThan(BCDvar *a, BCDvar *b) { + return FALSE; +} + +BCDvar *B2C_not(BCDvar *a) { + if ((*a)[1]) + return &_0_; + return &_1_; +} +unsigned char* B2C_convToStr(BCDvar *nb) { + bcdToStr(nb, stringBuffer); + return stringBuffer; +} +void B2C_setListRow(unsigned int nbList, unsigned int row, BCDvar *value) { + //TODO: handle complex numbers + unsigned short nbElements = 0; + char listName[] = "0LIST\0\0"; + listName[0] = getSetupEntry(SETUP_LISTFILE) + '0'; + if (nbList >= 10) { + listName[5] = nbList/10 + '0'; + listName[6] = nbList%10 + '0'; + } else { + listName[5] = nbList + '0'; + } + //Three possible cases: the list exists and the row isn't a new one, list exists and the row + //has to be added, list doesn't exist and has to be created + + //First case: list has to be created + if (getItemData("main", listName, 8, 2, &nbElements)) { //most likely an error "file does not exist" - it can be another error but doing checks is time consuming + unsigned char listContent[28] = {0,0,0,0,0,0,0,0, 0,1, 0,0,0,0,0,0}; + memcpy(listContent+16, value, 12); + putInternalItem(DIR_LIST, listName, 28, listContent); + } else { + //Second case: row has to be added + if (row > nbElements) { + //char str[2] = {0}; + unsigned short existingListElements; + unsigned int existingListLength; + unsigned char* buffer; + getItemSize("main", listName, &existingListLength); + buffer = calloc(existingListLength+12, 1); + + //Copy existing list data + getItemData("main", listName, 0, existingListLength, buffer); + + //Increase number of elements + memcpy(buffer+8, &existingListElements, 2); + existingListElements++; + memcpy(&existingListElements, buffer+8, 2); + + //Put the new value in the buffer + memcpy(buffer+existingListLength, value, 12); + deleteInternalItem(DIR_LIST, listName); + putInternalItem(DIR_LIST, listName, existingListLength+12, buffer); + free(buffer); + + } else if (1) { + overwriteItemData("main", listName, 12, value, 4+12*row); + + //DO NOT REMOVE THIS CONDITION OR ANYTHING INSIDE IT; THE DEMON INSIDE THIS FUNCTION WILL NOT APPROVE + } else { + locate(1,6); + Print("test"); + locate(23,2); + Print(" "); + } + } +} +void B2C_setDimList(unsigned int nbList, unsigned short nbElements) { + unsigned char* content = calloc(12*nbElements+LIST_START, 1); + char listName[] = "0LIST\0\0"; + listName[0] = getSetupEntry(SETUP_LISTFILE) + '0'; + if (nbList >= 10) { + listName[5] = nbList/10 + '0'; + listName[6] = nbList%10 + '0'; + } else { + listName[5] = nbList + '0'; + } + content[8] = nbElements>>8; + content[9] = nbElements&0xFF; + deleteInternalItem(DIR_LIST, listName); + putInternalItem(DIR_LIST, listName, 12*nbElements+LIST_START, content); + free(content); +} +/* +List B2C_newList(int nbElements, ...) { + List list; + va_list vaList; + list.nbElements = nbElements; + list.data = calloc(nbElements+1, sizeof(BCDvar)); + va_start(vaList, nbElements); + list.data[0] = _0_; + for (i = 1; i <= nbElements; i++) { + list.data[i] = va_arg(vaList, BCDvar); + } + va_end(vaList); + return list; +} +*/ +void B2C_setDimMat(unsigned char matrix, unsigned short y, unsigned short x) { + unsigned char* content = calloc(12*y*x + MAT_START, 1); + char matName[] = "MAT_ \0\0"; + matName[4] = matrix; + memcpy(content+8, &y, 2); + memcpy(content+10, &x, 2); + deleteInternalItem(DIR_MAT, matName); + putInternalItem(DIR_MAT, matName, 12*y*x+MAT_START, content); + free(content); +} +void B2C_setMat(unsigned char matrix, unsigned int y, unsigned int x, BCDvar *value) { + char matName[] = "MAT_ \0\0"; + unsigned short matWidth; + matName[4] = matrix; + getItemData("main", matName, 10, 2, &matWidth); + overwriteItemData("main", matName, 12, value, MAT_START+12*((y-1)*matWidth+(x-1))); +} +unsigned int B2C_convToUInt(BCDvar *nb) { + unsigned int result = 0; + //gets the 3rd digit of the exponent - that means it doesn't work for Uints > 10^10 + //however this function is intended for locate, matrixes, lists, etc so it isn't needed + int power = ((*nb)[1]>>4) + 1; + for (i = 1; i <= power; i++) { + if (i%2) { + result += ((*nb)[i/2+1]&0xF) * pow(10, power-i); + } else { + result += ((*nb)[i/2+1]>>4) * pow(10, power-i); + } + } + return result; +} +int B2C_convToInt(BCDvar *nb) { + //(almost) copy of B2C_convToUInt, any changes made here must be reflected in the other function + int result = 0; + int power = ((*nb)[1]>>4) + 1; + for (i = 1; i <= power; i++) { + if (i%2) { + result += ((*nb)[i/2+1]&0xF) * pow(10, power-i); + } else { + result += ((*nb)[i/2+1]>>4) * pow(10, power-i); + } + } + if ((*nb)[0] > 0x30) { //exponent is higher than 300 so number is negative + result = -result; + } + return result; +} +BCDvar *B2C_Getkey() { + if (!prgmGetkey(&getkeyBuffer)) { + B2C_exit(NO_ERROR); + } + return &getkeyBuffer; +} +#ifdef USES_INTERRUPTION_TIMER +void exitTimerHandler() { + /*short menuCode = 0x0308; + putMatrixCode(&menuCode);*/ + if (IsKeyDown(KEY_CTRL_AC)) { + KillTimer(INTERRUPTION_TIMER); + B2C_exit(NO_ERROR); + } else { + SetTimer(INTERRUPTION_TIMER, 50, exitTimerHandler); + } +} +#endif +void B2C_exit(int exitCode) { + /*installTimer(6, (void*)&timerHandler, 1); + startTimer(6); + GetKey(&key); + uninstallTimer(6);*/ + short menuCode = 0x0308; + PopUpWin(4); + + switch(exitCode) { + case NO_ERROR: + locate(5,3); Print((unsigned char*)"Interruption"); + break; + case MEMORY_ERROR: + locate(4,3); Print((unsigned char*)"Erreur m""\xE6""\x0A""moire"); + break; + } + locate(4,5); Print((unsigned char*)"Appuyer:[EXIT]"); + while (1) { + putMatrixCode(&menuCode); + do { + GetKey(&key); + } while (key != KEY_CTRL_EXIT); + } +} + +BCDvar *B2C_ranInt(BCDvar *a, BCDvar *b) { + return &_1_; + /*BCDvar result; + //A + Int (Ran# * (B - A + 1)) + const char *function = "A""\x89""\xA6""(""\xC1""\xA9""(B""\x99""A""\x89""1))"; + setAlphaVar('A', &a); + setAlphaVar('B', &b); + calcExp(&function, dummyOpCode, &result, 1); + return result;*/ +} + +BCDvar *B2C_getAlphaVar(unsigned char var) { + getAlphaVar(var, alphaVarBuffer); + return &alphaVarBuffer; +} + +BCDvar *B2C_calcExp(unsigned char* exp) { + calcExp(&exp, dummyOpCode, &expressionBuffer, 1); + return &expressionBuffer; +} +void B2C_setAlphaVar(unsigned char var, BCDvar *value) { + setAlphaVar(var, *value); +} +void B2C_setStr(Str *value, int isString, int strNum) { + free(strings[strNum].data); + strings[strNum].length = value->length; + strings[strNum].data = malloc((value->length+2)*2); + strings[strNum].data[(value->length+1)*2] = 0x00; + memcpy(strings[strNum].data + 2, value->data + 2, value->length * 2); + free_str(value); +} +unsigned char* B2C_strToCharArray(Str *str, int isString) { + int j = 0; + //Initialize the buffer + memset(stringBuffer, 0x00, 256); + //Goes through the string, starting at 2 + for (i = 2; i <= (str->length+1) * 2; i++) { + //Skip null bytes + if (str->data[i]) { + stringBuffer[j] = str->data[i]; + j++; + } + } + free_str(str); + return stringBuffer; +} +Str *B2C_charArrayToStr(unsigned char* charArray) { + int strPos = 2; + Str *result = malloc(sizeof(Str)); + result->data = calloc(strlen(charArray)+1, 2); + result->length = 0; + for (i = 0; charArray[i]; i++) { + if (!(strPos%2) && + charArray[i] != 0xE5 && + charArray[i] != 0xE6 && + charArray[i] != 0xE7 && + charArray[i] != 0xF7 && + charArray[i] != 0xF9 && + charArray[i] != 0x7F) { + strPos++; + } + result->data[strPos] = charArray[i]; + strPos++; + } + result->length = (strPos-2)/2; + return result; +} +BCDvar *B2C_strCmp(Str *str1, Str *str2, int isString1, int isString2) { + unsigned char str_1[256] = {0}, str_2[256] = {0}; + int j = 0, isString; + //Can't use strToCharArray because the buffer can't be used twice + for (i = 2; i <= (str1->length+1) * 2; i++) { + //Skip null bytes + if (str1->data[i]) { + str_1[j] = str1->data[i]; + j++; + } + } + for (i = 2; i <= (str2->length+1) * 2; i++) { + //Skip null bytes + if (str2->data[i]) { + str_2[j] = str2->data[i]; + j++; + } + } + isString = isString1; + //Can't use strcmp() because it must return -1, 0 or 1 + //so just implement strcmp while adapting free_str to free both str1 and str2 + for (i = 0; str_1[i] || str_2[i]; i++) { + if (str_1[i] < str_2[i]) { + free_str(str1); + isString = isString2; + free_str(str2); + return &__1_; + } else if (str_1[i] > str_2[i]) { + free_str(str1); + isString = isString2; + free_str(str2); + return &_1_; + } + } + free_str(str1); + isString = isString2; + free_str(str2); + return &_0_; +} +Str *B2C_strInv(Str *str, int isString) { + Str *result = malloc(sizeof(Str)); + result->data = malloc(2*(str->length+1)); + result->length = str->length; + for (i = 2*str->length; i >= 2; i -= 2) { + memcpy(result->data + 2*str->length-i, str->data + i, 2); + } + free_str(str); + return result; +} +Str *B2C_strJoin(Str *str1, Str *str2, int isString1, int isString2) { + int isString = isString1; + Str *result = malloc(sizeof(Str)); + result->data = malloc(2*(str1->length + str2->length + 1)); + result->length = str1->length + str2->length; + memcpy(result->data + 2, str1->data + 2, str1->length * 2); + memcpy(result->data + 2 + str1->length * 2, str2->data + 2, str2->length * 2); + free_str(str1); + isString = isString2; + free_str(str2); + return result; +} +BCDvar *B2C_strLen(Str *str, int isString) { + unsigned char length[4] = {0}; + BCDvar *result; + sprintf(length, "%d", str->length); + result = B2C_calcExp(length); + free_str(str); + return result; +} +Str *B2C_strMid(Str *str, int isString, int start, int offset) { + Str *result = malloc(sizeof(Str)); + if (!offset) { + offset = str->length-start; + } + result->data = malloc((offset+2) * 2); + //Set null byte at the end + result->data[(offset+1) * 2] = 0x00; + result->length = offset; + //Copy the substring + memcpy(result->data + 2, str->data + start*2, 2*offset); + free_str(str); + return result; +} +Str *B2C_charAt(Str *str, int isString, int charPos) { + Str *result = malloc(sizeof(Str)); + result->data = malloc(3*2); + result->data[2*2] = 0x00; + result->length = 1; + memcpy(result->data+2, str->data+charPos*2, 2); + free_str(str); + return result; +} +Str *B2C_strUpr(Str *str, int isString) { + Str *result = malloc(sizeof(Str)); + unsigned short currentChar; + result->data = malloc((str->length+2) * 2); + result->data[str->length+1] = 0x00; + memcpy(result->data+2, str->data+2, str->length * 2); + result->length = str->length; + for (i = 3; i <= result->length*2; i+=2) { + if (result->data[i] >= 'a' && result->data[i] <= 'z') { + result->data[i] -= 32; + } + } + free_str(str); + return result; +} +Str *B2C_strLwr(Str *str, int isString) { //(almost) copy of B2C_strUpr - any changes made here must be reflected in strUpr + Str *result = malloc(sizeof(Str)); + unsigned short currentChar; + result->data = malloc((str->length+2) * 2); + result->data[str->length+1] = 0x00; + memcpy(result->data+2, str->data+2, str->length * 2); + result->length = str->length; + for (i = 3; i <= result->length*2; i+=2) { + if (result->data[i] >= 'A' && result->data[i] <= 'Z') { + result->data[i] += 32; + } + } + free_str(str); + return result; +} +Str *B2C_strRight(Str *str, int isString, int offset) { + Str *result = malloc(sizeof(Str)); + + result->data = malloc((offset+2)*2); + result->data[(offset+1)*2] = 0x00; + result->length = offset; + memcpy(result->data+2, str->data + (str->length - offset + 1)*2, offset * 2); + free_str(str); + return result; +} +Str *B2C_strLeft(Str *str, int isString, int offset) { + Str *result = malloc(sizeof(Str)); + result->data = malloc((offset+2)*2); + result->data[(offset+1)*2] = 0x00; + result->length = offset; + memcpy(result->data+2, str->data + 2, offset * 2); + free_str(str); + return result; +} +Str *B2C_strRotate(Str *str, int isString, int offset) { + Str *result = malloc(sizeof(Str)); + result->length = str->length; + result->data = malloc((str->length+1)*2); + offset %= str->length; + if (offset > 0) { + memcpy(result->data+2, str->data+2+2*offset, (str->length-offset)*2); + memcpy(result->data+2+2*(str->length-offset), str->data+2, offset*2); + } else { + memcpy(result->data+2, str->data+2+2*(str->length+offset), -offset*2); + memcpy(result->data+2+2*-offset, str->data+2, (str->length+offset)*2); + } + free_str(str); + return result; +} + +//Debug function; is not used with converted programs +void printBCDvarBytes(BCDvar *var) { + unsigned char str[2] = {0}; + for (i = 0; i < 18; i++) { + if (i%2) { + str[0] = '0'+((*var)[i/2]&0x0F); + } else { + str[0] = '0'+((*var)[i/2]>>4); + } + if (str[0] > '9') { + str[0] += 'A'-'9'-1; + } + Print(str); + } +} + +void printChar(unsigned char c) { + unsigned char str[2] = {0}; + str[0] = c; + Print(str); +} \ No newline at end of file diff --git a/B2C/src/Default.g1w b/B2C/src/Default.g1w new file mode 100644 index 0000000..24f16f8 --- /dev/null +++ b/B2C/src/Default.g1w @@ -0,0 +1,17 @@ +[DLSimProject] +Name=%PROG_NAME% +Version=1.00.0000 +Model=:fx-9860G.dlm +SourcePath=SRC +MemoryPath=INIT +MemCardPath=SDCard + +[Program1] +Program=%PROG_NAME%.G1A +Debug=Debug\FXADDINror.dbg +LoadAddress=80000000:90100000 + +[Files] +SourceFile=:main.c +SourceFile=:MonochromeLib.c +SourceFile=:syscalls.src diff --git a/B2C/src/MainIcon.bmp b/B2C/src/MainIcon.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f5244f44942695a0683eaf15e737ecc6723860d4 GIT binary patch literal 138 zcmZ?r?P7ocJ0PV2#Bx9^48)8;2m(G}5|jA<|33o||Clwc=Eth5w|~r-`ufMJt+#*7 z1@b}SjR$Nj_PzgoV}JSgAN#An|Je8U`;W$dK>C0AkNxr6!Fb>M>Klz8{#XFj{{aB% C^gzS_ literal 0 HcmV?d00001 diff --git a/B2C/src/MonochromeLib.c b/B2C/src/MonochromeLib.c new file mode 100644 index 0000000..9b753c8 --- /dev/null +++ b/B2C/src/MonochromeLib.c @@ -0,0 +1,1289 @@ +/*************************************************************/ +/** MonochromeLib - monochrome graphic library for fx-9860G **/ +/** MonochromeLib is free software **/ +/** **/ +/** @author Pierre "PierrotLL" Le Gall **/ +/** @contact legallpierre89@gmail.com **/ +/** **/ +/** @file MonochromeLib.c **/ +/** Code file of MonochromeLib **/ +/** **/ +/** @date 11-22-2011 **/ +/*************************************************************/ + +#include "MonochromeLib.h" +#include + + +/******************************/ +/** Dependencies management **/ +/******************************/ + +#ifdef ML_ALL + #define ML_CLEAR_VRAM + #define ML_CLEAR_SCREEN + #define ML_DISPLAY_VRAM + #define ML_SET_CONTRAST + #define ML_GET_CONTRAST + #define ML_PIXEL + #define ML_POINT + #define ML_PIXEL_TEST + #define ML_LINE + #define ML_HORIZONTAL_LINE + #define ML_VERTICAL_LINE + #define ML_RECTANGLE + #define ML_POLYGON + #define ML_FILLED_POLYGON + #define ML_CIRCLE + #define ML_FILLED_CIRCLE + #define ML_ELLIPSE + #define ML_ELLIPSE_IN_RECT + #define ML_FILLED_ELLIPSE + #define ML_FILLED_ELLIPSE_IN_RECT + #define ML_HORIZONTAL_SCROLL + #define ML_VERTICAL_SCROLL + #define ML_BMP_OR + #define ML_BMP_AND + #define ML_BMP_XOR + #define ML_BMP_OR_CL + #define ML_BMP_AND_CL + #define ML_BMP_XOR_CL + #define ML_BMP_8_OR + #define ML_BMP_8_AND + #define ML_BMP_8_XOR + #define ML_BMP_8_OR_CL + #define ML_BMP_8_AND_CL + #define ML_BMP_8_XOR_CL + #define ML_BMP_16_OR + #define ML_BMP_16_AND + #define ML_BMP_16_XOR + #define ML_BMP_16_OR_CL + #define ML_BMP_16_AND_CL + #define ML_BMP_16_XOR_CL +#endif + +#ifdef ML_POLYGON + #define ML_LINE +#endif + +#ifdef ML_LINE + #define ML_PIXEL +#endif + +#ifdef ML_POINT + #define ML_PIXEL + #define ML_RECTANGLE +#endif + +#ifdef ML_RECTANGLE + #define ML_HORIZONTAL_LINE +#endif + +#ifdef ML_FILLED_POLYGON + #define ML_HORIZONTAL_LINE +#endif + +#ifdef ML_CIRCLE + #define ML_PIXEL +#endif + +#ifdef ML_FILLED_CIRCLE + #define ML_HORIZONTAL_LINE +#endif + +#ifdef ML_ELLIPSE_IN_RECT + #define ML_ELLIPSE +#endif + +#ifdef ML_ELLIPSE + #define ML_PIXEL +#endif + +#ifdef ML_FILLED_ELLIPSE_IN_RECT + #define ML_FILLED_ELLIPSE +#endif + +#ifdef ML_FILLED_ELLIPSE + #define ML_HORIZONTAL_LINE +#endif + + +/***************/ +/** Functions **/ +/***************/ + +#define sgn(x) (x<0?-1:1) +#define rnd(x) ((int)(x+0.5)) + +//Thanks to Simon Lothar for this function +static int SysCallCode[] = {0xD201422B,0x60F20000,0x80010070}; +static int (*SysCall)( int R4, int R5, int R6, int R7, int FNo ) = (void*)&SysCallCode; +char* ML_vram_adress() +{ + return (char*)((*SysCall)(0, 0, 0, 0, 309)); +} + +#ifdef ML_CLEAR_VRAM +void ML_clear_vram() +{ + int i, end, *pointer_long, vram; + char *pointer_byte; + vram = (int)ML_vram_adress(); + end = 4-vram&3; + pointer_byte = (char*)vram; + for(i=0 ; i>3)] |= 128>>(x&7); + break; + case ML_WHITE: + vram[(y<<4)+(x>>3)] &= ~(128>>(x&7)); + break; + case ML_XOR: + vram[(y<<4)+(x>>3)] ^= 128>>(x&7); + break; + case ML_CHECKER: + if(y&1^x&1) vram[(y<<4)+(x>>3)] &= ~(128>>(x&7)); + else vram[(y<<4)+(x>>3)] |= 128>>(x&7); + break; + } +} +#endif + +#ifdef ML_POINT +void ML_point(int x, int y, int width, ML_Color color) +{ + if(width < 1) return; + if(width == 1) ML_pixel(x, y, color); + else + { + int padding, pair; + padding = width>>1; + pair = !(width&1); + ML_rectangle(x-padding+pair, y-padding+pair, x+padding, y+padding, 0, 0, color); + } +} +#endif + +#ifdef ML_PIXEL_TEST +ML_Color ML_pixel_test(int x, int y) +{ + char *vram, byte; + if(x&~127 || y&~63) return ML_TRANSPARENT; + vram = ML_vram_adress(); + byte = 1<<(7-(x&7)); + return (vram[(y<<4)+(x>>3)] & byte ? ML_BLACK : ML_WHITE); + +} +#endif + +#ifdef ML_LINE +void ML_line(int x1, int y1, int x2, int y2, ML_Color color) +{ + int i, x, y, dx, dy, sx, sy, cumul; + x = x1; + y = y1; + dx = x2 - x1; + dy = y2 - y1; + sx = sgn(dx); + sy = sgn(dy); + dx = abs(dx); + dy = abs(dy); + ML_pixel(x, y, color); + if(dx > dy) + { + cumul = dx / 2; + for(i=1 ; i dx) + { + cumul -= dx; + y += sy; + } + ML_pixel(x, y, color); + } + } + else + { + cumul = dy / 2; + for(i=1 ; i dy) + { + cumul -= dy; + x += sx; + } + ML_pixel(x, y, color); + } + } +} +#endif + +#ifdef ML_HORIZONTAL_LINE +void ML_horizontal_line(int y, int x1, int x2, ML_Color color) +{ + int i; + char checker; + char* vram = ML_vram_adress(); + if(y&~63 || (x1<0 && x2<0) || (x1>127 && x2>127)) return; + if(x1 > x2) + { + i = x1; + x1 = x2; + x2 = i; + } + if(x1 < 0) x1 = 0; + if(x2 > 127) x2 = 127; + switch(color) + { + case ML_BLACK: + if(x1>>3 != x2>>3) + { + vram[(y<<4)+(x1>>3)] |= 255 >> (x1&7); + vram[(y<<4)+(x2>>3)] |= 255 << 7-(x2&7); + for(i=(x1>>3)+1 ; i>3 ; i++) + vram[(y<<4) + i] = 255; + } + else vram[(y<<4)+(x1>>3)] |= (255>>(x1%8 + 7-x2%8))<<(7-(x2&7)); + break; + case ML_WHITE: + if(x1>>3 != x2>>3) + { + vram[(y<<4)+(x1>>3)] &= 255 << 8-(x1&7); + vram[(y<<4)+(x2>>3)] &= 255 >> 1+(x2&7); + for(i=(x1>>3)+1 ; i>3 ; i++) + vram[(y<<4) + i] = 0; + } + else vram[(y<<4)+(x1>>3)] &= (255<<8-(x1&7)) | (255>>1+(x2&7)); + break; + case ML_XOR: + if(x1>>3 != x2>>3) + { + vram[(y<<4)+(x1>>3)] ^= 255 >> (x1&7); + vram[(y<<4)+(x2>>3)] ^= 255 << 7-(x2&7); + for(i=(x1>>3)+1 ; i<(x2>>3) ; i++) + vram[(y<<4) + i] ^= 255; + } + else vram[(y<<4)+(x1>>3)] ^= (255>>((x1&7) + 7-(x2&7)))<<(7-(x2&7)); + break; + case ML_CHECKER: + checker = (y&1 ? 85 : 170); + if(x1>>3 != x2>>3) + { + vram[(y<<4)+(x1>>3)] &= 255 << 8-(x1&7); + vram[(y<<4)+(x2>>3)] &= 255 >> 1+(x2&7); + vram[(y<<4)+(x1>>3)] |= checker & 255>>(x1&7); + vram[(y<<4)+(x2>>3)] |= checker & 255<<7-(x2&7); + for(i=(x1>>3)+1 ; i>3 ; i++) + vram[(y<<4) + i] = checker; + } + else + { + vram[(y<<4)+(x1>>3)] &= (255<<8-(x1&7)) | (255>>1+(x2&7)); + vram[(y<<4)+(x1>>3)] |= checker & (255>>(x1%8 + 7-x2%8))<<(7-(x2&7)); + } + break; + } +} + +#endif + +#ifdef ML_VERTICAL_LINE +void ML_vertical_line(int x, int y1, int y2, ML_Color color) +{ + int i, j; + char checker, byte, *vram = ML_vram_adress(); + if(x&~127 || (y1<0 && y2<0) || (y1>63 && y2>63)) return; + if(y1 > y2) + { + int tmp = y1; + y1 = y2; + y2 = tmp; + } + if(y1 < 0) y1 = 0; + if(y2 > 63) y2 = 63; + + i = (y1<<4)+(x>>3); + j = (y2<<4)+(x>>3); + switch(color) + { + case ML_BLACK: + byte = 128>>(x&7); + for( ; i<=j ; i+=16) + vram[i] |= byte; + break; + case ML_WHITE: + byte = ~(128>>(x&7)); + for( ; i<=j ; i+=16) + vram[i] &= byte; + break; + case ML_XOR: + byte = 128>>(x&7); + for( ; i<=j ; i+=16) + vram[i] ^= byte; + break; + case ML_CHECKER: + byte = 128>>(x&7); + checker = y1&1^x&1; + for( ; i<=j ; i+=16) + { + if(checker) vram[i] &= ~byte; + else vram[i] |= byte; + checker = !checker; + } + break; + } +} +#endif + +#ifdef ML_RECTANGLE +void ML_rectangle(int x1, int y1, int x2, int y2, int border_width, ML_Color border_color, ML_Color fill_color) +{ + int i; + if(x1 > x2) + { + i = x1; + x1 = x2; + x2 = i; + } + if(y1 > y2) + { + i = y1; + y1 = y2; + y2 = i; + } + if(border_width > (x2-x1)/2+1) border_width = (x2-x1)/2+1; + if(border_width > (y2-y1)/2+1) border_width = (y2-y1)/2+1; + if(border_color != ML_TRANSPARENT && border_width > 0) + { + for(i=0 ; i t[i]) + { + j++; + tmp = t[j]; + t[j] = t[i]; + t[i] = tmp; + } + } + t[r] = t[j+1]; + t[j+1] = x; + return j + 1; +} + +static void ML_filled_polygon_quicksord(int* t, int p, int r) +{ + int q; + if(p < r) + { + q = ML_filled_polygon_quicksord_partition(t, p, r); + ML_filled_polygon_quicksord(t, p, q-1); + ML_filled_polygon_quicksord(t, q+1, r); + } +} + + +void ML_filled_polygon(const int *x, const int *y, int nb_vertices, ML_Color color) +{ + int i, j, dx, dy, ymin, ymax; + int *cut_in_line, nb_cut; + if(nb_vertices < 3) return; + cut_in_line = malloc(nb_vertices*sizeof(int)); + if(!cut_in_line) return; + ymin = ymax = y[0]; + for(i=1 ; i ymax) ymax = y[i]; + } + for(i=ymin ; i<=ymax ; i++) + { + nb_cut = 0; + for(j=0 ; j=i) || (y[j]>=i && y[(j+1)%nb_vertices]<=i)) + { + dy = abs(y[j]-y[(j+1)%nb_vertices]); + if(dy) + { + dx = x[(j+1)%nb_vertices]-x[j]; + cut_in_line[nb_cut] = x[j] + rnd(abs(i-y[j]+sgn(i-y[j])/2)*dx/dy); + nb_cut++; + } + } + } + ML_filled_polygon_quicksord(cut_in_line, 0, nb_cut-1); + j = 0; + while(j plot_x) + { + if(d < 0) + d += 2*plot_x+3; + else + { + d += 2*(plot_x-plot_y)+5; + plot_y--; + } + plot_x++; + if(plot_y >= plot_x) + { + ML_pixel(x+plot_x, y+plot_y, color); + ML_pixel(x-plot_x, y+plot_y, color); + ML_pixel(x+plot_x, y-plot_y, color); + ML_pixel(x-plot_x, y-plot_y, color); + } + if(plot_y > plot_x) + { + ML_pixel(x+plot_y, y+plot_x, color); + ML_pixel(x-plot_y, y+plot_x, color); + ML_pixel(x+plot_y, y-plot_x, color); + ML_pixel(x-plot_y, y-plot_x, color); + } + } +} +#endif + +#ifdef ML_FILLED_CIRCLE +void ML_filled_circle(int x, int y, int radius, ML_Color color) +{ + int plot_x, plot_y, d; + + if(radius < 0) return; + plot_x = 0; + plot_y = radius; + d = 1 - radius; + + ML_horizontal_line(y, x-plot_y, x+plot_y, color); + while(plot_y > plot_x) + { + if(d < 0) + d += 2*plot_x+3; + else { + d += 2*(plot_x-plot_y)+5; + plot_y--; + ML_horizontal_line(y+plot_y+1, x-plot_x, x+plot_x, color); + ML_horizontal_line(y-plot_y-1, x-plot_x, x+plot_x, color); + } + plot_x++; + if(plot_y >= plot_x) + { + ML_horizontal_line(y+plot_x, x-plot_y, x+plot_y, color); + ML_horizontal_line(y-plot_x, x-plot_y, x+plot_y, color); + } + } +} +#endif + +#ifdef ML_ELLIPSE +void ML_ellipse(int x, int y, int radius1, int radius2, ML_Color color) +{ + int plot_x, plot_y; + float d1, d2; + if(radius1 < 1 || radius2 < 1) return; + plot_x = 0; + plot_y = radius2; + d1 = radius2*radius2 - radius1*radius1*radius2 + radius1*radius1/4; + ML_pixel(x, y+plot_y, color); + ML_pixel(x, y-plot_y, color); + while(radius1*radius1*(plot_y-.5) > radius2*radius2*(plot_x+1)) + { + if(d1 < 0) + { + d1 += radius2*radius2*(2*plot_x+3); + plot_x++; + } else { + d1 += radius2*radius2*(2*plot_x+3) + radius1*radius1*(-2*plot_y+2); + plot_x++; + plot_y--; + } + ML_pixel(x+plot_x, y+plot_y, color); + ML_pixel(x-plot_x, y+plot_y, color); + ML_pixel(x+plot_x, y-plot_y, color); + ML_pixel(x-plot_x, y-plot_y, color); + } + d2 = radius2*radius2*(plot_x+.5)*(plot_x+.5) + radius1*radius1*(plot_y-1)*(plot_y-1) - radius1*radius1*radius2*radius2; + while(plot_y > 0) + { + if(d2 < 0) + { + d2 += radius2*radius2*(2*plot_x+2) + radius1*radius1*(-2*plot_y+3); + plot_y--; + plot_x++; + } else { + d2 += radius1*radius1*(-2*plot_y+3); + plot_y--; + } + ML_pixel(x+plot_x, y+plot_y, color); + ML_pixel(x-plot_x, y+plot_y, color); + if(plot_y > 0) + { + ML_pixel(x+plot_x, y-plot_y, color); + ML_pixel(x-plot_x, y-plot_y, color); + } + } +} +#endif + +#ifdef ML_ELLIPSE_IN_RECT +void ML_ellipse_in_rect(int x1, int y1, int x2, int y2, ML_Color color) +{ + int radius1, radius2; + if(x1 > x2) + { + int tmp = x1; + x1 = x2; + x2 = tmp; + } + if(y1 > y2) + { + int tmp = y1; + y1 = y2; + y2 = tmp; + } + radius1 = (x2-x1)/2; + radius2 = (y2-y1)/2; + ML_ellipse(x1+radius1, y1+radius2, radius1, radius2, color); +} +#endif + +#ifdef ML_FILLED_ELLIPSE +void ML_filled_ellipse(int x, int y, int radius1, int radius2, ML_Color color) +{ + int plot_x, plot_y; + float d1, d2; + if(radius1 < 1 || radius2 < 1) return; + plot_x = 0; + plot_y = radius2; + d1 = radius2*radius2 - radius1*radius1*radius2 + radius1*radius1/4; + while(radius1*radius1*(plot_y-.5) > radius2*radius2*(plot_x+1)) + { + if(d1 < 0) + { + d1 += radius2*radius2*(2*plot_x+3); + plot_x++; + } else { + d1 += radius2*radius2*(2*plot_x+3) + radius1*radius1*(-2*plot_y+2); + ML_horizontal_line(y+plot_y, x-plot_x, x+plot_x, color); + ML_horizontal_line(y-plot_y, x-plot_x, x+plot_x, color); + plot_x++; + plot_y--; + } + } + ML_horizontal_line(y+plot_y, x-plot_x, x+plot_x, color); + ML_horizontal_line(y-plot_y, x-plot_x, x+plot_x, color); + d2 = radius2*radius2*(plot_x+.5)*(plot_x+.5) + radius1*radius1*(plot_y-1)*(plot_y-1) - radius1*radius1*radius2*radius2; + while(plot_y > 0) + { + if(d2 < 0) + { + d2 += radius2*radius2*(2*plot_x+2) + radius1*radius1*(-2*plot_y+3); + plot_y--; + plot_x++; + } else { + d2 += radius1*radius1*(-2*plot_y+3); + plot_y--; + } + ML_horizontal_line(y+plot_y, x-plot_x, x+plot_x, color); + if(plot_y > 0) + ML_horizontal_line(y-plot_y, x-plot_x, x+plot_x, color); + } +} +#endif + +#ifdef ML_FILLED_ELLIPSE_IN_RECT +void ML_filled_ellipse_in_rect(int x1, int y1, int x2, int y2, ML_Color color) +{ + int radius1, radius2; + if(x1 > x2) + { + int tmp = x1; + x1 = x2; + x2 = tmp; + } + if(y1 > y2) + { + int tmp = y1; + y1 = y2; + y2 = tmp; + } + radius1 = (x2-x1)/2; + radius2 = (y2-y1)/2; + ML_filled_ellipse(x1+radius1, y1+radius2, radius1, radius2, color); +} +#endif + +#ifdef ML_HORIZONTAL_SCROLL +void ML_horizontal_scroll(int scroll) +{ + int i, j; + char line[16], shift, *vram; + unsigned char next; + unsigned short word; + vram = ML_vram_adress(); + scroll %= 128; + shift = 8-(scroll&7); + for(i=0 ; i<64 ; i++) + { + for(j=0 ; j<16 ; j++) line[j] = vram[(i<<4)+((j-(scroll>>3)+15)&15)]; + next = line[15]; + vram[(i<<4)+15] = 0; + for(j=15 ; j>0 ; j--) + { + word = next << shift; + next = line[j-1]; + vram[(i<<4)+j] |= *((char*)&word+1); + vram[(i<<4)+j-1] = *((char*)&word); + } + word = next << shift; + vram[(i<<4)] |= *((char*)&word+1); + vram[(i<<4)+15] |= *((char*)&word); + } +} +#endif + +#ifdef ML_VERTICAL_SCROLL +void ML_vertical_scroll(int scroll) +{ + int i, j; + char column[64], *vram = ML_vram_adress(); + scroll %= 64; + for(i=0 ; i<16 ; i++) + { + for(j=0 ; j<64 ; j++) column[j] = vram[(j<<4)+i]; + for(j=0 ; j<64 ; j++) vram[(j<<4)+i] = column[(j-scroll+64)&63]; + } +} +#endif + +#ifdef ML_BMP_OR +void ML_bmp_or(const unsigned char *bmp, int x, int y, int width, int height) +{ + unsigned short line; + char shift, *screen, *p=(char*)&line; + int i, j, begin=0, end=height, real_width=(width-1>>3<<3)+8; + if(!bmp || x<0 || x>128-width || y<1-height || y>63 || width<1 || height<1) return; + if(y < 0) begin = -y; + if(y+height > 64) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i>3 ; j++) + { + line = bmp[i*(real_width>>3)+j]<>3)+j] & -1<<(real_width-width))<>3<<3)+8; + if(!bmp || x<0 || x>128-width || y<1-height || y>63 || width<1 || height<1) return; + if(y < 0) begin = -y; + if(y+height > 64) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i>3 ; j++) + { + line = ~((unsigned char)~bmp[i*(real_width>>3)+j]<>3)+j] | (unsigned char)-1>>8-(width&7))<>3<<3)+8; + if(!bmp || x<0 || x>128-width || y<1-height || y>63 || width<1 || height<1) return; + if(y < 0) begin = -y; + if(y+height > 64) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i>3 ; j++) + { + line = bmp[i*(real_width>>3)+j]<>3)+j] & -1<<(real_width-width))<127 || y<1-height || y>63 || height<1 || width<1) return; + p = (char*)&line; + real_width = (width-1>>3<<3)+8; + if(y < 0) begin_y = -y; + else begin_y = 0; + if(y+height > 64) end_y = 64-y; + else end_y = height; + shift = 8-(x&7); + if(x<0) + { + begin_x = -x>>3; + if(shift != 8) bool1 = 0; + } else begin_x = 0; + if(x+real_width > 128) end_x = 15-(x>>3), bool2 = 0; + else end_x = real_width-1>>3; + bool3 = (end_x == real_width-1>>3); + screen = ML_vram_adress()+(y+begin_y<<4)+(x>>3); + + for(i=begin_y ; i>3)+begin_x] << shift; + if(bool1) screen[begin_x] |= *p; + if(shift!=8) screen[begin_x+1] |= *(p+1); + for(j=begin_x+1 ; j>3)+j] << shift; + screen[j] |= *p; + if(shift!=8) screen[j+1] |= *(p+1); + } + } + line = bmp[i*(real_width>>3)+end_x]; + if(bool3) line &= -1<127 || y<1-height || y>63 || height<1 || width<1) return; + p = (char*)&line; + real_width = (width-1>>3<<3)+8; + if(y < 0) begin_y = -y; + else begin_y = 0; + if(y+height > 64) end_y = 64-y; + else end_y = height; + shift = 8-(x&7); + if(x<0) + { + begin_x = -x>>3; + if(shift != 8) bool1 = 0; + } else begin_x = 0; + if(x+real_width > 128) end_x = 15-(x>>3), bool2 = 0; + else end_x = real_width-1>>3; + bool3 = (end_x == real_width-1>>3); + screen = ML_vram_adress()+(y+begin_y<<4)+(x>>3); + + for(i=begin_y ; i>3)+begin_x]<>3)+j]<>3)+end_x]; + if(bool3) line &= -1<127 || y<1-height || y>63 || height<1 || width<1) return; + p = (char*)&line; + real_width = (width-1>>3<<3)+8; + if(y < 0) begin_y = -y; + else begin_y = 0; + if(y+height > 64) end_y = 64-y; + else end_y = height; + shift = 8-(x&7); + if(x<0) + { + begin_x = -x>>3; + if(shift != 8) bool1 = 0; + } else begin_x = 0; + if(x+real_width > 128) end_x = 15-(x>>3), bool2 = 0; + else end_x = real_width-1>>3; + bool3 = (end_x == real_width-1>>3); + screen = ML_vram_adress()+(y+begin_y<<4)+(x>>3); + + for(i=begin_y ; i>3)+begin_x] << shift; + if(bool1) screen[begin_x] ^= *p; + if(shift!=8) screen[begin_x+1] ^= *(p+1); + for(j=begin_x+1 ; j>3)+j] << shift; + screen[j] ^= *p; + if(shift!=8) screen[j+1] ^= *(p+1); + } + } + line = bmp[i*(real_width>>3)+end_x]; + if(bool3) line &= -1<120 || y<-7 || y>63) return; + if(y < 0) begin = -y; + if(y > 56) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i120 || y<-7 || y>63) return; + if(y < 0) begin = -y; + if(y > 56) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i120 || y<-7 || y>63) return; + if(y < 0) begin = -y; + if(y > 56) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i127 || y<-7 || y>63) return; + if(y < 0) begin = -y; + if(y > 56) end = 64-y; + shift = 8-(x&7); + if(x < 0) bool1 = 0; + if(x>120 || shift==8) bool2 = 0; + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i127 || y<-7 || y>63) return; + if(y < 0) begin = -y; + if(y > 56) end = 64-y; + shift = 8-(x&7); + if(x < 0) bool1 = 0; + if(x>120 || shift==8) bool2 = 0; + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i127 || y<-7 || y>63) return; + if(y < 0) begin = -y; + if(y > 56) end = 64-y; + shift = 8-(x&7); + if(x < 0) bool1 = 0; + if(x>120 || shift==8) bool2 = 0; + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i112 || y<-15 || y>63) return; + if(y < 0) begin = -y; + if(y > 48) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i112 || y<-15 || y>63) return; + if(y < 0) begin = -y; + if(y > 48) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i112 || y<-15 || y>63) return; + if(y < 0) begin = -y; + if(y > 48) end = 64-y; + shift = 8-(x&7); + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i127 || y<-15 || y>63) return; + if(y < 0) begin = -y; + if(y > 48) end = 64-y; + shift = 8-(x&7); + if(x < 0) bool1 = 0; + if(x<-8 || x>119) bool2 = 0; + if(x>111 || shift==8) bool3 = 0; + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i127 || y<-15 || y>63) return; + if(y < 0) begin = -y; + if(y > 48) end = 64-y; + shift = 8-(x&7); + if(x < 0) bool1 = 0; + if(x<-8 || x>119) bool2 = 0; + if(x>111 || shift==8) bool3 = 0; + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i127 || y<-15 || y>63) return; + if(y < 0) begin = -y; + if(y > 48) end = 64-y; + shift = 8-(x&7); + if(x < 0) bool1 = 0; + if(x<-8 || x>119) bool2 = 0; + if(x>111 || shift==8) bool3 = 0; + screen = ML_vram_adress()+(y+begin<<4)+(x>>3); + for(i=begin ; i.c + * generate .g1w + * + */ + +public class B2C { + + final static boolean debugMode = true; + + static String path = "C:\\Users\\Catherine\\Documents\\CASIO\\fx-9860G SDK\\TestB2C\\"; + static String pathToG1M = "C:\\Users\\Catherine\\Desktop\\test.g1m"; + static String mainProgramName = "TEST"; + static boolean isRealTimeGame = true; + static boolean assureOS1Compatibility = true; + static boolean usesAcOnTimer = true; + static String main_c; + + + public static void main(String[] args) { + if (!debugMode) { + Scanner sc = new Scanner(System.in); + System.out.println("Enter the path to the .g1m file:"); + while (true) { + pathToG1M = ""+sc.nextLine().charAt(0); + if (new File(pathToG1M).isFile()) { + break; + } else { + System.out.println("File not found."); + } + } + pathToG1M = pathToG1M.replaceAll("\\\\", "/"); + System.out.println("Enter the name of the main program.\nReplace 'r' with \"radius\", 'θ' by \"theta\" and non-ASCII characters by '_'."); + mainProgramName = Parser.parseProgName(sc.nextLine()); + String programName = pathToG1M.substring(pathToG1M.lastIndexOf('/')+1, pathToG1M.lastIndexOf('.')); + path = System.getProperty("user.home") + "\\Documents\\CASIO\\fx-9860G SDK\\" + + programName + System.getProperty("file.separator"); + System.out.println("Enter the destination path. Write \"default\" to set to:\n" + path); + String destinationPath = sc.nextLine(); + if (!destinationPath.equals("default")) { + path = destinationPath; + } + new File(path).mkdir(); + + //TODO create custom image + try { + Files.copy(new File(B2C.class.getClassLoader().getResource("MainIcon.bmp").getPath().substring(1)).toPath(), + new File(path + "/MainIcon.bmp").toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } + + IO.writeToFile(new File(path + File.separator + programName + ".g1w"), + IO.readFromRelativeFile("Default.g1w").replaceAll("%PROG_NAME%", programName), true); + IO.writeToFile(new File(path + File.separator + "AddinInfo.txt"), + IO.readFromRelativeFile("AddinInfo.txt").replaceAll("%PROG_NAME%", programName), true); + + } + long startTime = System.currentTimeMillis(); + + //Add some constants for functions + Constants.add("0"); + Constants.add("1"); + Constants.add("-1"); + /*Constants.add("53123523"); + Constants.add("0.3"); + Constants.add("2.304"); + Constants.add("-1"); + Constants.add("0.0456"); + Constants.add("-0.00786");*/ + + main_c = + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \n" + + "#include \"fxlib.h\"\n" + + "#include \"main.h\"\n\n" + + "unsigned int key;\n" + + "int i;\n"+ + "BCDvar var[28] = {0}; //A-Z, r, theta\n"+ + "BCDvar Ans;\n" + + "Str strings[20];\n" + + "Mat mat[26]; //Important thing: matrixes are (height, width) not (width, height)\n" + + "char dummyOpCode[2] = {5, 8};\n" + + "//These are buffers for syscalls that do not return a value.\n" + + "BCDvar alphaVarBuffer;\n" + + "BCDvar expressionBuffer;\n" + + "BCDvar getkeyBuffer;\n" + + "unsigned char stringBuffer[256] = {0};\n"; + /*"const BCDvar ZERO = {0};\n"; + for (int i = 1; i <= 9; i++) { + main_c += "const BCDvar " + Parser.consts.get(i) + " = {0x10, 0x0" + i + "};\n"; + }*/ + main_c+="\nint AddIn_main(int isAppli, unsigned short OptionNum) {\n" + + "\t//Initialize strings\n" + + "\tfor (i = 0; i < 20; i++) {\n" + + "\t\tstrings[i].length = 0;\n" + + "\t}\n" + + "\t#ifdef USES_INTERRUPTION_TIMER\n" + + "\t//Timer allowing AC/ON to be pressed at any moment\n" + + "\tSetTimer(INTERRUPTION_TIMER, 50, exitTimerHandler);\n" + + "\t#endif\n" + + "\tprog_"+mainProgramName+"();\n\n" + + "\tdo {\n" + + "\t\tGetKey(&key);\n" + + "\t} while (key != KEY_CTRL_EXE && key != KEY_CTRL_AC);\n" + + "\treturn 1;\n" + + "}\n\n"; + + main_c += IO.readFromFile(pathToG1M); + + System.out.println("Result:\n-------------\n"+main_c); + + //pragma stuff + main_c += "\n\n#pragma section _BR_Size\nunsigned long BR_Size;\n#pragma section\n\n" + + "#pragma section _TOP\n" + + "int InitializeSystem(int isAppli, unsigned short OptionNum) {" + + "\n\treturn INIT_ADDIN_APPLICATION(isAppli, OptionNum);\n}\n" + + "#pragma section\n"; + + //GetKey handling + /*if (isRealTimeGame) { + main_c = main_c.replaceAll( + "(do \\{\\n+([\\t ]+)?([\\w\\[\\]])+? \\= )Getkey_Temp(\\(\\);\n([\\t ]+)?} while \\()", + "$1Getkey_Block$4" + ); + main_c = main_c.replaceAll("Getkey_Temp\\(\\);", "Getkey_NoBlock();"); + } else { + main_c = main_c.replaceAll("Getkey_Temp\\(\\);", "Getkey_Block();"); + }*/ + + + main_c += Functions.getFunctions(); + + IO.writeToFile(new File(path + "/main.c"), main_c, true); + + //Syscalls asm file + + /*writeToFile(new File(path + "syscalls.src"), + "\t.SECTION P,CODE,ALIGN=4\n\n" + + "\t.MACRO SYSCALL FUNO, SYSCALLNAME, TAIL=nop\n\n" + + "\t.export \\SYSCALLNAME'\n" + + "\\SYSCALLNAME'\n" + + "\tmov.l #h'\\FUNO, r0\n" + + "\tmov.l #H'80010070, r2\n" + + "\tjmp @r2\n" + + "\t\\TAIL'\n" + + "\t.ENDM\n\n" + + "\tSYSCALL " + , true);*/ + Syscalls.addSyscall("bcdToStr", "4F0"); + Syscalls.addSyscall("intToBCD", "5A6"); + Syscalls.addSyscall("calcExp", "645"); + Syscalls.addSyscall("getAlphaVar", "4DF"); + Syscalls.addSyscall("setAlphaVar", "4E0"); + Syscalls.addSyscall("prgmGetkey", "6C4"); + Syscalls.addSyscall("putMatrixCode", "24F"); + //Syscalls.addSyscall("installTimer", "118"); + //Syscalls.addSyscall("startTimer", "11A"); + //Syscalls.addSyscall("uninstallTimer", "119"); + Syscalls.addSyscall("putInternalItem", "82A"); + Syscalls.addSyscall("deleteInternalItem", "835"); + Syscalls.addSyscall("openItem", "83B"); + Syscalls.addSyscall("getItemData", "372"); + Syscalls.addSyscall("getItemSize", "840"); + Syscalls.addSyscall("overwriteItemData", "830"); + Syscalls.addSyscall("setSetupEntry", "4DD"); + Syscalls.addSyscall("getSetupEntry", "4DC"); + Syscalls.createSyscallFile(); + + String[] externalLibs = {"MonochromeLib.c", "MonochromeLib.h", "memory.c", "memory.h"}; + for (int i = 0; i <= 1; i++) { + IO.writeToFile(new File(path+externalLibs[i]), IO.readFromRelativeFile(externalLibs[i]), true); + } + Header.addDefine("FALSE 0"); + Header.addDefine("TRUE 1"); + Header.addDefine("NO_ERROR 0"); + Header.addDefine("MEMORY_ERROR 1"); + Header.addDefine("INTERRUPTION_TIMER 2"); + if (usesAcOnTimer) { + Header.addDefine("USES_INTERRUPTION_TIMER"); + } + Header.addDefine("DIR_PROG 0x01"); + Header.addDefine("DIR_LIST 0x05"); + Header.addDefine("DIR_MAT 0x06"); + Header.addDefine("DIR_PICT 0x07"); + Header.addDefine("DIR_CAPT 0x0A"); + + Header.addDefine("LIST_START 0x10"); + Header.addDefine("MAT_START 0x10"); + + Header.addDefine("SETUP_LISTFILE 0x2E"); + + Header.addDefine("free_str(x) if(!isString){free(x->data); free(x);}"); + Header.addDefine("getDigit(BCDvar, i) (((i)%2) ? (*(BCDvar))[((i)+1)/2+1]>>4 : (*(BCDvar))[((i)+1)/2+1]&0x0F)"); + Header.create(); + + System.out.println("Parsing done in " + (System.currentTimeMillis()-startTime) + " ms."); + if (!assureOS1Compatibility) { + System.out.println("WARNING: This program uses OS 2 functions. It won't run properly on the SDK emulator!"); + } + } +} diff --git a/B2C/src/b2c/Constants.java b/B2C/src/b2c/Constants.java new file mode 100644 index 0000000..6ade179 --- /dev/null +++ b/B2C/src/b2c/Constants.java @@ -0,0 +1,72 @@ +package b2c; + +import java.util.ArrayList; + +public class Constants { + + static ArrayList consts = new ArrayList(); + + /** + * This method is to optimise the speed of B2C by pre-calculating constants. + * Only send to this method integer and double constants. For now, it won't calculate + * special things like 1e5, 1/3, etc. + */ + public static void add(String constant) { + constant = constant.replaceAll("\\x99", "-"); + System.out.println(constant); + if (constant.startsWith(".")) { + constant = "0" + constant; + } + if (consts.contains(Double.valueOf(constant))) { + return; + } + consts.add(Double.valueOf(constant)); + //Calculate the bytes of the constant + //Note: can't convert to double due to precision loss + //To fix this, we remove the decimal point to convert to integer and keep the exponent + + int exponent = 100; //exponent is 100-indexed in casio's system + + if (constant.indexOf(".") >= 0) { + //Remove trailing zeroes that have, in this case, no significance + constant = constant.replaceAll("0+$", ""); + + //The exponent is modified by the number of significant digits after the decimal part + exponent -= constant.length() - (constant.indexOf(".")+1); + } + + //Convert integer to scientific notation using StackOverflow magic + //First number apparently means the number of significant digits (including exponent) + //Second number is the number of digits after the decimal point (not including exponent) + System.out.println(constant); + + String sciNotation = String.format("%18.14e", Double.valueOf(constant.replaceAll("\\.", ""))).replace(",", "."); + + + String mantissa = sciNotation.substring(0, sciNotation.indexOf("e")).replaceAll("\\.", ""); + System.out.println(mantissa); + exponent += Integer.valueOf(sciNotation.substring(sciNotation.indexOf('e')+1)); + + //Can't use Integer.valueOf(mantissa) because it might be over 2^32 + if (mantissa.startsWith("-")) { + exponent += 500; + mantissa = mantissa.substring(1); + } + + String bcdNotation = (exponent < 100 ? "0" : "") + String.valueOf(exponent) + mantissa; + if (bcdNotation.contains(".") || bcdNotation.contains("-") || bcdNotation.length() != 18) { + Parser.error("Error in BCD conversion of " + constant + " which gave " + bcdNotation); + } + System.out.println("Result= "+bcdNotation); + //Replace groups of 2 digits by "0x##, " and remove the last comma+space + System.out.println(bcdNotation); + bcdNotation = bcdNotation.replaceAll("(.{2})", "0x$1, ").replaceAll(", $", ""); + System.out.println(bcdNotation); + Header.addGlobal("const BCDvar " + Constants.getVarNotation(constant) + " = {" + bcdNotation + "};\n"); + } + + public static String getVarNotation(String nb) { + return "_"+nb.replaceAll("\\.|\\-|\\x99", "_")+"_"; + } + +} diff --git a/B2C/src/b2c/Functions.java b/B2C/src/b2c/Functions.java new file mode 100644 index 0000000..ef234c6 --- /dev/null +++ b/B2C/src/b2c/Functions.java @@ -0,0 +1,203 @@ +package b2c; + +//This class contains all B2C functions. + +public class Functions { + + static String functions = "\n//B2C functions\n\n"; + + //This is for automatically generated methods; for unique methods, write them manually in the local B2CFunctions.c file. + public static void addFunctions() { + /* + //Calculation functions + String[] operators = { + "7F\"\"\\xB4", + "10", // <= + "11", // != + "12", // >= + "3D", // = + "3C", // < + "3E", // > + "A8", // ^ + "A9", // * + "B9", // / + "89", // + + "99" // - + }; + String[] calcFunctions = { + "xor", + "lessOrEqualThan", + "notEqualTo", + "greaterOrEqualThan", + "equalTo", + "lessThan", + "greaterThan", + "pow", + "mult", + "div", + "add", + "sub", + }; + for (int i = 0; i < operators.length; i++) { + functions += addMethod( + "BCDvar B2C_" + calcFunctions[i] + "(BCDvar a, BCDvar b) {\n" + + "\tBCDvar result;\n" + + "\tconst char *function = \"A\\x" + operators[i] + "\"\"B\";\n" + + "\tsetAlphaVar('A', &a);\n" + + "\tsetAlphaVar('B', &b);\n" + + "\tcalcExp(&function" + + //_"+calcFunctions[i] + + ", dummyOpCode, &result, 1);\n" + + "\treturn result;\n}\n"); + //Header.addGlobal("char *function_"+calcFunctions[i]+" = \"A\"\"\\x" + operators[i] + "\"\"B\";\n"); + + } + String[] logicalOperators = { + "&&", "and", + "||", "or", + }; + for (int i = 0; i < logicalOperators.length; i+=2) { + functions += addMethod( + "BCDvar B2C_" + logicalOperators[i+1] + "(BCDvar a, BCDvar b) {\n" + + "\tif (a.bytes[1] " + logicalOperators[i] + " b.bytes[1]) {\n" + + "\t\treturn _1_;\n" + + "\t}\n" + + "\treturn _0_;\n}\n" + ); + } + */ + /*functions += addMethod( + "BCDvar B2C_not(BCDvar a) {\n" + + "\tif (a.bytes[1])\n" + + "\t\treturn ZERO;" + + "\treturn ONE;\n}\n" + ); + + functions += addMethod( + "char* B2C_convToStr(BCDvar nb) {\n" + + "\tchar* result = calloc(15, 1);\n" + + "\tbcdToStr(&nb, result);\n" + + "\treturn result;\n}\n"); + + functions += addMethod( + "BCDvar B2C_convToBCD(char* str) {\n" + + "\tBCDvar result;\n" + + "\tcalcExp(&str, dummyOpCode, &result, 1);\n" + + "\treturn result;\n}\n"); + + functions += addMethod( + "void B2C_setListRow(int nbList, int row, BCDvar value) {\n" + + "\tif (row > list[nbList].nbElements) {\n" + + "\t\tBCDvar *tempPtr = realloc(list[nbList].data, (list[nbList].nbElements+1)*sizeof(BCDvar));\n" + + "\t\tif (tempPtr == NULL) {\n" + + "\t\t\tfree(list[nbList].data);\n" + + "\t\t\tB2C_stop();\n\t\t}\n" + + "\t\tlist[nbList].data = tempPtr;\n" + + "\t\tlist[nbList].nbElements++;\n\t}\n" + + "\tlist[nbList].data[row] = value;\n}\n" + ); + functions += addMethod( + "void B2C_setDimList(int nbList, int nbElements) {\n" + + "\tfree(list[nbList].data);\n" + + "\tlist[nbList].data = calloc(nbElements+1, sizeof(BCDvar));\n}\n" + ); + + functions += addMethod( + "List B2C_newList(int nbElements, ...) {\n" + + "\tList list;\n" + + "\tva_list vaList;\n" + + "\tlist.nbElements = nbElements;\n" + + "\tlist.data = calloc(nbElements+1, sizeof(BCDvar));\n" + + "\tva_start(vaList, nbElements);\n" + + "\tlist.data[0] = ZERO;\n" + + "\tfor (i = 1; i <= nbElements; i++) {\n" + + "\t\tlist.data[i] = va_arg(vaList, BCDvar);\n" + + "\t}\n" + + "\tva_end(vaList);\n" + + "\treturn list;\n}\n" + ); + + //TODO: add method which takes (matrix, height, width) as argument, could lead to a faster conversion than initializing a list + functions += addMethod( + "void B2C_setDimMat(int matrix, List list) {\n" + + "\tif (mat[matrix].data) free(mat[matrix].data);\n" + + "\tmat[matrix].data = calloc((B2C_convToUInt(list.data[2])+1)*(B2C_convToUInt(list.data[1])+1), sizeof(BCDvar));\n" + + "\tmat[matrix].width = B2C_convToUInt(list.data[1]);\n" + + "\tmat[matrix].height = B2C_convToUInt(list.data[2]);\n" + + "}\n" + ); + + functions += addMethod( + "int B2C_convToUInt(BCDvar nb) {\n" + + "\tint result = 0;\n" + + "\tint power = (nb.bytes[1]>>4) + 1;\n" + + "\tfor (i = 1; i <= power; i++) {\n" + + "\t\tif (i%2) {\n" + + "\t\t\tresult += (nb.bytes[i/2+1]&0xF) * pow(10, power-i);\n" + + "\t\t} else {\n" + + "\t\t\tresult += (nb.bytes[i/2+1]>>4) * pow(10, power-i);\n" + + "\t\t}\n" + + "\t}\n" + + "\treturn result;\n}\n" + ); + + functions += addMethod( + "BCDvar B2C_Getkey() {\n" + + "\tBCDvar result;\n" + + "\tif (!prgmGetkey(&result)) {\n" + + "\t\tB2C_stop();\n" + + "\t}\n" + + "\treturn result;\n}\n" + ); + + functions += addMethod( + "void timerHandler() {\n" + + "\tshort menuCode = 0x0308;\n" + + "\tputMatrixCode(&menuCode);" + + "\n}\n" + ); + + functions += addMethod( + "void B2C_stop() {\n" + + "\tinstallTimer(6, (void*)&timerHandler, 1);\n" + + "\tstartTimer(6);\n" + + "\tGetKey(&key);\n" + + "\tuninstallTimer(6);\n" + + "\tPopUpWin(4);\n" + + "\tlocate(5,3); Print(\"Interruption\");\n" + + "\tlocate(4,5); Print(\"Appuyer:[MENU]\");\n" + + "\twhile(1)\n" + + "\t\tGetKey(&key);\n" + + "\n}\n" + ); + + //TODO actually randomize + functions += addMethod( + "BCDvar B2C_ranInt(int a, int b) {\n" + + "\treturn ONE;\n}\n" + );*/ + } + + public static String getFunctions() { + addFunctions(); + String functionsBuffer = IO.readFromRelativeFile("B2CFunctions.c"); + Integer[] functionsPositions = Parser.parseBrackets(functionsBuffer); + + //System.out.println(functionsBuffer.substring(0, functionsPositions[2])); + functions += addMethod(functionsBuffer.substring(0, functionsPositions[3]+1)); + for (int i = 3; i < functionsPositions.length-4; i+=4) { + //System.out.println(functionsBuffer.substring(functionsPositions[i], functionsPositions[i+4])); + functions += addMethod(functionsBuffer.substring(functionsPositions[i]+1, functionsPositions[i+4]+1)); + } + return functions; + } + + //Automatically generates the prototypes for the given method. + public static String addMethod(String method) { + + //This should normally get the method name. + //String methodName = method.substring(method.substring(0, method.indexOf('(')).indexOf(' '), method.indexOf('(')); + Header.addPrototype(method.substring(0, method.indexOf('{')).trim() + ";\n"); + return method; + } +} diff --git a/B2C/src/b2c/G1MParser.java b/B2C/src/b2c/G1MParser.java new file mode 100644 index 0000000..c646429 --- /dev/null +++ b/B2C/src/b2c/G1MParser.java @@ -0,0 +1,67 @@ +package b2c; + +import java.util.ArrayList; + +public class G1MParser { + + + public static String convert(String content) { + if (content.isEmpty()) return ""; + + String currentProgram = Parser.parseProgName(content.substring(0, 8)); //content.substring(60,68); + System.out.println("Program name: " + currentProgram); + Header.addPrototype("void prog_"+currentProgram+"();\n"); + //System.out.println("Instructions : " + content.substring(86)); + content = content.substring(26); + int lastCarriageReturn = -1; + Parser.instructions.clear(); + Parser.instructionNumber = 0; + Parser.nbBuffers = 0; + + + //Divides the instructions + for (int i = 0; i < content.length(); i++) { + if (content.charAt(i) == '\r') { + Parser.instructions.add(content.substring(lastCarriageReturn+1, i)); + lastCarriageReturn = i; + } + if (Parser.isMultibytePrefix(content.charAt(i))) { + i++; + } + + } + Parser.instructions.add(content.substring(lastCarriageReturn+1)); + StringBuilder result = new StringBuilder(); + + /* Due to the functions returning BCDvar* and not BCDvar, + * there must be buffers in which the functions return. + * To avoid creating a buffer at each function call, + * as many buffers are created as functions calls in an instruction. + */ + int nbBuffers = 0; + do { + Parser.nbBuffers = 0; + result.append(Parser.tabs + Parser.parse(Parser.instructions.get(Parser.instructionNumber), Parser.WHOLE_INSTRUCTION) + "\n"); + Parser.instructionNumber++; + if (nbBuffers < Parser.nbBuffers) { + nbBuffers = Parser.nbBuffers; + } + } while (Parser.instructionNumber < Parser.instructions.size()); + + //Add buffers + String buffers = "\tBCDvar "; + for (int i = 0; i < nbBuffers; i++) { + buffers += "buffer" + i; + if (i+1 < nbBuffers) buffers += ", "; + } + buffers += ";\n"; + if (nbBuffers > 0) result.insert(0, buffers); + result.insert(0, "void prog_"+currentProgram+"() {\n"); + //result = Parser.autoreplace(result); + result.append("}"); + System.out.println("nb buffers = " + nbBuffers); + System.out.println(Parser.nbBuffers); + return result.toString(); + + } +} diff --git a/B2C/src/b2c/Header.java b/B2C/src/b2c/Header.java new file mode 100644 index 0000000..2496374 --- /dev/null +++ b/B2C/src/b2c/Header.java @@ -0,0 +1,56 @@ +package b2c; + +import java.io.File; + +public class Header { + + static String headerDefines = ""; + static String headerPrototypes = ""; + static String headerGlobals = ""; + String headerVars = ""; + + public static void addDefine(String content) { + headerDefines += "#define "+content+"\n"; + } + + public static void addPrototype(String prototype) { + headerPrototypes += prototype; + } + + public static void addGlobal(String global) { + headerGlobals += global; + } + + public static void create() { + + String header = + "#ifndef MAIN_H\n" + + "#define MAIN_H\n\n" + + headerDefines + "\n\n" + + "typedef unsigned char BCDvar[24]; //this defines BCDvar as an array of 24 unsigned chars\n" + + "typedef struct {\n" + + "\t//int nbElements;\n" + + "\tBCDvar *data;\n" + + "} List;\n\n" + + "typedef struct {\n" + + "\t//int width;\n" + + "\t//int height;\n" + + "\tBCDvar *data;\n" + + "} Mat;\n\n" + + //"typedef unsigned short Fontchar;\n" + + "typedef struct {\n" + + "\tint length;\n" + + "\tunsigned char* data;\n" + + "} Str;\n\n" + + "typedef struct {\n" + + "\tunsigned char data[4];\n" + + "} SmallStr;\n\n" + + headerPrototypes + "\n" + + headerGlobals + + "\n#endif //MAIN_H"; + IO.writeToFile(new File(B2C.path + "/main.h"), header, true); + + } + + +} diff --git a/B2C/src/b2c/IO.java b/B2C/src/b2c/IO.java new file mode 100644 index 0000000..8147ece --- /dev/null +++ b/B2C/src/b2c/IO.java @@ -0,0 +1,90 @@ +package b2c; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class IO { + public static void writeToFile(File file, String content, boolean deleteFile) { + try { + if (deleteFile) { + file.delete(); + } + file.createNewFile(); + BufferedWriter bw = new BufferedWriter(new FileWriter(file.getAbsoluteFile(), true)); + bw.write(content); + bw.close(); + } catch (IOException e2) { + e2.printStackTrace(); + } + } + + public static String readFromRelativeFile(String fileName) { + byte[] encoded = null; + try { + //For some reason it appends a '/' to the beginning of the string, making the file path invalid + String relativePath = B2C.class.getClassLoader().getResource(fileName).getPath().substring(1); + encoded = Files.readAllBytes(Paths.get(relativePath)); + } catch (IOException e) { + e.printStackTrace(); + } + String result = null; + try { + result = new String(encoded, "Cp1252"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + return result; + } + + public static String readFromFile(String path) { + /*String content = ""; + try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "Cp1252"))) { + content = br. + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + }*/ + String content = ""; + byte[] encoded; + try { + encoded = Files.readAllBytes(Paths.get(path)); + content = new String(encoded, "Cp1252"); + } catch (IOException e) { + e.printStackTrace(); + } + //remove header + content = content.substring(32); + + //due to unicode encoding, some characters get encoded as others + + content = content.replaceAll("\\u2020", new String(new char[]{0x86})); + content = content.replaceAll("\\u2021", new String(new char[]{0x87})); + content = content.replaceAll("\\u02C6", new String(new char[]{0x88})); + content = content.replaceAll("\\u2030", new String(new char[]{0x89})); + content = content.replaceAll("\\uFFFD", new String(new char[]{0x8F})); + content = content.replaceAll("\\u2019", new String(new char[]{0x92})); + content = content.replaceAll("\\u201D", new String(new char[]{0x94})); + content = content.replaceAll("\\u2122", new String(new char[]{0x99})); + content = content.replaceAll("\\u0161", new String(new char[]{0x9A})); + content = content.replaceAll("\\u203A", new String(new char[]{0x9B})); + //TODO actually parse the g1m + String[] programs = content.split("PROGRAM[\\s\\S]{13}system[\\s\\S]{2}"); + + String result = ""; + for (int i = 1; i < programs.length; i++) { + String str = programs[i]; + + //removes \0 's at the end of the file + result += "\n" + G1MParser.convert(str.substring(0, str.indexOf("\0", str.length()-4))); + } + + + return result; + } +} diff --git a/B2C/src/b2c/Parser.java b/B2C/src/b2c/Parser.java new file mode 100644 index 0000000..42ccfeb --- /dev/null +++ b/B2C/src/b2c/Parser.java @@ -0,0 +1,1032 @@ +package b2c; + +import java.util.ArrayList; +import java.util.Arrays; + +public class Parser { + + final static int NO_OPTION = 0; + final static int WHOLE_INSTRUCTION = 1; + final static int CONV_TO_BCD = 2; + final static int CONV_TO_INT = 3; + + static String tabs = "\t"; + + //Be sure to clear these variables between programs. + static ArrayList instructions = new ArrayList(); + static int instructionNumber = 0; + static int nbBuffers = 0; + + + public static String parse(String content) { + return parse(content, NO_OPTION); + } + + /* This is the main method for the parsing. + * It recursively parses each instruction it receives. + * Note that instructions must not have the \r at the end, or any \r at all. + * It obviously assumes that the instruction is valid Basic Casio code. + * + * When adding a method returning a value, always declare it like this: + * + * if (content.startsWith(method) { + * return supportAns(isWholeInstruction, ); + * } + * + * This is to provide support for the Ans variable. + */ + + public static String parse(String content, int option) { + + String instruction = ""; + for (int i = 0; i < content.length(); i++) { + if (content.charAt(i) >= 32 && content.charAt(i) < 127) { + instruction += content.charAt(i) + " "; + } else { + String hex = Integer.toHexString(content.charAt(i)); + instruction += "0x" + hex + " "; + if (hex.length() > 2) { + error("Unhandled unicode character u+" + hex.length()); + } + } + } + System.out.println("Parsing instruction: " + instruction); + + + + if (content.equals("")) { + return ""; + } + + int matchResult = -1; + + //comment + if (content.startsWith("'")) { + return "//"+content.substring(1); + } + + //instruction colon ':' that counts as a \r + matchResult = checkMatch(content, ":"); + if (matchResult >= 0) { + instructions.add(instructionNumber, content.substring(matchResult+1)); + return parse(content.substring(0, matchResult), WHOLE_INSTRUCTION) + "\n" + tabs + + parse(content.substring(matchResult+1), WHOLE_INSTRUCTION); + } + + if (content.startsWith("\"") && option == WHOLE_INSTRUCTION) { + System.out.println("Hardcoded string detected, removing it..."); + return ""; + } + + + + //The easy functions: those that always have their arguments after, AND that don't return anything. (exception of =>) + //Functions like Int or Frac have their arguments after but return a value so they can be used in a calculation. + //Those are listed in the alphabetical order of their opcodes. + //So List (0x7F51) is above Lbl (0xE2) which is above If (0xF700). (again, exception of => which is after IfEnd) + + //RanInt#( + /*if (content.startsWith(new String(new char[]{0x7F,0x87}))) { + if (content.charAt(content.length()-1) == ')') { + content = content.substring(0, content.length()-1); + } + Integer[] args = parseArgs(content); + if (args.length != 1) { + error("RanInt# method doesn't have 2 arguments!"); + } + return supportAns("B2C_ranInt(" + parse(content.substring(2, args[0]), CONV_TO_BCD) + "," + + parse(content.substring(args[0]+1), CONV_TO_BCD) + ")", option); + + }*/ + + //Getkey + if (content.startsWith(new String(new char[]{0x7F,0x8F}))) { + if (content.length() > 2) { + error("Instruction begins by GetKey but includes something else!"); + } + + return supportAns("B2C_Getkey()", option); + } + + //Lbl + if (content.startsWith(new String(new char[]{0xE2}))) { + content = content.substring(1); //remove the Lbl to exploit the variable + if (content.equals(new String(new char[]{0xCD}))) { + content = "radius"; + } else if (content.equals(new String(new char[]{0xCE}))) { + content = "theta"; + } + return "Lbl_"+content+":;"; //the ';' is needed because you can place Lbls just before IfEnd/WhileEnd/Next + } + + //Goto + if (content.startsWith(new String(new char[]{0xEC}))) { + content = content.substring(1); //remove the Goto to exploit the variable + if (content.equals(new String(new char[]{0xCD}))) { + content = "radius"; + } else if (content.equals(new String(new char[]{0xCE}))) { + content = "theta"; + } + if (content.length() > 2) { + error("Instruction begins by Goto but includes something else!"); + } + String[] gotosAreBad = { + "Gotos are the root of all evil.", + "I know you're writing in basic but still... gotos?", + "Get that goto out of there, we're not in assembly.", + "I sincerely hope you're not using that goto for a loop. Else you need to learn about do/while.", + "This is justified if and only if you are using this goto for a Menu.", + "You're lucky gotos work in C the exact way they do in basic.", + "Gotos are bad and you should feel bad.", + "The use of gotos in your program makes it read like a \"Chose your own adventure\" book.", + "http://xkcd.com/292/", + "If you're using that to break out of nested loops... I'll allow it.", + "Like this converted code wasn't unreadable enough.", + }; + String result = "goto Lbl_"+content+";"; + if (Math.random() > 0.9) { + result += " //" + Arrays.asList(gotosAreBad).get((int)(Math.random()*gotosAreBad.length)); + } + return result; + } + + //Prog + if (content.startsWith(new String(new char[]{0xED}))) { + String result = content.substring(1); + + if (result.charAt(0) == '"') { + result = result.substring(1); + } + if (result.charAt(result.length()-1) == '"') { + result = result.substring(0, result.length()-1); + } + + return "prog_"+parseProgName(result)+"();"; + } + + //If + if (content.startsWith(new String(new char[]{0xF7,0x00}))) { + incrementTabs(); + return "if ((*" + parse(content.substring(2), CONV_TO_BCD) + ")[1]) {"; + } + + //Then + if (content.startsWith(new String(new char[]{0xF7,0x01}))) { + return parse(content.substring(2), WHOLE_INSTRUCTION); + } + + //Else + if (content.startsWith(new String(new char[]{0xF7,0x02}))) { + decrementTabs(); + String result = "\n" + tabs + "} else {\n"; + incrementTabs(); + return result + tabs + parse(content.substring(2), WHOLE_INSTRUCTION); + + } + + //IfEnd ; it is always a single instruction + if (content.startsWith(new String(new char[]{0xF7,0x03}))) { + decrementTabs(); + if (content.length() > 2) { + error("Instruction begins by IfEnd but includes something else!"); + } + return "\n" + tabs + "}"; + } + + //inline if (double arrow '=>') + matchResult = checkMatch(content, new String(new char[]{0x13})); + if (matchResult >= 0) { + incrementTabs(); + String result = "if ((*" + parse(content.substring(0, matchResult), CONV_TO_BCD) + + ")[1]) {\n" + tabs + parse(content.substring(matchResult+1), WHOLE_INSTRUCTION) + "\n"; + decrementTabs(); + return result + "\n" + tabs + "}"; + } + + //For, To, Step + if (content.startsWith(new String(new char[]{0xF7,0x04}))) { + //Stocks the position of the "To", no need to check for strings because there are no strings in a for + int toPosition = content.indexOf(new String(new char[]{0xF7, 0x05})); + //Stocks the position of the -> + int assignmentPosition = content.indexOf((char)0x0E); + //Checks for "Step" + int stepPosition = content.indexOf(new String(new char[]{0xF7, 0x06})); + String variable = replaceNonAscii(content.substring(assignmentPosition+1, toPosition)); + System.out.println("Parsing a For instruction. Position of To is "+toPosition+ + ", position of -> is "+assignmentPosition+", position of Step is "+stepPosition+ + ", variable is: "+variable); + + //Check for empty for, which is replaced by Sleep() + if (instructions.get(instructionNumber+1).equals(new String(new char[]{0xF7, 0x07}))) { + System.out.println("Parsing empty for"); + String result = "Sleep("; + if (stepPosition >= 0) { + result += "Sleep(" + handleIntConversion(content.substring(toPosition+2, stepPosition)) + "/"+ + handleIntConversion(content.substring(stepPosition+2)); + } else { + result += handleIntConversion(content.substring(toPosition+2)); + } + instructionNumber++; + return result + ");"; + } + incrementTabs(); + String result = "for ("; + //variable = beginning; + result += parse(content.substring(2, toPosition)) + ";"; + + //TODO: parse the step as an integer to know if it is <0 or >0 + //also put the break condition in the for + if (stepPosition >= 0) { + //step < 0 && var >= limit || step > 0 && var <= limit; variable = variable + step) { + String step = replaceNonAscii(content.substring(stepPosition+2)); + System.out.println("Step = " + step); + String limit = replaceNonAscii(content.substring(toPosition+2, stepPosition)); + result += " (*B2C_calcExp((unsigned char*)\""+step+"<0\\x7F\"\"\\xB0\"\""+variable+"\\x12\"\""+limit+"\\x7F\"\"\\xB1\"\""+step+">0\\x7F\"\"\\xB0\"\""+variable+"\\x10\"\""+limit+"\"))[1]" + "; " + + parse(variable+(char)0x89+step+(char)0x0E+variable) + ") {"; + //+ "\n" + tabs + "if ((*B2C_calcExp((unsigned char*)\""+step+"<0\\x7F\"\"\\xB0\"\""+variable+"<"+limit+"\\x7F\"\"\\xB1\"\""+step+">0\\x7F\"\"\\xB0\"\""+variable+">"+limit+"\"))[1]) break;"; + } else { + //variable <= limit; variable = variable + 1) {" + result += " (*B2C_calcExp((unsigned char*)\"" + variable + "\\x10\"\"" + replaceNonAscii(content.substring(toPosition+2)) + "\"))[1]; " + + parse(variable + (char)0x89 + "1" + (char)0x0E + variable) + ") {"; + } + + return result; + } + + //Next ; like IfEnd + if (content.startsWith(new String(new char[]{0xF7,0x07}))) { + if (content.length() > 2) { + error("Instruction begins by Next but includes something else!"); + } + decrementTabs(); + return "\n"+tabs+"}"; + } + + //While + if (content.startsWith(new String(new char[]{0xF7,0x08}))) { + incrementTabs(); + return "while ((*" + parse(content.substring(2), CONV_TO_BCD) + ")[1]) {"; + } + + //WhileEnd + if (content.startsWith(new String(new char[]{0xF7,0x09}))) { + if (content.length() > 2) { + error("Instruction begins by WhileEnd but includes something else!"); + } + decrementTabs(); + return "\n" + tabs + "}"; + } + + //Do + if (content.startsWith(new String(new char[]{0xF7,0x0A}))) { + if (content.length() > 2) { + error("Instruction begins by Do but includes something else!"); + } + incrementTabs(); + return "do {"; + } + + //LpWhile + if (content.startsWith(new String(new char[]{0xF7,0x0B}))) { + decrementTabs(); + return "\n" + tabs + "} while ((*" + parse(content.substring(2)) + ")[1]);"; + } + + //Return + if (content.startsWith(new String(new char[]{0xF7,0x0C}))) { + if (content.length() > 2) { + error("Instruction begins by Return but includes something else!"); + } + return "return;"; + } + + //Break + if (content.startsWith(new String(new char[]{0xF7,0x0D}))) { + if (content.length() > 2) { + error("Instruction begins by Break but includes something else!"); + } + return "break;"; + } + + //Stop + if (content.startsWith(new String(new char[]{0xF7,0x0E}))) { + if (content.length() > 2) { + error("Instruction begins by Stop but includes something else!"); + } + return "B2C_stop();"; + } + + //Locate + if (content.startsWith(new String(new char[]{0xF7,0x10}))) { + Integer[] args = parseArgs(content); + return "locate(" + handleIntConversion(content.substring(2, args[0])) + ", " + + handleIntConversion(content.substring(args[0]+1, args[1])) + + "); Print((unsigned char*)" + + parseStr(content.substring(args[1]+1)) + "); ML_display_vram();"; + } + + //ClrText + if (content.startsWith(new String(new char[]{0xF7,0x18}))) { + if (content.length() > 2) { + error("Instruction begins by ClrText but includes something else!"); + } + return "ML_clear_vram();"; + } + + + + //End of starting functions. At this point the instruction is likely a mathematical operation, or a string, + //or a variable assignment. Note that it can have functions inside, like the factorial or nCr function. + + if (content.startsWith("\"") || content.startsWith(new String(new char[]{0xF9, 0x3F}))) { //it is a standalone string + return parseStr(content); + } + + //Check for assignment + + matchResult = checkMatch(content, new String(new char[]{0x0E})); + if (matchResult >= 0) { + + //Check for the Dim assignment case; in this case it's not an assignment but a method calling + if (content.substring(matchResult+1).startsWith(new String(new char[]{0x7F, 0x46}))) { + //The assignment is followed by a Dim. Now check if it's to a List or a Mat + System.out.println("Parsing a Dim assignment."); + + if (content.substring(matchResult+3).startsWith(new String(new char[]{0x7F, 0x40}))) { //followed by Mat + String result = "B2C_setDimMat('" + content.charAt(matchResult+5) + "', "; + if (content.startsWith(new String(new char[]{0x7F, 0x51}))) { + result += handleIntConversion(parse(content.substring(0, matchResult) + "[1]")) + ", "; + result += handleIntConversion(parse(content.substring(0, matchResult) + "[2]")) + ");"; + return result; + } else if (content.startsWith("{")) { + Integer[] commaPos = parseArgs(content.substring(1, matchResult)); + if (commaPos.length != 1) { + error("List must consist of 2 numbers!"); + } + result += content.substring(1, commaPos[0]+1) + ", "; + if (content.charAt(matchResult-1) != '}') { + content = content.substring(0, matchResult) + '}' + content.substring(matchResult); + matchResult++; + } + result += content.substring(commaPos[0]+2, matchResult-1) + ");"; + return result; + } else { + error("Unknown mat assignment"); + } + + } else if (content.substring(matchResult+3).startsWith(new String(new char[]{0x7F, 0x51}))) { //followed by List + return "B2C_setDimList(" + handleIntConversion(content.substring(matchResult+5)) + ", " + + handleIntConversion(content.substring(0, matchResult)) + ");"; + } else { + error("Dim instruction is not followed by List or Mat!"); + } + + //Check for '~' operator + } else if (content.substring(matchResult+1).matches("[A-Z]~[A-Z]")) { + String assignment = parse(content.substring(0, matchResult), CONV_TO_BCD); + incrementTabs(); + String result = "for (i = '"+content.charAt(matchResult+1)+"'; i <= '"+content.charAt(matchResult+3)+"'; i++) {\n"+tabs+"B2C_setAlphaVar(i, "+assignment+");\n"; + decrementTabs(); + return result + tabs + "}"; + + //Check for list assignment + } else if (content.substring(matchResult+1).startsWith(new String(new char[]{0x7F, 0x51}))) { + Integer[] check = parseBrackets(content.substring(matchResult+1)); + + if (check.length > 0) { + if (check.length == 2 && matchResult+1+check[1] == content.length()-1) { + content = content.substring(0, content.length()-1); + } + String result = "B2C_setListRow(" + handleIntConversion( + content.substring(matchResult+3, matchResult+1+check[0])) + + ", " + handleIntConversion( + content.substring(matchResult+2+check[0], content.length())) + + ", " + parse(content.substring(0, matchResult), CONV_TO_BCD) + ");"; + return result; + } + + //Check for Mat assignment + } else if (content.substring(matchResult+1).startsWith(new String(new char[]{0x7F, 0x40}))) { + //Account for possible unmatched bracket + if (content.charAt(content.length()-1) != ']') { + content += ']'; + } + Integer[] check = parseArgs(content.substring(matchResult+5, content.length()-1)); + + if (check.length != 1) { + error("Mat instruction does not have one comma!"); + } + String result = "B2C_setMat('" + content.charAt(matchResult+3) + "', " + + handleIntConversion(content.substring(matchResult+5, matchResult+5+check[0])) + ", " + + handleIntConversion(content.substring(matchResult+5+check[0]+1, content.length()-1)) + ", " + + parse(content.substring(0, matchResult), CONV_TO_BCD) + ");"; + + return result; + + /*if (check.length > 0) { + if (check.length == 2 && matchResult+1+check[1] == content.length()-1) { + content = content.substring(0, content.length()-1); + } + String result = "B2C_setMat(" + handleIntConversion( + content.substring(matchResult+3, matchResult+1+check[0])) + + ", " + handleIntConversion( + content.substring(matchResult+2+check[0], content.length())) + + ", " + parse(content.substring(0, matchResult), CONV_TO_BCD) + ");"; + return result; + }*/ + + //Check for variable assignment + } else if (content.substring(matchResult+1).matches("[A-Z\\xCD\\xCE\\xC0]")) { + String result = "B2C_setAlphaVar('"; + if (content.charAt(matchResult+1) >= 'A' && content.charAt(matchResult+1) <= 'Z') { + result += content.charAt(matchResult+1); + } else { + result += "\\x" + Integer.toHexString(content.charAt(matchResult+1)); + } + result += "', " + parse(content.substring(0, matchResult), CONV_TO_BCD) + ")"; + if (option == WHOLE_INSTRUCTION) { + result += ";"; + } + return result; + } else { + error("Unknown assignment!"); + } + + } + + //at this point it is a mathematical operation + //stock the level of the parentheses + Integer[] parenthesesPos = parseBrackets(content); + + //Mat + if (content.startsWith(new String(new char[]{0x7F,0x40}))) { + System.out.println("Parsing a matrix"); + //Before parsing, we must check if the entire instruction is a Mat instruction + Integer[] check = parseBrackets(content); + Integer[] arg = parseArgs(content.substring(check[0]+1, check[1])); + if (check[1] == content.length()-1) { + if (arg.length != 1) { + error("matrix coordinates are fewer or more than two!"); + } else { + return supportAns("mat[" + (content.charAt(2)-'A') + "].data[mat[" + (content.charAt(2)-'A') + "].width*(" + + handleIntConversion(parse(content.substring(check[0]+1, check[0]+1+arg[0]))) + ")+(" + + handleIntConversion(parse(content.substring(check[0]+2+arg[0],content.length()-1))) + ")]", option); + } + + } + + } + + //Dim ; for now it cannot parse it automatically, need to wait for the getNextArg() function + //TODO do getNextArg() + if (content.startsWith(new String(new char[]{0x7F,0x46}))) { + + return "Dim " + parse(content.substring(2)); + + } + + //List + if (content.startsWith(new String(new char[]{0x7F,0x51}))) { + System.out.println("Parsing a list"); + //Before parsing, we must check if the entire instruction is a List instruction + Integer[] check = parseBrackets(content); + + if (check.length == 2 && check[1] == content.length()-1 || option == WHOLE_INSTRUCTION && check.length > 0) { + if (check.length == 2 && check[1] == content.length()-1) { + content = content.substring(0, content.length()-1); + } + return supportAns("list[" + handleIntConversion(parse(content.substring(2, check[0]))) + "].data[" + + handleIntConversion(parse(content.substring(check[0]+1, content.length()))) + "]", option); + } + } + + //searches for an operator + String[] operators = { + new String(new char[]{0x7F, 0xB0}), //And + new String(new char[]{0x7F, 0xB1}), //Or + new String(new char[]{0x7F, 0xB4}), //Xor + new String(new char[]{0x10}), //<= + new String(new char[]{0x11}), //!= + new String(new char[]{0x12}), //>= + "=", + "<", + ">", + new String(new char[]{0xA8}), // ^ + new String(new char[]{0xA9}), // * + new String(new char[]{0xB9}), // / + new String(new char[]{0x89}), // + + new String(new char[]{0x99}), // - + new String(new char[]{0x7F, 0xB3}) //Not + }; + + for (int i = 0; i < operators.length; i++) { + for (int j = 0; j < content.length(); j++) { + if (content.startsWith(operators[i], j)) { + //test if the operator is not within parentheses + boolean isInParentheses = false; + for (int k = 0; k < parenthesesPos.length; k+=2) { + if (j >= parenthesesPos[k] && j <= parenthesesPos[k+1]) { + isInParentheses = true; + } + } + //If the operator is at the beginning of the string, it isn't a binary operator + if (!isInParentheses && j != 0) { + String str = ""; + + switch(i) { + case 0: + str = "B2C_and("; + break; + case 1: + str = "B2C_or("; + break; + case 2: + str = "B2C_xor("; + break; + case 3: + str = "B2C_lessOrEqualThan("; + break; + case 4: + str = "B2C_notEqualTo("; + break; + case 5: + str = "B2C_greaterOrEqualThan("; + break; + case 6: + str = "B2C_equalTo("; + break; + case 7: + str = "B2C_lessThan("; + break; + case 8: + str = "B2C_greaterThan("; + break; + case 9: // ^ + str = "B2C_pow("; + break; + case 10: // * + str = "B2C_mult("; + break; + case 11: // / + str = "B2C_div("; + break; + case 12: // + + str = "B2C_add("; + break; + case 13: // - + str = "B2C_sub("; + break; + } + + str += "&buffer" + nbBuffers + ", "; + nbBuffers++; + if (i <= 2) { + str += parse(content.substring(0, j), CONV_TO_BCD) + ", " + parse(content.substring(j+2), CONV_TO_BCD) + ")"; + } else if (i < 14){ + str += parse(content.substring(0, j), CONV_TO_BCD) + ", " + parse(content.substring(j+1), CONV_TO_BCD) + ")"; + } else { + str += "B2C_not(" + parse(content.substring(2)) + ")"; + } if (option == WHOLE_INSTRUCTION) { + str += ";"; + } + return str; + } + + } + if (isMultibytePrefix(content.charAt(j))) { + j++; + } + } + } + + //this only occurs if the entire string is within parentheses, such as "(2+3)" + if (parenthesesPos.length == 2 && parenthesesPos[0] == 0 && parenthesesPos[1] == content.length()-1) { + return "(" + parse(content.substring(1, content.length()-1)) + ")"; + } + + //replace variables with their position in the var[] array; only do this if the string only contains the variable + if (content.length() == 1 && !content.matches("^\\d")) { + String result = ""; + if (content.charAt(0) >= 'A' && content.charAt(0) <= 'Z') { + result += "var[" + (int)(content.charAt(0)-65) + "]"; + } + if (content.charAt(0) == (char)0xC0) { + result += "Ans"; + } + if (content.charAt(0) == (char)0xCD) { //r + result += "var[26]"; + } + if (content.charAt(0) == (char)0xCE) { //theta + result += "var[27]"; + } + + return supportAns(result, option); + } + + //Test if it is a number (note that it can be something like 2X, implicit multiplication) + if (content.matches("^[\\d\\x99\\.](.+)?")) { + int testForImplicitMultiplication = -1; + for (char i = '0'; i <= '9'; i++) { + if (testForImplicitMultiplication < content.lastIndexOf(i)) { + testForImplicitMultiplication = content.lastIndexOf(i); + } + } + if (testForImplicitMultiplication != content.length()-1) { + return supportAns("B2C_mult(" + parse(content.substring(0, testForImplicitMultiplication+1), CONV_TO_BCD) + + ", " + parse(content.substring(testForImplicitMultiplication+1, content.length())) + ")", option); + } + //At this point it is a number, add it to constants + Constants.add(content); + String result = ""; + if (option == WHOLE_INSTRUCTION || option == CONV_TO_BCD) { + /*if (content.matches("\\d")) { + result += consts[Integer.valueOf(content)]; + } else if (content.equals("10")) { + result += consts[10]; + } else { + result = "B2C_convToBCD(\"" + content + "\")"; + }*/ + result += "&"+Constants.getVarNotation(content); + } else { + result = content; + } + if (option == WHOLE_INSTRUCTION) { + return supportAns(result, option); + } + return result; + } + + //At this point it is a calculation, check for calculations functions + String result = ""; + if (content.matches("\\d+")) { + //Parse numbers as a global variable (for example, 36 is replaced by a const BCDvar _36 which value is calculated at the beginning). + if (!Constants.consts.contains(Integer.parseInt(content))) { + Constants.add(content); + } + result += "&" + Constants.getVarNotation(content); + return result; + //Check if it is a lone variable + } else if (content.matches("[A-Z\\xCD\\xCE\\xC0]")) { + result += handleAlphaVar(content, option); + return result; + } /*else { + result += "B2C_calcExp((unsigned char*)" + parseStr("\"" + content + "\"") + ")"; + return result; + }*/ + //return supportAns(result, option); + + //At this point in the code, the method must have already returned + //if it has detected at least one instruction it understands + + error("function in the instruction above not recognized!"); + return ""; + } + + /* This function is called to parse hardcoded lists (written like {1,2,3}). + * At the moment the only functions calling this method are: + * - Assignment operation on Dim Mat ({1,2}->Dim Mat M) + * - Assignment operation on List ({1,2}->List 3) + * - Multi/Super drawstat (Graph(X,Y)=({1,2},{3,4}); + */ + + public static String parseList(String content) { + String result = "B2C_newList("; + + //Check if the list is hardcoded or not + if (content.startsWith(new String(new char[]{0x7F, 0x51}))) { + return parse(content); + } + if (content.charAt(0) != '{') { + error("Trying to parse hardcoded list but the list doesn't begin with a '{'!"); + return ""; + } + + + if (content.charAt(content.length()-1) == '}') { + content = content.substring(0, content.length()-1); + } + + System.out.println("Parsing a hardcoded list: "+content); + //remove the leading '{' for easier argument parsing + content = content.substring(1); + + ArrayList args = new ArrayList(); + args.addAll(Arrays.asList(parseArgs(content.substring(0)))); + args.add(content.length()); + + System.out.println(args.toString()); + result += args.size() + ", "; + result += parse(content.substring(0, args.get(0)), CONV_TO_BCD) + ", "; + for (int i = 0; i < args.size()-1; i++) { + result += parse(content.substring(args.get(i)+1, args.get(i+1)), CONV_TO_BCD) + ", "; + } + + //remove the last comma + return result.substring(0, result.length()-2) + ")"; + } + + /* This method checks for the presence of the string match in the string content. + * This can't be done with traditional methods because it must checks if the match + * string is in the content string AND not in a string. + * + * Returns -1 if the value doesn't exist, or the beginning of the first occurence of the match. + * + * Examples: + * + * checkMatch("Locate 1,1,\"=> First option\"", "=>") will return -1, + * because there is a '=>' but inside a string. + * + * checkMatch("A>B => Locate 1,1,C", "=>") will return 4. + * + */ + + public static int checkMatch(String content, String match) { + + boolean positionIsString = false; + for (int i = 0; i < content.length(); i++) { + if (content.charAt(i) == (char)0x7F || + content.charAt(i) == (char)0xF7 || + content.charAt(i) == (char)0xE5 || + content.charAt(i) == (char)0xE6 || + content.charAt(i) == (char)0xE7) { + i += 2; + if (i >= content.length()) { + break; + } + } + if (content.substring(i).startsWith(match) && !positionIsString) { + return i; + } + if (content.charAt(i) == '"') { + positionIsString = !positionIsString; + } else if (content.charAt(i) == '\\') { + i++; + } + + } + + + return -1; + } + + public static String parseProgName(String content) { + //The use of replaceAll is possible because you can't have multi byte characters in program names + String[] specialChars = { + "\\{", "\\}", + "\\[", "\\]", + "\\.", + "\"", + " ", + "\\xA9|\\*", + "\\xB9|\\/", + "\\x99|-", + "\\x89|\\+", + "\\xCD", + "\\xCE", + "'", + "~", + "\0" + }; + String[] replacements = { + "lcurlybracket", + "rcurlybracket", + "lbracket", + "rbracket", + "dot", + "quote", + "space", + "mult", + "div", + "sub", + "add", + "radius", + "theta", + "apos", + "tilde", + "" + }; + for (int i = 0; i < specialChars.length; i++) { + content = content.replaceAll(specialChars[i], replacements[i]); + } + content = content.replaceAll("[^ -~]", "_"); //replace non-ASCII characters + return content; + } + + /* This method parses a string. It is designed to parse things like: + * Str 1 + "test" + Str 2 + * + * The main parse() method only calls this method in case of an argument that is always a string, + * for the functions Locate, Text and standalone strings. + * + */ + + public static String parseStr(String content) { + System.out.println("Parsing string: "+content); + if (content.startsWith("\"")/* || content.startsWith(new String(new char[]{0xF9, 0x3F}))*/) { + if (content.startsWith("\"") && content.charAt(content.length()-1) != '"') { + content += '"'; + } + content = replaceNonAscii(content); + return content; //TODO parse Str function + } + return "B2C_convToStr(" + handleAlphaVar(content, NO_OPTION) + ")"; + } + + //Replace non-ASCII characters with \xXX, using string concatenation. + public static String replaceNonAscii(String content) { + for (int i = 0; i < content.length(); i++) { + if (content.charAt(i) < ' ' || content.charAt(i) > '~') { + String result = content.substring(0, i); + result += "\\x"; + String str = Integer.toHexString(content.charAt(i)); + if (str.length() > 2) { + error("Unicode character u" + str + "!"); + } else { + result += str; + } + + //if (i < content.length()-1) + result += "\"\""; + result += content.substring(i+1); + content = result; + + } + } + return content; + } + + /* This method parses comma-separated arguments. It is used to parse any function + * with those kind of arguments. It is needed because the arguments themselves may have + * commas (example: Locate 1,Mat M[A,B],Str 1). + * + * Note that it doesn't return the arguments themselves, but the position of the commas, that + * must be exploited by the parser. + * + */ + public static Integer[] parseArgs(String content) { + System.out.println("Parsing arguments: "+content); + ArrayList args = new ArrayList(); + int argsBuffer = 0; + boolean positionIsString = false; + for (int i = 0; i < content.length(); i++) { + + if (content.charAt(i) == ',' && argsBuffer == 0 && !positionIsString) { + args.add(i); + } + if ((content.charAt(i) == '(' || content.charAt(i) == '[' || content.charAt(i) == '{') && !positionIsString) { + argsBuffer++; + } else if ((content.charAt(i) == ')' || content.charAt(i) == ']' || content.charAt(i) == '}') && !positionIsString) { + argsBuffer--; + } else if (content.charAt(i) == '"') { + positionIsString = !positionIsString; + } else if (content.charAt(i) == '\\') { + i++; + } + if (isMultibytePrefix(content.charAt(i))) { + i++; + } + + } + //System.out.println("Result:"+args.toString()); + return args.toArray(new Integer[args.size()]); + } + + /** + * This function returns the index of each first-level opening and closing brackets/parentheses. + * Example: the string "3*(4*(5+6))+(4*5)" will return {2, 10, 12, 16}. + * It accounts for unmatched brackets at the end, so "2->Mat M[1,3" will return the same as "2->Mat M[1,3]". + */ + public static Integer[] parseBrackets(String content) { + ArrayList bracketsPos = new ArrayList(); + int bracketsLevel = 0; + boolean currentPositionIsString = false; + for (int i = 0; i < content.length(); i++) { + if ((content.charAt(i) == '(' || content.charAt(i) == '[' || content.charAt(i) == '{') && !currentPositionIsString) { + bracketsLevel++; + if (bracketsLevel == 1) { + bracketsPos.add(i); + } + } else if ((content.charAt(i) == ')' || content.charAt(i) == ']' || content.charAt(i) == '}') && !currentPositionIsString) { + bracketsLevel--; + if (bracketsLevel == 0) { + bracketsPos.add(i); + } else if (bracketsLevel < 0) { + error("brackets level below 0!"); + } + } else if (content.charAt(i) == '"') { + currentPositionIsString = !currentPositionIsString; + } else if (content.charAt(i) == '\\') { + i++; + } else if (isMultibytePrefix(content.charAt(i))) { + i++; + } + } + //This should take care of unmatched brackets at the end + while (bracketsLevel > 0) { + bracketsPos.add(content.length()); + bracketsLevel--; + } + + return bracketsPos.toArray(new Integer[bracketsPos.size()]); + } + + /* This method replaces some basic functions (listed below). + * Reason for this method is to avoid replacing functions in strings, which can't be done with replaceAll(). + * The replacements are the following: + * + * 0x99 (-) and 0x87 (-) by '-' + * 0x89 (+) by '+' + * 0xA8 (^) by '^' + * 0xA9 (*) by '*' + * 0xB9 (/) by '/' + * + * It it not used at the moment. + */ + /*public static StringBuilder autoreplace(StringBuilder result) { + boolean positionIsString = false; + for (int i = 0; i < result.length(); i++) { + + if (result.charAt(i) == (char)0x99) { + result.setCharAt(i, '-'); + } + if (result.charAt(i) == (char)0x87 && !positionIsString) { + result.setCharAt(i, '-'); + } + if (result.charAt(i) == (char)0x89) { + result.setCharAt(i, '+'); + } + if (result.charAt(i) == (char)0xA8) { + result.setCharAt(i, '^'); + } + if (result.charAt(i) == (char)0xA9) { + result.setCharAt(i, '*'); + } + if (result.charAt(i) == (char)0xB9) { + result.setCharAt(i, '/'); + } + if (result.charAt(i) == '"') { + positionIsString = !positionIsString; + } else if (result.charAt(i) == '\\') { + i++; + } + if (isMultibytePrefix(result.charAt(i))) { + i++; + } + + } + return result; + + + }*/ + + public static boolean isMultibytePrefix(char prefix) { + if (prefix == (char)0xF7 || + prefix == (char)0x7F || + prefix == (char)0xE5 || + prefix == (char)0xE6 || + prefix == (char)0xE7) + return true; + return false; + } + + public static String supportAns(String content, int option) { + if (option == WHOLE_INSTRUCTION) + return "B2C_setAlphaVar('\\xC0', " + content + ");"; + return content; + } + + public static String handleIntConversion(String content) { + //TODO: optimise some cases like "A+2" where you could convert A then add 2 + //instead of calculating "A+2" in BCD + if (content.matches("\\d+")) { + return content; + } + return "B2C_convToUInt(" + parse(content) + ")"; + } + + public static String handleAlphaVar(String content, int option) { + if (content.matches("[A-Z\\xCD\\xCE\\xC0]")) { + String result = "B2C_getAlphaVar('"; + if (content.charAt(0) >= 'A' && content.charAt(0) <= 'Z') { + result += content; + } else { + result += "\\x" + Integer.toHexString(content.charAt(0)); + } + result += "')"; + return supportAns(result, option); + } + return parse(content, option); + } + + public static void incrementTabs() { + tabs += "\t"; + } + public static void decrementTabs() { + tabs = tabs.substring(0, tabs.length()-1); + } + + public static void error(String error) { + System.out.println("\n===ERROR: "+error+"===\n"); + System.exit(0); + } +} diff --git a/B2C/src/b2c/Syscalls.java b/B2C/src/b2c/Syscalls.java new file mode 100644 index 0000000..5fe6813 --- /dev/null +++ b/B2C/src/b2c/Syscalls.java @@ -0,0 +1,40 @@ +package b2c; + +import java.io.File; +import java.util.ArrayList; + +public class Syscalls { + + //Not much to explain here. Look at a generated file to get an idea of what this does + + static String syscallContent = ""; + static ArrayList syscalls = new ArrayList(); + static ArrayList syscallIDs = new ArrayList(); + + public static void addSyscall(String syscall, String syscallID) { + syscalls.add(syscall); + syscallIDs.add(syscallID); + } + + public static void createSyscallFile() { + for (int i = 0; i < syscalls.size(); i++) { + syscallContent += "\t.export\t_" + syscalls.get(i) + "\n"; + } + for (int i = 0; i < syscalls.size(); i++) { + syscallContent += + "\n_" + syscalls.get(i) + ":\n" + + "\tmov.l\tsyscall_table, r2\n" + + "\tmov.l\t_" + syscalls.get(i) + "_code, r0\n" + + "\tjmp\t@r2\n" + + "\tnop\n" + + "_" + syscalls.get(i) + "_code:\n" + + "\t.data.l\tH'" + syscallIDs.get(i) + "\n"; + } + syscallContent += + "\nsyscall_table:\n" + + "\t.data.l\tH'80010070\n\n" + + "\t.end"; + IO.writeToFile(new File(B2C.path + "/syscalls.src"), syscallContent, true); //TODO change to false when all syscalls are added + } + +} diff --git a/B2C/src/memory.c b/B2C/src/memory.c new file mode 100644 index 0000000..64aa485 --- /dev/null +++ b/B2C/src/memory.c @@ -0,0 +1,291 @@ +/****************************************************************/ +/* */ +/* Memory */ +/* */ +/* Description: Fonctions de manipulation de la memoire */ +/* Auteur: LePhenixNoir */ +/* Version: 3.0 */ +/* Date: 11.06.2014 */ +/* Fichier: memory.c - Code des fonctions */ +/* */ +/****************************************************************/ + +#ifndef __FXLIB_H__ + #include "fxlib.h" +#endif + +#ifndef _STDIO + #include +#endif + +#ifndef _STDLIB + #include +#endif + +#ifndef _STRING + #include +#endif + +#include "memory.h" + +int memory_errors = 0; + +void memory_seterrors(int e) +{ + memory_errors = (e!=0); +} + +void memory_error(char *from, char *func, int val) +{ + unsigned int key; + char info[20]; + if(!memory_errors) return; + + sprintf(info,"%d",val); + PopUpWin(6); + + locate(4,2); Print((unsigned char *)"Memory ERROR !!"); + locate(3,4); Print((unsigned char *)"FROM:"); + locate(8,4); Print((unsigned char *)from); + locate(3,5); Print((unsigned char *)"FUNC:"); + locate(8,5); Print((unsigned char *)func); + locate(3,6); Print((unsigned char *)"INFO:"); + locate(8,6); Print((unsigned char *)info); + locate(3,7); Print((unsigned char *)"META:"); + locate(8,7); + + switch(val) + { + case 1: Print((unsigned char *)"NotEnoughRAM"); break; + case -1: Print((unsigned char *)"Nonexisting"); break; + case -5: Print((unsigned char *)"WrongDevice"); break; + case -8: Print((unsigned char *)"AccessDenied"); break; + case -14: Print((unsigned char *)"ReadOnly"); break; + case -31: Print((unsigned char *)"DeviceError"); break; + case -35: Print((unsigned char *)"NotEmpty"); break; + default: Print((unsigned char *)"Other"); break; + } + GetKey(&key); +} + +FONTCHARACTER *memory_char2font(char *adresse) +{ + FONTCHARACTER *adr; + int i; + + adr = calloc((strlen(adresse)+1),sizeof(FONTCHARACTER)); + for(i=0;i3?3:n);t++) + { + if(icoind[offset+i]!=255) for(i=0;i<32;i++) { + k = icons[icoind[offset+t]][i]; + for(j=0;j<8;j++) { + if(k&1) Bdisp_SetPoint_VRAM(11-j+8*(i&1),20*t+4+(i>>1),1); + k >>= 1; } } + PrintXY(24,20*t+9,(const unsigned char *)*(files+offset+t),0); + } + Bdisp_DrawLineVRAM(2,20*p+3,2,20*p+20); + Bdisp_DrawLineVRAM(3,20*p+2,99,20*p+2); + Bdisp_DrawLineVRAM(3,20*p+21,99,20*p+21); + Bdisp_DrawLineVRAM(100,20*p+3,100,20*p+20); + if(offset>0) PrintXY(114,6,(const unsigned char *)"\346\234",0); + if(offset+3