Added str functions

This commit is contained in:
Zezombye 2017-01-08 20:03:49 +01:00
parent d56af7f194
commit cd901db577
6 changed files with 433 additions and 187 deletions

View File

@ -478,6 +478,9 @@ void B2C_exit(int exitCode) {
case MEMORY_ERROR:
locate(4,3); Print((unsigned char*)"Erreur m\xE6""\x0A""moire");
break;
case ARG_ERROR:
locate(4,3); Print((unsigned char*)"Erreur argument");
break;
}
locate(4,5); Print((unsigned char*)"Appuyer:[EXIT]");
@ -534,106 +537,153 @@ BCDvar *B2C_calcExp(unsigned char* exp) {
void B2C_setAlphaVar(BCDvar *alphaVar, BCDvar *value) {
memcpy(*alphaVar, *value, sizeof(BCDvar)-3);
}
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);
void B2C_setStr(Str *str, Str *value, int isString) {
free(str->data);
str->length = value->length;
str->data = malloc(value->length*2);
memcpy(str->data, value->data, value->length*2);
free_str(value);
}
unsigned char* B2C_strToCharArray(Str *str, int isString) {
int j = 0;
//Initialize the buffer
memset(stringBuffer, 0x00, 256);
memset(stringBuffer, 0x00, 512);
//Goes through the string, starting at 2
for (i = 2; i <= (str->length+1) * 2; i++) {
for (i = 0; i < str->length; i++) {
//Skip null bytes
if (str->data[i]) {
stringBuffer[j] = str->data[i];
if ((str->data[i])&0xFF00) {
stringBuffer[j] = (((str->data[i])&0xFF00)>>8);
j++;
}
//There is normally no need to skip null bytes here
//if ((str->data[i])&0x00FF) {
stringBuffer[j] = ((str->data[i])&0x00FF);
j++;
//}
}
free_str(str);
return stringBuffer;
}
Str *B2C_charArrayToStr(unsigned char* charArray) {
int strPos = 2;
int strPos = 0;
unsigned short currentChar;
Str *result = malloc(sizeof(Str));
result->data = calloc(strlen((char*)charArray)+1, 2);
result->length = 0;
result->data = calloc(strlen((char*)charArray), 2);
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++;
currentChar = 0;
if (charArray[i] == 0xE5 ||
charArray[i] == 0xE6 ||
charArray[i] == 0xE7 ||
charArray[i] == 0xF7 ||
charArray[i] == 0xF9 ||
charArray[i] == 0x7F) {
currentChar = charArray[i] << 8;
i++;
}
result->data[strPos] = charArray[i];
result->data[strPos] = currentChar + charArray[i];
strPos++;
}
result->length = (strPos-2)/2;
result->length = strPos;
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_;
BCDvar *B2C_strCmp(BCDvar *buffer, Str *str1, int isString1, Str *str2, int isString2) {
int j, isString = isString1;
for (i = 0; i < str1->length && i < str1->length; i++) {
//Case 1, most common: both characters are single bytes
if (!(str1->data[i]&0xFF00) && (str2->data[i]&0xFF00)) {
if (str1->data[i] < str2->data[i]) {
goto str1_lt_str2;
} else if (str1->data[i] > str2->data[i]) {
goto str1_gt_str2;
}
}
//Case 2: str1[i] is single byte, str2[i] is multi byte
//They can't be equal because the single byte at str1[i] can't match the multi byte prefix
else if (!(str1->data[i]&0xFF00)) {
if (str1->data[i] < (str2->data[i]>>8)) {
goto str1_lt_str2;
} else {
goto str1_gt_str2;
}
}
//Case 3: str1[i] is multi byte, str2[i] is single byte
else if (!(str2->data[i]&0xFF00)) {
if ((str1->data[i]>>8) < str2->data[i]) {
goto str1_lt_str2;
} else {
goto str1_gt_str2;
}
}
//Case 4: both are multi bytes
else {
if (str1->data[i] < str2->data[i]) {
goto str1_lt_str2;
} else if (str1->data[i] > str2->data[i]) {
goto str1_gt_str2;
}
}
}
//goto equalStrings;
//equalStrings:
buffer = &_0_;
goto freestrs;
str1_gt_str2:
buffer = &_1_;
goto freestrs;
str1_lt_str2:
buffer = &__1_;
//goto freestrs;
freestrs:
free_str(str1);
isString = isString2;
free_str(str2);
return &_0_;
return buffer;
}
BCDvar *B2C_strSrc(BCDvar *buffer, Str *str1, int isString1, Str *str2, int isString2, int n) {
int isString = isString1;
n--;
exitIfNeg(n);
for (i = n; i < str1->length-str2->length+1; i++) {
if (!memcmp(str1->data+i, str2->data+i, str2->length*2)) {
intToBCD(i+1, buffer);
goto freestrs;
}
}
//str_not_found:
buffer = &_0_;
freestrs:
free_str(str1);
isString = isString2;
free_str(str2);
return buffer;
}
Str *B2C_strInv(Str *str, int isString) {
Str *result = malloc(sizeof(Str));
result->data = malloc(2*(str->length+1));
result->data = malloc(2*str->length);
result->length = str->length;
for (i = 2*str->length; i >= 2; i -= 2) {
memcpy(result->data + 2*str->length-i, str->data + i, 2);
for (i = 0; i < str->length; i++) {
result->data[str->length-1-i] = str->data[i];
}
free_str(str);
return result;
}
Str *B2C_strJoin(Str *str1, Str *str2, int isString1, int isString2) {
Str *B2C_strJoin(Str *str1, int isString1, Str *str2, int isString2) {
int isString = isString1;
Str *result = malloc(sizeof(Str));
result->data = malloc(2*(str1->length + str2->length + 1));
result->data = malloc(2*(str1->length + str2->length));
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);
memcpy(result->data, str1->data, str1->length * 2);
memcpy(result->data+str1->length, str2->data, str2->length * 2);
free_str(str1);
isString = isString2;
free_str(str2);
@ -643,37 +693,47 @@ BCDvar *B2C_strLen(BCDvar *buffer, Str *str, int isString) {
intToBCD(str->length, buffer);
return buffer;
}
Str *B2C_strMid2args(Str *str, int isString, int start) {
//+1 because strings are 1-indexed in casio
return B2C_strMid(str, isString, start, str->length+1-start);
}
Str *B2C_strMid(Str *str, int isString, int start, int offset) {
Str *result = malloc(sizeof(Str));
if (!offset) {
start--; //In casio, strings are 1-indexed!
exitIfNeg(start);
exitIfNeg(offset);
if (offset+start > str->length) {
offset = str->length-start;
}
result->data = malloc((offset+2) * 2);
//Set null byte at the end
result->data[(offset+1) * 2] = 0x00;
if (start > str->length) {
start = str->length;
}
result->data = malloc(offset * 2);
result->length = offset;
//Copy the substring
memcpy(result->data + 2, str->data + start*2, 2*offset);
memcpy(result->data, str->data+start, 2*offset);
free_str(str);
return result;
}
Str *B2C_charAt(Str *str, int isString, int charPos) {
//Unused at the moment - not tested
Str *result = malloc(sizeof(Str));
result->data = malloc(3*2);
result->data[2*2] = 0x00;
charPos--; //In casio, strings are 1-indexed!
exitIfNeg(charPos);
result->data = malloc(2);
result->length = 1;
memcpy(result->data+2, str->data+charPos*2, 2);
result->data[0] = str->data[charPos];
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->data = malloc(str->length * 2);
memcpy(result->data, str->data, str->length * 2);
result->length = str->length;
for (i = 3; i <= result->length*2; i+=2) {
for (i = 0; i < result->length; i++) {
if (result->data[i] >= 'a' && result->data[i] <= 'z') {
result->data[i] -= 32;
}
@ -683,12 +743,10 @@ Str *B2C_strUpr(Str *str, int isString) {
}
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->data = malloc(str->length * 2);
memcpy(result->data, str->data, str->length * 2);
result->length = str->length;
for (i = 3; i <= result->length*2; i+=2) {
for (i = 0; i < result->length; i++) {
if (result->data[i] >= 'A' && result->data[i] <= 'Z') {
result->data[i] += 32;
}
@ -698,34 +756,58 @@ Str *B2C_strLwr(Str *str, int isString) { //(almost) copy of B2C_strUpr - any ch
}
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;
exitIfNeg(offset);
result->data = malloc(offset*2);
if (offset > str->length) offset=str->length;
result->length = offset;
memcpy(result->data+2, str->data + (str->length - offset + 1)*2, offset * 2);
memcpy(result->data, str->data+(str->length-offset), 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;
exitIfNeg(offset);
result->data = malloc(offset*2);
if (offset > str->length) offset=str->length;
result->length = offset;
memcpy(result->data+2, str->data + 2, offset * 2);
memcpy(result->data, str->data, offset*2);
free_str(str);
return result;
}
Str *B2C_strShift(Str *str, int isString, int offset) {
unsigned short* spaces = malloc(2*abs(offset));
Str *result = malloc(sizeof(Str));
for (i = 0; i < abs(offset); i++) {
spaces[i] = (unsigned short)' ';
}
result->length = str->length;
result->data = malloc(str->length*2);
if (offset > str->length) {
offset = str->length;
} else if (-offset > str->length) {
offset = -str->length;
}
if (offset > 0) {
memcpy(result->data, str->data+offset, (str->length-offset)*2);
memcpy(result->data+(str->length-offset), spaces, offset*2);
} else {
memcpy(result->data, spaces, -offset*2);
memcpy(result->data-offset, str->data, (str->length+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);
result->data = malloc(str->length*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);
memcpy(result->data, str->data+offset, (str->length-offset)*2);
memcpy(result->data+(str->length-offset), str->data, 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);
memcpy(result->data, str->data+(str->length+offset), -offset*2);
memcpy(result->data-offset, str->data, (str->length+offset)*2);
}
free_str(str);
return result;

View File

@ -19,8 +19,8 @@ public class B2C {
final static boolean debugMode = true;
static String path = "C:\\Users\\Catherine\\Documents\\CASIO\\fx-9860G SDK\\TestB2C\\";
static String mainProgramName = "DEMNR";
static String pathToG1M = "C:\\Users\\Catherine\\Desktop\\goldroad.g2m";
static String mainProgramName = "TESTSTR";
static String pathToG1M = "C:\\Users\\Catherine\\Desktop\\teststr.g1m";
static boolean isRealTimeGame = true;
static boolean assureOS1Compatibility = true;
static boolean usesAcOnTimer = true;
@ -108,7 +108,7 @@ public class B2C {
"unsigned int key;\n" +
"int i;\n"+
"BCDvar var[29] = {0}; //A-Z, r, theta, Ans\n"+
"Str strings[20];\n" +
"Str str[20];\n" +
"Mat mat[27]; //Important thing: matrixes are (height, width) not (width, height)\n" +
"List list[26];\n" +
"char dummyOpCode[2] = {5, 8};\n" +
@ -116,7 +116,7 @@ public class B2C {
"BCDvar alphaVarBuffer;\n" +
"BCDvar expressionBuffer;\n" +
"BCDvar getkeyBuffer;\n" +
"unsigned char stringBuffer[256] = {0};\n";
"unsigned char stringBuffer[512] = {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";
@ -124,7 +124,7 @@ public class B2C {
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\tstr[i].length = 0;\n" +
"\t}\n" +
"\tsrand((unsigned int)" + new Random().nextInt() + ");\n" +
"\t#ifdef USES_INTERRUPTION_TIMER\n" +
@ -204,9 +204,16 @@ public class B2C {
for (int i = 0; i <= 1; i++) {
IO.writeToFile(new File(path+externalLibs[i]), IO.readFromRelativeFile(externalLibs[i]), true);
}
/*for (char c = 'A'; c <= 'Z'; c++) {
Header.addDefine(c+" "+(c-'A'));
}*/
//Add constants for easier reading and debugging
for (char c = 'A'; c <= 'Z'; c++) {
Header.addDefine("VAR_"+c+" (&var["+(c-'A')+"])");
}
for (char c = 'A'; c <= 'Z'; c++) {
Header.addDefine("MAT_"+c+" (&mat["+(c-'A')+"])");
}
for (int i = 1; i <= 20; i++) {
Header.addDefine("STR_"+i+" (&str["+(i-1)+"])");
}
Header.addDefine("FALSE 0");
Header.addDefine("TRUE 1");
Header.addDefine("A_GREATER_THAN_B 1");
@ -214,6 +221,7 @@ public class B2C {
Header.addDefine("A_LESS_THAN_B -1");
Header.addDefine("NO_ERROR 1");
Header.addDefine("MEMORY_ERROR 4");
Header.addDefine("ARG_ERROR 8");
Header.addDefine("INTERRUPTION_TIMER 2");
if (usesAcOnTimer) {
Header.addDefine("USES_INTERRUPTION_TIMER");
@ -227,13 +235,14 @@ public class B2C {
Header.addDefine("LIST_START 0x10");
Header.addDefine("MAT_START 0x10");
Header.addDefine("ANS 28");
Header.addDefine("THETA 27");
Header.addDefine("RADIUS 26");
Header.addDefine("VAR_ANS (&var[28])");
Header.addDefine("VAR_THETA (&var[27])");
Header.addDefine("VAR_RADIUS (&var[26])");
Header.addDefine("SETUP_LISTFILE 0x2E");
Header.addDefine("free_str(x) if(!isString){free(x->data); free(x);}");
Header.addDefine("exitIfNeg(x) if((x)<0){B2C_exit(ARG_ERROR);}");
Header.addDefine("getDigit(BCDvar, i) (((i)%2) ? (*(BCDvar))[((i)+1)/2+1]>>4 : (*(BCDvar))[((i)+1)/2+1]&0x0F)");
Header.addDefine("getExp(BCDvar) (((*(BCDvar))[0]>>4) * 100 + ((*(BCDvar))[0]&0x0F) * 10 + ((*(BCDvar))[1]>>4))");
Header.create();

View File

@ -12,15 +12,7 @@ public class Constants {
* special things like 1e5, 1/3, etc.
*/
public static void add(String constant) {
constant = constant.replaceAll("\\x99|\\x87", "-");
//System.out.println(constant);
//Interpret "." as "0.", example: -.5 = -0.5
constant = constant.replaceAll("(?<!\\d)\\.", "0.");
//Remove last ".", example: 85. = 85.0 = 85
if (constant.charAt(constant.length()-1) == '.') {
constant = constant.substring(0, constant.length()-1);
}
constant = getNumberNotation(constant);
//Parse special operators
//sqrt
@ -89,17 +81,22 @@ public class Constants {
}
public static String getVarNotation(String nb) {
String result = getNumberNotation(nb);
result = result.replaceAll("\\.|\\-", "_");
return "_" + result + "_";
}
public static String getNumberNotation(String nb) {
String result;
//System.out.println(nb);
result = nb.replaceAll("(?<!\\d)\\.", "0.");
//System.out.println(result);
result = result.replaceAll("\\.|\\-|\\x99|\\x87", "_");
result = result.replaceAll("\\x99|\\x87", "-");
//System.out.println(result);
//Remove last "."
if (result.charAt(result.length()-1) == '.') {
result = result.substring(0, result.length()-1);
}
return "_" + result + "_";
return result;
}
public static boolean isNumber(String nb) {

View File

@ -40,7 +40,7 @@ public class Header {
//"typedef unsigned short Fontchar;\n" +
"typedef struct {\n" +
"\tint length;\n" +
"\tunsigned char* data;\n" +
"\tunsigned short* data;\n" +
"} Str;\n\n" +
"typedef struct {\n" +
"\tunsigned char data[4];\n" +

View File

@ -54,7 +54,7 @@ public class IO {
byte[] encoded;
try {
encoded = Files.readAllBytes(Paths.get(path));
content = new String(encoded, "Cp1252");
content = new String(encoded, "ISO-8859-1");
} catch (IOException e) {
e.printStackTrace();
}
@ -62,7 +62,7 @@ public class IO {
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}));
@ -74,6 +74,7 @@ public class IO {
content = content.replaceAll("\\u0161", new String(new char[]{0x9A}));
content = content.replaceAll("\\u203A", new String(new char[]{0x9B}));
content = content.replaceAll("\\u017E", new String(new char[]{0x9E}));
*/
//TODO actually parse the g1m
String[] programs = content.split("PROGRAM[\\s\\S]{13}system[\\s\\S]{2}");

View File

@ -8,7 +8,9 @@ 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;
//final static int CONV_TO_INT = 3; //Use handleIntConversion instead
final static int CONV_TO_STR = 4;
final static int CONV_TO_CHARARRAY = 5;
final static int BCD_BUFFER = 0;
final static int STR_BUFFER = 1;
@ -66,14 +68,6 @@ public class Parser {
parse(content.substring(matchResult+1), WHOLE_INSTRUCTION);
}
if (startsWithStringFunction(content)) {
if (option == WHOLE_INSTRUCTION) {
error("B2C does not support standalone strings!");
} else {
return parseStr(content);
}
}
//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.
@ -319,8 +313,8 @@ public class Parser {
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();";
+ "); Print("
+ parseStr(content.substring(args[1]+1), CONV_TO_CHARARRAY) + "); ML_display_vram();";
}
//ClrText
@ -342,16 +336,16 @@ public class Parser {
//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) {
if (option != WHOLE_INSTRUCTION) {
error("Assignment isn't whole instruction?!");
}
//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
@ -360,8 +354,8 @@ public class Parser {
if (content.substring(matchResult+3).startsWith(new String(new char[]{0x7F, 0x40}))) { //followed by Mat
String result = "B2C_setDimMat(" + (content.charAt(matchResult+5)-'A') + ", ";
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]")) + ");";
result += handleIntConversion(content.substring(0, matchResult) + "[1]") + ", ";
result += handleIntConversion(content.substring(0, matchResult) + "[2]") + ");";
return result;
} else if (content.startsWith("{")) {
Integer[] commaPos = parseArgs(content.substring(1, matchResult));
@ -443,17 +437,31 @@ public class Parser {
//Check for variable assignment
} else if (content.substring(matchResult+1).matches("[A-Z\\xCD\\xCE]")) {
String result = "B2C_setAlphaVar(" + getAlphaVar(content.charAt(matchResult+1))
+ ", " + parse(content.substring(0, matchResult), CONV_TO_BCD) + ")";
if (option == WHOLE_INSTRUCTION) {
result += ";";
}
+ ", " + parse(content.substring(0, matchResult), CONV_TO_BCD) + ");";
return result;
//Check for Str assignment
} else if (content.substring(matchResult+1).startsWith(new String(new char[]{0xF9, 0x3F}))) {
System.out.println("Parsing Str assignment, matchresult = " + matchResult);
String result = "B2C_setStr(" + getStr(content.substring(matchResult+3))
+ ", " + parse(content.substring(0, matchResult)) + ", " + handleString(content.substring(0, matchResult)) + ");";
return result;
} else {
error("Unknown assignment!");
}
}
//Check for strings
if (startsWithStringFunction(content)) {
if (option == WHOLE_INSTRUCTION) {
error("B2C does not support standalone strings!");
} else {
return parseStr(content, option);
}
}
//at this point it is a mathematical operation
//stock the level of the parentheses
Integer[] parenthesesPos = parseBrackets(content);
@ -526,7 +534,7 @@ public class Parser {
content = content.substring(0, content.length()-1);
}
return supportAns("list[" + getList(content.substring(2, check[0])) + "].data["
+ handleIntConversion(parse(content.substring(check[0]+1, content.length()))) + "]", option);
+ handleIntConversion(content.substring(check[0]+1, content.length())) + "]", option);
}
}
@ -768,11 +776,7 @@ public class Parser {
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) {
if (isMultibytePrefix(content.charAt(i))) {
i += 2;
if (i >= content.length()) {
break;
@ -845,13 +849,17 @@ public class Parser {
*
*/
public static String parseStr(String content) {
//TODO use buffers as str and place free() after
public static String parseStr(String content, int option) {
System.out.println("Parsing string: "+printNonAscii(content));
Integer[] parenthesesPos = parseBrackets(content);
if (startsWithStringFunction(content)) {
//Note that standalone strings aren't supported, there is no Str Ans; therefore, no ';'!
//Parse operators
//It is easy because the only operator is the '+'
Integer[] parenthesesPos = parseBrackets(content);
for (int i = content.length()-1; i >= 0; i--) {
if (content.substring(0, i).endsWith(new String(new char[]{0x89}))) {
//test if the operator is not within parentheses
@ -864,40 +872,147 @@ public class Parser {
System.out.println("Parsing concatenation operator (+)");
if (!isInParentheses) {
String str = "B2C_strcat(";
str += parse(content.substring(0, i-1)) + ", " + parse(content.substring(i));
str += ")";
//Parse as StrJoin(a,b)
String str = parse(new String(new char[]{0xF9,0x30}) + content.substring(0, i-1) + ","
+ content.substring(i) + ")", option);
if (option == CONV_TO_CHARARRAY) {
return "B2C_strToCharArray(" + str + ", " + handleString(str) + ")";
}
return str;
}
}
}
//Note that standalone strings aren't supported, there is no Str Ans; therefore, no ';'!
//Plain strings
if (content.startsWith("\"")) {
if (content.charAt(content.length()-1) != '"') {
content += '"';
}
content = replaceNonAscii(content);
return content;
content = "(unsigned char*)" + replaceNonAscii(content);
if (option == CONV_TO_CHARARRAY) {
return content;
}
return "B2C_charArrayToStr(" + content + ")";
}
//All subsequent str functions have parenthesis, so check if there is the right number
if (parenthesesPos.length != 2) {
error("Str function does not have one level of parenthesis!");
}
//No returns from here; always assign the result to this string!
//This is to handle the conversion to char array/str.
String result = "";
//Str function
if (content.startsWith(new String(new char[]{0xF9, 0x3F}))) {
return getStr(content.substring(2));
result = getStr(content.substring(2));
//All subsequent str functions have parenthesis, so check if there is the right number
} else if (parenthesesPos.length != 2) {
error("Str function does not have one level of parenthesis! ("+parenthesesPos.length+")");
}
//StrRotate
if (content.startsWith(new String(new char[]{0xF9, 0x3D}))) {
return "B2C_strRotate(" + addStrBuffer() + parse(content.substring(2, parenthesesPos[0])) + ")";
//These string functions all have similar structures (arguments = str, int)
String[] strFunctions1 = {"strLeft", "strRight", "strShift", "strRotate"};
String[] strOpcodes1 = {new String(new char[]{0xF9,0x34}),
new String(new char[]{0xF9,0x35}),
new String(new char[]{0xF9,0x3C}),
new String(new char[]{0xF9,0x3D}),
};
for (int i = 0; i < strFunctions1.length; i++) {
if (content.startsWith(strOpcodes1[i])) {
Integer[] argPos = parseArgs(content.substring(2, parenthesesPos[1]));
if (argPos.length > 1) {
error(strFunctions1[i]+" does not contain 2 arguments!");
}
if (argPos.length == 0) {
result = "B2C_"+strFunctions1[i]+"(" + parse(content.substring(2, parenthesesPos[1])) + ", " + handleString(content.substring(2, parenthesesPos[1]))
+ ", 1)";
} else {
result = "B2C_"+strFunctions1[i]+"(" + parse(content.substring(2, argPos[0]+2)) + ", " + handleString(content.substring(2, argPos[0]+2))
+ ", " + handleIntConversion(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ")";
}
}
}
//These string functions all have similar structures (argument = str)
String[] strFunctions2 = {"strInv", "strUpr", "strLwr"};
String[] strOpcodes2 = {new String(new char[]{0xF9,0x3B}),
new String(new char[]{0xF9,0x39}),
new String(new char[]{0xF9,0x3A}),
};
for (int i = 0; i < strFunctions2.length; i++) {
if (content.startsWith(strOpcodes2[i])) {
result = "B2C_"+strFunctions2[i]+"(" + parse(content.substring(2, parenthesesPos[1])) + ", " + handleString(content.substring(2, parenthesesPos[1])) + ")";
}
}
//StrMid
if (content.startsWith(new String(new char[]{0xF9, 0x36}))) {
Integer[] argPos = parseArgs(content.substring(2, parenthesesPos[1]));
if (argPos.length == 1) {
//StrMid with only 2 arguments = StrLeft
result = "B2C_strMid2args(" + parse(content.substring(2, argPos[0]+2)) + ", " + handleString(content.substring(2, argPos[0]+2))
+ ", " + handleIntConversion(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ")";
} else if (argPos.length != 2) {
error("strMid does not contain 3 arguments!");
} else {
result = "B2C_strMid(" + parse(content.substring(2, argPos[0]+2)) + ", " + handleString(content.substring(2, argPos[0]+2)) + ", "
+ handleIntConversion(content.substring(argPos[0]+2+1, argPos[1]+2)) + ", " + handleIntConversion(content.substring(argPos[1]+2+1, parenthesesPos[1])) + ")";
}
}
//StrJoin
if (content.startsWith(new String(new char[]{0xF9, 0x30}))) {
Integer[] argPos = parseArgs(content.substring(2, parenthesesPos[1]));
if (argPos.length != 1) {
error("StrJoin function does not contain 2 arguments!");
}
result = "B2C_strJoin(" + parse(content.substring(2, argPos[0]+2)) + ", " +handleString(content.substring(2, argPos[0]+2)) + ", "
+ parse(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ", " +handleString(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ")";
}
if (option == CONV_TO_CHARARRAY) {
return "B2C_strToCharArray(" + result + ", " + handleString(content) + ")";
}
return result;
}
return "B2C_convToStr(" + handleAlphaVar(content, NO_OPTION) + ")";
String result = "";
//StrLen
if (content.startsWith(new String(new char[]{0xF9, 0x31}))) {
result = "B2C_strLen(" + addBCDBuffer() + ", " + parse(content.substring(2, parenthesesPos[1])) + ", " + handleString(content.substring(2, parenthesesPos[1])) + ")";
}
//Both these functions have 2 strings as arguments and return a BCDvar
//StrCmp
else if (content.startsWith(new String(new char[]{0xF9,0x32}))) {
Integer[] argPos = parseArgs(content.substring(2, parenthesesPos[1]));
if (argPos.length != 1) {
error("StrCmp function does not contain 2 arguments!");
}
result = "B2C_strCmp(" + addBCDBuffer() + ", " + parse(content.substring(2, argPos[0]+2)) +", " + handleString(content.substring(2, argPos[0]+2)) + ", "
+ parse(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ", "+ handleString(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ")";
}
//StrSrc
else if (content.startsWith(new String(new char[]{0xF9,0x33}))) {
Integer[] argPos = parseArgs(content.substring(2, parenthesesPos[1]));
if (argPos.length > 2 || argPos.length < 1) {
error("StrSrc function does not contain 2 or 3 arguments!");
} else if (argPos.length == 1) {
result = "B2C_strSrc(" + addBCDBuffer() + ", " + parse(content.substring(2, argPos[0]+2)) +", " + handleString(content.substring(2, argPos[0]+2)) + ", "
+ parse(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ", " +handleString(content.substring(argPos[0]+2+1, parenthesesPos[1])) + ", 1)";
} else {
result = "B2C_strSrc(" + addBCDBuffer() + ", " + parse(content.substring(2, argPos[0]+2)) +", " + handleString(content.substring(2, argPos[0]+2)) + ", "
+ parse(content.substring(argPos[0]+2+1, argPos[1]+2)) +", " + handleString(content.substring(argPos[0]+2+1, argPos[1]+2))
+ ", " + handleIntConversion(content.substring(argPos[1]+2+1, parenthesesPos[1])) + ")";
}
} else {
result = handleAlphaVar(content, NO_OPTION);
}
return "B2C_convToStr(" + result + ")";
}
//Replace non-ASCII characters with \xXX, using string concatenation.
@ -933,7 +1048,7 @@ public class Parser {
*
*/
public static Integer[] parseArgs(String content) {
System.out.println("Parsing arguments: "+content);
System.out.println("Parsing arguments: "+printNonAscii(content));
ArrayList<Integer> args = new ArrayList<Integer>();
int argsBuffer = 0;
boolean positionIsString = false;
@ -942,7 +1057,7 @@ public class Parser {
if (content.charAt(i) == ',' && argsBuffer == 0 && !positionIsString) {
args.add(i);
}
if ((content.charAt(i) == '(' || content.charAt(i) == '[' || content.charAt(i) == '{') && !positionIsString) {
if (startsWithParenthesis(content.substring(i)) && !positionIsString) {
argsBuffer++;
} else if ((content.charAt(i) == ')' || content.charAt(i) == ']' || content.charAt(i) == '}') && !positionIsString) {
argsBuffer--;
@ -971,20 +1086,7 @@ public class Parser {
int bracketsLevel = 0;
boolean currentPositionIsString = false;
for (int i = 0; i < content.length(); i++) {
if (!currentPositionIsString && (content.charAt(i) == '(' || content.charAt(i) == '[' || content.charAt(i) == '{' ||
//Check for opcodes that contains parenthesis
content.startsWith(new String(new char[]{0x7F, 0x87}), i) || //RanInt#(
content.startsWith(new String(new char[]{0x7F, 0x47}), i) || //Fill(
content.startsWith(new String(new char[]{0xF9, 0x30}), i) || //StrJoin(
content.startsWith(new String(new char[]{0xF9, 0x34}), i) || //StrLeft(
content.startsWith(new String(new char[]{0xF9, 0x35}), i) || //StrRight(
content.startsWith(new String(new char[]{0xF9, 0x36}), i) || //StrMid(
content.startsWith(new String(new char[]{0xF9, 0x39}), i) || //StrUpr(
content.startsWith(new String(new char[]{0xF9, 0x3A}), i) || //StrLwr(
content.startsWith(new String(new char[]{0xF9, 0x3B}), i) || //StrInv(
content.startsWith(new String(new char[]{0xF9, 0x3C}), i) || //StrShift(
content.startsWith(new String(new char[]{0xF9, 0x3D}), i) //StrRotate(
)) {
if (!currentPositionIsString && startsWithParenthesis(content.substring(i))) {
bracketsLevel++;
if (bracketsLevel == 1) {
bracketsPos.add(i);
@ -1013,6 +1115,35 @@ public class Parser {
return bracketsPos.toArray(new Integer[bracketsPos.size()]);
}
/**
* Returns true if the given string starts with a parenthesis (or a bracket),
* but also with an opcode containing a parenthesis (RanInt#(, StrRotate(, etc).
*/
public static boolean startsWithParenthesis(String content) {
if ((content.charAt(0) == '(' || content.charAt(0) == '[' || content.charAt(0) == '{' ||
//Check for opcodes that contains parenthesis
content.startsWith(new String(new char[]{0x7F, 0x87})) || //RanInt#(
content.startsWith(new String(new char[]{0x7F, 0x47})) || //Fill(
content.startsWith(new String(new char[]{0xF9, 0x30})) || //StrJoin(
content.startsWith(new String(new char[]{0xF9, 0x31})) || //StrLen(
content.startsWith(new String(new char[]{0xF9, 0x32})) || //StrCmp(
content.startsWith(new String(new char[]{0xF9, 0x33})) || //StrSrc(
content.startsWith(new String(new char[]{0xF9, 0x34})) || //StrLeft(
content.startsWith(new String(new char[]{0xF9, 0x35})) || //StrRight(
content.startsWith(new String(new char[]{0xF9, 0x36})) || //StrMid(
content.startsWith(new String(new char[]{0xF9, 0x37})) || //Exp->Str(
content.startsWith(new String(new char[]{0xF9, 0x38})) || //Exp(
content.startsWith(new String(new char[]{0xF9, 0x39})) || //StrUpr(
content.startsWith(new String(new char[]{0xF9, 0x3A})) || //StrLwr(
content.startsWith(new String(new char[]{0xF9, 0x3B})) || //StrInv(
content.startsWith(new String(new char[]{0xF9, 0x3C})) || //StrShift(
content.startsWith(new String(new char[]{0xF9, 0x3D})) //StrRotate(
)) {
return true;
}
return false;
}
/* 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:
@ -1065,6 +1196,7 @@ public class Parser {
public static boolean isMultibytePrefix(char prefix) {
if (prefix == (char)0xF7 ||
prefix == (char)0x7F ||
prefix == (char)0xF9 ||
prefix == (char)0xE5 ||
prefix == (char)0xE6 ||
prefix == (char)0xE7)
@ -1073,6 +1205,7 @@ public class Parser {
}
/**
* Returns true if the given string starts with a string function.
* A string function is defined as a function that returns a string.
* That means that Str, StrLwr, StrShift, '"', ... return true,
* but not StrLen, StrCmp or StrSrc as they return BCDvars!
*
@ -1106,8 +1239,8 @@ public class Parser {
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;
if (Constants.isNumber(content)) {
return Constants.getNumberNotation(content);
}
return "B2C_convToUInt(" + parse(content) + ")";
}
@ -1121,6 +1254,30 @@ public class Parser {
return parse(content, option);
}
/**
* Handle the isString param, required for any function taking a string as argument.
* If isString(content) returns true, this function returns "TRUE". Else it returns "FALSE".
*/
public static String handleString(String content) {
if (isString(content)) {
return "TRUE";
}
return "FALSE";
}
/**
* Returns true iff the content consists only of the Str function.
* "Str 1 + StrRotate(Str 2)" will return false.
* "Str 20" will return true.
*/
public static boolean isString(String content) {
if (content.startsWith(new String(new char[]{0xF9, 0x3F})) && content.length() <= 4) {
return true;
}
return false;
}
public static void incrementTabs() {
tabs += "\t";
}
@ -1162,12 +1319,12 @@ public class Parser {
if (list.length() == 1 && list.charAt(0) == 0xC0) {
return "LIST_ANS";
} else {
return handleIntConversion(parse(list));
return handleIntConversion(list);
}
}
public static String getStr(String str) {
if (str.length() > 2) {
error("Invalid str " + str + "!");
error("Invalid str " + printNonAscii(str) + "!");
}
try {
int strno = Integer.valueOf(str);
@ -1177,12 +1334,12 @@ public class Parser {
} catch (NumberFormatException e) {
error("Invalid str " + str + "!");
}
return "&str["+Integer.valueOf(str)+"]";
return "STR_"+Integer.valueOf(str);
}
public static String addBCDBuffer() {return addBuffer(BCD_BUFFER);}
public static String addStrBuffer() {return addBuffer(STR_BUFFER);}
//public static String addStrBuffer() {return addBuffer(STR_BUFFER);}
public static String addMatBuffer() {return addBuffer(MAT_BUFFER);}
public static String addListBuffer() {return addBuffer(LIST_BUFFER);}