Fixed bug in matrices, refactored B2C

This commit is contained in:
Zezombye 2017-01-07 19:56:03 +01:00
parent f77d90b9c2
commit d56af7f194
10 changed files with 521 additions and 190 deletions

View File

@ -99,7 +99,7 @@ BCDvar *B2C_sub(BCDvar *buffer, BCDvar *a, BCDvar *b) {
unsigned char tempByte;
int result[15] = {0};
//Check for special cases
//a < 0 and b < 0 -> b-a
//a < 0 and b < 0 -> (-b)-(-a)
//Ex: (-4)-(-3) -> 3-4
if ((*a)[0] > 0x30 && (*b)[0] > 0x30) {
BCDvar a2, b2;
@ -360,13 +360,22 @@ BCDvar *B2C_xor(BCDvar *a, BCDvar *b) {
if (!((*a)[1]) != !((*b)[1])) return &_1_;
return &_0_;
}
BCDvar *B2C_int(BCDvar *buffer, BCDvar *a) {
const char *function = "\xA6""A";
setAlphaVar('A', a);
calcExp(&function, dummyOpCode, buffer, 1);
return buffer;
}
unsigned char* B2C_convToStr(BCDvar *nb) {
bcdToStr(nb, stringBuffer);
return stringBuffer;
}
void B2C_setListRow(unsigned int nbList, unsigned int row, BCDvar *value) {
memcpy(list[nbList].data[row], *value, 21);
memcpy(list[nbList].data[row], *value, sizeof(BCDvar)-3);
}
void B2C_setDimList(unsigned int nbList, unsigned short nbElements) {
@ -382,20 +391,32 @@ List B2C_newList(int nbElements, ...) {
va_start(vaList, nbElements);
//memcpy(list.data[0], _0_, sizeof(BCDvar));
for (i = 1; i <= nbElements; i++) {
memcpy(list.data[i], va_arg(vaList, BCDvar), 21);
memcpy(list.data[i], va_arg(vaList, BCDvar), sizeof(BCDvar)-3);
}
va_end(vaList);
return list;
}
void B2C_setDimMat(unsigned char matrix, unsigned short y, unsigned short x) {
void B2C_setDimMat(unsigned char matrix, unsigned short x, unsigned short y) {
mat[matrix].width = x;
mat[matrix].height = y;
mat[matrix].data = calloc((y+1)*(x+1), sizeof(BCDvar));
mat[matrix].data = calloc(x*y, sizeof(BCDvar));
}
void B2C_setMat(unsigned char matrix, unsigned int y, unsigned int x, BCDvar *value) {
memcpy(mat[matrix].data[mat[matrix].width*y+x], *value, 21);
void B2C_setMatCase(unsigned char matrix, unsigned int x, unsigned int y, BCDvar *value) {
memcpy(mat[matrix].data[mat[matrix].height*(x-1)+y-1], *value, sizeof(BCDvar)-3);
}
void B2C_fillMat(BCDvar *value, unsigned char matrix) {
for (i = 0; i < mat[matrix].width*mat[matrix].height; i++) {
memcpy(mat[matrix].data[i], *value, sizeof(BCDvar)-3);
}
}
void B2C_clrMat(unsigned char matrix) {
free(mat[matrix].data);
mat[matrix].width = 0;
mat[matrix].height = 0;
}
unsigned int B2C_convToUInt(BCDvar *nb) {
@ -428,7 +449,7 @@ int B2C_convToInt(BCDvar *nb) {
}
return result;
}
BCDvar *B2C_Getkey() {
BCDvar *B2C_getkey() {
if (!prgmGetkey(&getkeyBuffer)) {
B2C_exit(NO_ERROR);
}
@ -476,6 +497,22 @@ void B2C_exit(int exitCode) {
}
}
BCDvar *B2C_rand(BCDvar *buffer) {
int randDigit;
char tempByte;
//Initialise exponent to 99 (-1)
(*buffer)[0] = 9;
tempByte = 0x90;
for (i = 0; i < 15; i++) {
if (i%2) {
tempByte = (rand()%10) << 4;
} else {
(*buffer)[(i+1)/2+1] = tempByte + (rand()%10);
}
}
return buffer;
}
BCDvar *B2C_ranInt(BCDvar *buffer, BCDvar *a, BCDvar *b) {
//A + Int (Ran# * (B - A + 1))
const char *function = "A""\x89""\xA6""(""\xC1""\xA9""(B""\x99""A""\x89""1))";
@ -494,8 +531,8 @@ BCDvar *B2C_calcExp(unsigned char* exp) {
calcExp(&exp, dummyOpCode, &expressionBuffer, 1);
return &expressionBuffer;
}
void B2C_setAlphaVar(unsigned char variable, BCDvar *value) {
memcpy(var[variable], *value, 21);
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);
@ -602,13 +639,9 @@ Str *B2C_strJoin(Str *str1, Str *str2, int isString1, int 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;
BCDvar *B2C_strLen(BCDvar *buffer, Str *str, int isString) {
intToBCD(str->length, buffer);
return buffer;
}
Str *B2C_strMid(Str *str, int isString, int start, int offset) {
Str *result = malloc(sizeof(Str));

View File

@ -4,6 +4,7 @@ import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import java.util.Scanner;
/* TODO 's:
@ -18,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 = "__uiss4_";
static String pathToG1M = "C:\\Users\\Catherine\\Desktop\\puiss4.g1m";
static String mainProgramName = "DEMNR";
static String pathToG1M = "C:\\Users\\Catherine\\Desktop\\goldroad.g2m";
static boolean isRealTimeGame = true;
static boolean assureOS1Compatibility = true;
static boolean usesAcOnTimer = true;
@ -84,6 +85,7 @@ public class B2C {
}
long startTime = System.currentTimeMillis();
Operators.initOperators();
//Add some constants for functions
Constants.add("0");
Constants.add("1");
@ -107,7 +109,7 @@ public class B2C {
"int i;\n"+
"BCDvar var[29] = {0}; //A-Z, r, theta, Ans\n"+
"Str strings[20];\n" +
"Mat mat[26]; //Important thing: matrixes are (height, width) not (width, height)\n" +
"Mat mat[27]; //Important thing: matrixes are (height, width) not (width, height)\n" +
"List list[26];\n" +
"char dummyOpCode[2] = {5, 8};\n" +
"//These are buffers for syscalls that do not return a value.\n" +
@ -124,6 +126,7 @@ public class B2C {
"\tfor (i = 0; i < 20; i++) {\n" +
"\t\tstrings[i].length = 0;\n" +
"\t}\n" +
"\tsrand((unsigned int)" + new Random().nextInt() + ");\n" +
"\t#ifdef USES_INTERRUPTION_TIMER\n" +
"\t//Timer allowing AC/ON to be pressed at any moment\n" +
"\tSetTimer(INTERRUPTION_TIMER, 50, (void (*)(void))exitTimerHandler);\n" +
@ -201,9 +204,9 @@ 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+" "+(int)c);
}
/*for (char c = 'A'; c <= 'Z'; c++) {
Header.addDefine(c+" "+(c-'A'));
}*/
Header.addDefine("FALSE 0");
Header.addDefine("TRUE 1");
Header.addDefine("A_GREATER_THAN_B 1");
@ -232,7 +235,7 @@ public class B2C {
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.addDefine("getExp(BCDvar) (((*(a))[0]>>4) * 100 + ((*(a))[0]&0x0F) * 10 + ((*(a))[1]>>4))");
Header.addDefine("getExp(BCDvar) (((*(BCDvar))[0]>>4) * 100 + ((*(BCDvar))[0]&0x0F) * 10 + ((*(BCDvar))[1]>>4))");
Header.create();
System.out.println("Parsing done in " + (System.currentTimeMillis()-startTime) + " ms.");

View File

@ -4,7 +4,7 @@ import java.util.ArrayList;
public class Constants {
static ArrayList<Double> consts = new ArrayList<Double>();
static ArrayList<String> consts = new ArrayList<String>();
/**
* This method is to optimise the speed of B2C by pre-calculating constants.
@ -12,15 +12,33 @@ public class Constants {
* special things like 1e5, 1/3, etc.
*/
public static void add(String constant) {
constant = constant.replaceAll("\\x99", "-");
constant = constant.replaceAll("\\x99|\\x87", "-");
//System.out.println(constant);
if (constant.startsWith(".")) {
constant = "0" + 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);
}
if (consts.contains(Double.valueOf(constant))) {
//Parse special operators
//sqrt
if (constant.startsWith(new String(new char[]{0x86}))) {
String sqrt = String.valueOf(Math.sqrt(Double.valueOf(constant.substring(1))));
if (sqrt.length() > 15) {
sqrt = sqrt.substring(0, 15);
}
add(sqrt);
}
if (!isNumber(constant)) {
Parser.error("Constant " + Parser.printNonAscii(constant) + " is not a number!");
}
if (consts.contains(constant)) {
return;
}
consts.add(Double.valueOf(constant));
consts.add(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
@ -60,13 +78,32 @@ public class Constants {
//System.out.println("Result= "+bcdNotation);
//Replace groups of 2 digits by "0x##, " and remove the last comma+space
//System.out.println(bcdNotation);
//Handle the special case of 0
if (Double.valueOf(constant) == 0) {
bcdNotation = "000000000000000000"; //18 0s
}
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", "_")+"_";
String result;
//System.out.println(nb);
result = nb.replaceAll("(?<!\\d)\\.", "0.");
//System.out.println(result);
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 + "_";
}
public static boolean isNumber(String nb) {
return nb.matches("[\\d\\x99\\x87\\.\\-]+");
}
}

View File

@ -182,6 +182,9 @@ public class Functions {
addFunctions();
String functionsBuffer = IO.readFromRelativeFile("B2CFunctions.c");
Integer[] functionsPositions = Parser.parseBrackets(functionsBuffer);
if (functionsPositions.length % 4 != 0) {
Parser.error("cannot parse functions! Make sure not to have comments between functions (put them inside)");
}
//System.out.println(functionsBuffer.substring(0, functionsPositions[2]));
functions += addMethod(functionsBuffer.substring(0, functionsPositions[3]+1));

View File

@ -16,7 +16,6 @@ public class G1MParser {
int lastCarriageReturn = -1;
Parser.instructions.clear();
Parser.instructionNumber = 0;
Parser.nbBuffers = 0;
//Divides the instructions
@ -38,29 +37,35 @@ public class G1MParser {
* To avoid creating a buffer at each function call,
* as many buffers are created as functions calls in an instruction.
*/
int nbBuffers = 0;
int[] buffers = {0,0,0,0};
do {
Parser.nbBuffers = 0;
for (int i = 0; i < buffers.length; i++) {
Parser.buffers[0] = 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;
for (int i = 0; i < buffers.length; i++) {
if (buffers[i] < Parser.buffers[i]) {
buffers[i] = Parser.buffers[i];
}
}
} 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 += ", ";
for (int h = 0; h < buffers.length; h++) {
String bufferStr = "\t" + Parser.bufferTypes[h] + " ";
for (int i = 0; i < buffers[h]; i++) {
bufferStr += Parser.bufferVars[h] + i;
if (i+1 < buffers[h]) bufferStr += ", ";
}
bufferStr += ";\n";
if (buffers[h] > 0) result.insert(0, bufferStr);
}
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);
//System.out.println("nb buffers = " + nbBuffers);
//System.out.println(Parser.nbBuffers);
return result.toString();
}

View File

@ -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}));
@ -73,6 +73,7 @@ public class IO {
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}));
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

@ -3,13 +3,36 @@ package b2c;
public class Operator {
private String casioChar, asciiFunction;
private int precedence, nbOperands;
private int nbOperands;
private boolean isMathematicalFunction;
public Operator(int nbOperands, String casioChar, String asciiFunction, int precedence) {
public boolean isMathematicalFunction() {
return this.isMathematicalFunction;
}
public void setMathematicalFunction(boolean isMathematicalFunction) {
this.isMathematicalFunction = isMathematicalFunction;
}
public int getNbOperands() {
return nbOperands;
}
public void setNbOperands(int nbOperands) {
this.nbOperands = nbOperands;
}
public Operator(String casioChar, String asciiFunction, boolean isMathematicalFunction) {
this.casioChar = casioChar;
this.asciiFunction = asciiFunction;
this.precedence = precedence;
this.isMathematicalFunction = isMathematicalFunction;
}
public Operator(String casioChar, String asciiFunction, boolean isMathematicalFunction, int nbOperands) {
this.casioChar = casioChar;
this.asciiFunction = asciiFunction;
this.nbOperands = nbOperands;
this.isMathematicalFunction = isMathematicalFunction;
}
public String getCasioChar() {
@ -27,20 +50,4 @@ public class Operator {
public void setAsciiFunction(String asciiFunction) {
this.asciiFunction = asciiFunction;
}
public int getPrecedence() {
return precedence;
}
public void setPrecedence(int precedence) {
this.precedence = precedence;
}
public int getNbOperands() {
return nbOperands;
}
public void setNbOperands(int nbOperands) {
this.nbOperands = nbOperands;
}
}

View File

@ -4,34 +4,43 @@ import java.util.ArrayList;
public class Operators {
public static int maxPrecedence = 6;
public static int maxPrecedence = 0;
//Not sure if the precedence of xor/or is equal or not
//Pretty sure about all other precedences; feel free to test
//All seem to be left-to-right
//All seem to be left-to-right, even equality operators
public static Operator[][] operators = {{
new Operator(1, new String(new char[]{0x7F, 0xB3}), "B2C_not", 0),
new Operator(new String(new char[]{0xA8}), "B2C_pow", true),
new Operator(new String(new char[]{0x86}), "B2C_nthRoot", true),
},{
new Operator(new String(new char[]{0x99}), "B2C_neg", true, 1),
new Operator(new String(new char[]{0x87}), "B2C_neg", true, 1),
//new Operator(new String(new char[]{0x89}), "B2C_unaryPlus", false, 1), //unary plus = nothing
},{
new Operator(2, new String(new char[]{0xA8}), "B2C_pow", 1),
new Operator(2, new String(new char[]{0x86}), "B2C_sqrt", 1),
new Operator(new String(new char[]{0xA9}), "B2C_mult", true),
new Operator(new String(new char[]{0xB9}), "B2C_div", true),
},{
new Operator(2, new String(new char[]{0xA9}), "B2C_mult", 2),
new Operator(2, new String(new char[]{0xB9}), "B2C_div", 2),
new Operator(new String(new char[]{0x89}), "B2C_add", true),
new Operator(new String(new char[]{0x99}), "B2C_sub", true),
},{
new Operator(2, new String(new char[]{0x89}), "B2C_add", 3),
new Operator(2, new String(new char[]{0x99}), "B2C_sub", 3),
new Operator(new String(new char[]{0x86}), "B2C_sqrt", true, 1),
},{
new Operator(new String(new char[]{0x10}), "B2C_lessOrEqualThan", false),
new Operator(new String(new char[]{0x12}), "B2C_greaterOrEqualThan", false),
new Operator("<", "B2C_lessThan", false),
new Operator(">", "B2C_greaterThan", false),
new Operator("=", "B2C_equalTo", false),
new Operator(new String(new char[]{0x11}), "B2C_notEqualTo", false),
},{
new Operator(2, new String(new char[]{0x10}), "B2C_lessOrEqualThan", 4),
new Operator(2, new String(new char[]{0x12}), "B2C_greaterOrEqualThan", 4),
new Operator(2, "<", "B2C_lessThan", 4),
new Operator(2, ">", "B2C_greaterThan", 4),
new Operator(2, "=", "B2C_equalTo", 4),
new Operator(2, new String(new char[]{0x11}), "B2C_notEqualTo", 4),
new Operator(new String(new char[]{0x7F, 0xB0}), "B2C_and", false),
},{
new Operator(2, new String(new char[]{0x7F, 0xB0}), "B2C_and", 5),
},{
new Operator(2, new String(new char[]{0x7F, 0xB1}), "B2C_or", 6),
new Operator(2, new String(new char[]{0x7F, 0xB4}), "B2C_xor", 6),
new Operator(new String(new char[]{0x7F, 0xB1}), "B2C_or", false),
new Operator(new String(new char[]{0x7F, 0xB4}), "B2C_xor", false),
}};
public static void initOperators() {
maxPrecedence = operators.length-1;
}
}

View File

@ -9,13 +9,19 @@ public class Parser {
final static int WHOLE_INSTRUCTION = 1;
final static int CONV_TO_BCD = 2;
final static int CONV_TO_INT = 3;
final static int BCD_BUFFER = 0;
final static int STR_BUFFER = 1;
final static int LIST_BUFFER = 2;
final static int MAT_BUFFER = 3;
final static String[] bufferVars = {"bcdBuffer", "strBuffer", "listBuffer", "matBuffer"};
final static String[] bufferTypes = {"BCDvar", "Str", "List", "Mat"};
static String tabs = "\t";
//Be sure to clear these variables between programs.
static ArrayList<String> instructions = new ArrayList<String>();
static int instructionNumber = 0;
static int nbBuffers = 0;
static int[] buffers = {0,0,0,0};
public static String parse(String content) {
@ -37,22 +43,8 @@ public class Parser {
*/
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);
System.out.println("Parsing instruction: " + printNonAscii(content));
if (content.equals("")) {
return "";
@ -69,43 +61,49 @@ public class Parser {
matchResult = checkMatch(content, ":");
if (matchResult >= 0) {
instructions.add(instructionNumber, content.substring(matchResult+1));
instructionNumber++;
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 "";
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.
//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}))) {
//So Fill (0x7F47) is above Lbl (0xE2) which is above If (0xF700). (again, exception of => which is after IfEnd)
//Fill(
if (content.startsWith(new String(new char[]{0x7F,0x47}))) {
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!");
error("Fill method doesn't have 2 arguments!");
}
return supportAns("B2C_ranInt(" + addBuffer() + ", " + parse(content.substring(2, args[0]), CONV_TO_BCD) + ","
+ parse(content.substring(args[0]+1), CONV_TO_BCD) + ")", option);
if (content.substring(args[0]+1).startsWith(new String(new char[]{0x7F,0x40}))) {
return "B2C_fillMat(" + parse(content.substring(2, args[0]), CONV_TO_BCD) + ", "
+ parse(content.substring(args[0]+1), CONV_TO_BCD) + ");";
} else if (content.substring(args[0]+1).startsWith(new String(new char[]{0x7F,0x51}))) {
return "B2C_fillList(" + parse(content.substring(2, args[0]), CONV_TO_BCD) + ", "
+ parse(content.substring(args[0]+1), CONV_TO_BCD) + ");";
} else {
error("2nd argument of Fill isn't a Mat or a List!");
}
}
//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);
//unary plus = no purpose
if (content.startsWith(new String(new char[]{0x89}))) {
return parse(content.substring(1), option);
}
//Lbl
@ -333,6 +331,13 @@ public class Parser {
return "ML_clear_vram();";
}
//ClrMat
if (content.startsWith(new String(new char[]{0xF9,0x1E}))) {
if (content.length() != 3) {
error("Invalid argument for ClrMat!");
}
return "B2C_clrMat(" + getMat(content.charAt(2)) + ");";
}
//End of starting functions. At this point the instruction is likely a mathematical operation, or a string,
@ -385,7 +390,7 @@ public class Parser {
} 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 = "+getAlphaVar(content.charAt(matchResult+1))+"; i <= "+getAlphaVar(content.charAt(matchResult+3))+"; i++) {\n"+tabs+"B2C_setAlphaVar(i, "+assignment+");\n";
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 + "}";
@ -416,7 +421,7 @@ public class Parser {
if (check.length != 1) {
error("Mat instruction does not have one comma!");
}
String result = "B2C_setMat(" + (content.charAt(matchResult+3)-'A') + ", " +
String result = "B2C_setMatCase(" + getMat(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) + ");";
@ -452,33 +457,54 @@ public class Parser {
//at this point it is a mathematical operation
//stock the level of the parentheses
Integer[] parenthesesPos = parseBrackets(content);
//System.out.println(Arrays.toString(parenthesesPos));
//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
//Before parsing, we must check if the Mat instruction does not include dimensions
if (content.length() == 3) {
String str = getMat(content.charAt(2));
if (option == WHOLE_INSTRUCTION) {
str = "B2C_setMat(" + getMat((char)0xC0) + ", " + str + ");";
}
return str;
}
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*("
return supportAns("&mat[" + getMat(content.charAt(2)) + "].data[mat[" + getMat(content.charAt(2)) + "].height*("
/*+ 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);*/
+ handleIntConversion(content.substring(check[0]+1, check[0]+1+arg[0])) + ")+("
+ handleIntConversion(content.substring(check[0]+2+arg[0],content.length()-1)) + ")]", option);
+ handleIntConversion(content.substring(check[0]+1, check[0]+1+arg[0])) + "-1)+("
+ handleIntConversion(content.substring(check[0]+2+arg[0],content.length()-1)) + "-1)]", option);
}
}
}
//Dim ; for now it cannot parse it automatically, need to wait for the getNextArg() function
//TODO do getNextArg()
//Dim
if (content.startsWith(new String(new char[]{0x7F,0x46}))) {
return "Dim " + parse(content.substring(2));
//If it is Dim Mat
if (content.substring(2).startsWith(new String(new char[]{0x7F, 0x40}))) {
String result = "B2C_getDimMat(" + getMat(content.charAt(4)) + ")";
if (option == WHOLE_INSTRUCTION)
return "B2C_setList(LIST_ANS, " + result + ");";
return result;
//If it is Dim List
} else if (content.substring(2).startsWith(new String(new char[]{0x7F, 0x40}))) {
return supportAns("&list["+getList(content.substring(2)) + "].nbElements", option);
} else {
error("Dim instruction is not followed by List or Mat!");
}
}
@ -488,11 +514,18 @@ public class Parser {
//Before parsing, we must check if the entire instruction is a List instruction
Integer[] check = parseBrackets(content);
if (check.length == 0) {
String result = getList(content.substring(2));
if (option == WHOLE_INSTRUCTION)
return "B2C_setList(LIST_ANS, " + result + ");";
return result;
}
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["
return supportAns("list[" + getList(content.substring(2, check[0])) + "].data["
+ handleIntConversion(parse(content.substring(check[0]+1, content.length()))) + "]", option);
}
}
@ -506,32 +539,44 @@ public class Parser {
//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]) {
if (j-Operators.operators[h][i].getCasioChar().length() >= parenthesesPos[k] && j-Operators.operators[h][i].getCasioChar().length() <= parenthesesPos[k+1]) {
isInParentheses = true;
}
}
System.out.println("Parsing operator: " + Operators.operators[h][i].getAsciiFunction());
//If the operator is at the beginning of the string, it isn't a binary operator
if (!isInParentheses && (j != 0 && Operators.operators[h][i].getNbOperands() != 1)) {
if (!isInParentheses && (j != Operators.operators[h][i].getCasioChar().length() || Operators.operators[h][i].getNbOperands() == 1)) {
String str = "";
//System.out.println("Found the above operator");
str += Operators.operators[h][i].getAsciiFunction() + "(";
//If it is a mathematical operation (pow, mult, div, add, sub, sqrt)
if (str.startsWith("B2C_pow(") || str.startsWith("B2C_sqrt(") || str.startsWith("B2C_mult(") ||
str.startsWith("B2C_div(") || str.startsWith("B2C_add(") || str.startsWith("B2C_sub(")) {
str += addBuffer() + ", ";
//Check for special of unary plus operator (which does nothing)
/*if (str.equals("B2C_unaryPlus(")) {
return parse(content.substring(1), option);
}*/
//If it is a mathematical operation
if (Operators.operators[h][i].isMathematicalFunction()) {
str += addBCDBuffer() + ", ";
}
if (!str.startsWith("B2C_not(")) {
str += parse(content.substring(0, j-Operators.operators[h][i].getCasioChar().length()), CONV_TO_BCD) + ", " + parse(content.substring(j), CONV_TO_BCD) + ")";
if (Operators.operators[h][i].getNbOperands() != 1) {
str += parse(content.substring(0, j-Operators.operators[h][i].getCasioChar().length()), CONV_TO_BCD) + ", " + parse(content.substring(j), CONV_TO_BCD);
} else {
str += "B2C_not(" + parse(content.substring(2)) + ")";
//If it is an unary operator, check if we can convert them as a constant
if (content.matches("[\\d\\x99\\x87\\.\\x86]+")) {
//System.out.println("convert to const");
Constants.add(content);
return supportAns("&"+Constants.getVarNotation(content), option);
} else {
str += parse(content.substring(j), CONV_TO_BCD);
}
}
if (option == WHOLE_INSTRUCTION) {
str += ";";
}
return str;
}
str += ")";
return supportAns(str, option);
}/* else {
System.out.println("Operator was in parenthesis, ignoring it");
}*/
}
/*if (isMultibytePrefix(content.charAt(j))) {
@ -541,19 +586,15 @@ public class Parser {
}
}
//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 = "&var[" + getAlphaVar(content) + "]";
return supportAns(result, option);
if (content.matches("[A-Z\\xCD\\xCE\\xC0]")) {
return handleAlphaVar(content, option);
}
//Test if it is a number (note that it can be something like 2X, implicit multiplication)
if (content.matches("^[\\d\\x99\\.](.+)?")) {
if (content.matches("^[\\d\\x99\\x87\\.](.+)?")) {
int testForImplicitMultiplication = -1;
for (char i = '0'; i <= '9'; i++) {
if (testForImplicitMultiplication < content.lastIndexOf(i)) {
@ -561,8 +602,7 @@ public class Parser {
}
}
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);
return parse(content.substring(0, testForImplicitMultiplication+1) + (char)0xA9 + content.substring(testForImplicitMultiplication+1, content.length()));
}
//At this point it is a number, add it to constants
Constants.add(content);
@ -584,9 +624,63 @@ public class Parser {
}
return result;
}
//At this point it is a calculation, check for calculations functions
String result = "";
//Any function that returns a BCD value must be here! (GetKey, RanInt...)
//Don't forget to add the buffer!
//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(" + addBCDBuffer() + ", " + 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(" + addBCDBuffer() + ")", option);
}
//Not
if (content.startsWith(new String(new char[]{0x7F,0xB3}))) {
return supportAns("B2C_not(" + parse(content.substring(1, CONV_TO_BCD) + ")"), option);
}
//Int
if (content.startsWith(new String(new char[]{0xA6}))) {
if (content.length() == 1) {
error("Int instruction is standalone!");
}
return supportAns("B2C_int(" + addBCDBuffer() + ", " + parse(content.substring(1), CONV_TO_BCD) + ")", option);
}
//Ran#
if (content.startsWith(new String(new char[]{0xC1}))) {
if (content.length() != 1) {
error("Ran# instruction includes something else!");
}
return supportAns("B2C_rand(" + addBCDBuffer() + ")", option);
}
//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)) + ")";
}
/*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))) {
@ -597,8 +691,8 @@ public class Parser {
//Check if it is a lone variable
} else if (content.matches("[A-Z\\xCD\\xCE\\xC0]")) {
result += handleAlphaVar(content, option);
return result;
} /*else {
return result;*/
/*} else {
result += "B2C_calcExp((unsigned char*)" + parseStr("\"" + content + "\"") + ")";
return result;
}*/
@ -607,11 +701,12 @@ public class Parser {
//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 "";
error("function not recognized! " + printNonAscii(content));
return "===COMPILATION ERROR===";
}
/* This function is called to parse hardcoded lists (written like {1,2,3}).
/**
* 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)
@ -654,8 +749,9 @@ public class Parser {
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
/**
* 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 check 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.
@ -666,7 +762,6 @@ public class Parser {
* 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) {
@ -741,7 +836,8 @@ public class Parser {
return content;
}
/* This method parses a string. It is designed to parse things like:
/**
* 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,
@ -750,13 +846,56 @@ public class Parser {
*/
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 += '"';
System.out.println("Parsing string: "+printNonAscii(content));
if (startsWithStringFunction(content)) {
//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
boolean isInParentheses = false;
for (int k = 0; k < parenthesesPos.length; k+=2) {
if (i-1 >= parenthesesPos[k] && i-1 <= parenthesesPos[k+1]) {
isInParentheses = true;
}
}
System.out.println("Parsing concatenation operator (+)");
if (!isInParentheses) {
String str = "B2C_strcat(";
str += parse(content.substring(0, i-1)) + ", " + parse(content.substring(i));
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;
}
//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!");
}
//Str function
if (content.startsWith(new String(new char[]{0xF9, 0x3F}))) {
return getStr(content.substring(2));
}
//StrRotate
if (content.startsWith(new String(new char[]{0xF9, 0x3D}))) {
return "B2C_strRotate(" + addStrBuffer() + parse(content.substring(2, parenthesesPos[0])) + ")";
}
content = replaceNonAscii(content);
return content; //TODO parse Str function
}
return "B2C_convToStr(" + handleAlphaVar(content, NO_OPTION) + ")";
}
@ -784,7 +923,8 @@ public class Parser {
return content;
}
/* This method parses comma-separated arguments. It is used to parse any function
/**
* 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).
*
@ -824,13 +964,27 @@ public class Parser {
* 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]".
* When adding an opcode containing parenthesis, make sure to include it in this function.
*/
public static Integer[] parseBrackets(String content) {
ArrayList<Integer> bracketsPos = new ArrayList<Integer>();
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) {
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(
)) {
bracketsLevel++;
if (bracketsLevel == 1) {
bracketsPos.add(i);
@ -917,6 +1071,31 @@ public class Parser {
return true;
return false;
}
/**
* Returns true if the given string starts with a string function.
* That means that Str, StrLwr, StrShift, '"', ... return true,
* but not StrLen, StrCmp or StrSrc as they return BCDvars!
*
* The function must be the function alone, if there is something else then
* it will return false.
*/
public static boolean startsWithStringFunction(String function) {
if (function.startsWith(new String(new char[]{0xF9, 0x30})) || //StrJoin(
function.startsWith(new String(new char[]{0xF9, 0x34})) || //StrLeft(
function.startsWith(new String(new char[]{0xF9, 0x35})) || //StrRight(
function.startsWith(new String(new char[]{0xF9, 0x36})) || //StrMid(
function.startsWith(new String(new char[]{0xF9, 0x39})) || //StrUpr(
function.startsWith(new String(new char[]{0xF9, 0x3A})) || //StrLwr(
function.startsWith(new String(new char[]{0xF9, 0x3B})) || //StrInv(
function.startsWith(new String(new char[]{0xF9, 0x3C})) || //StrShift(
function.startsWith(new String(new char[]{0xF9, 0x3D})) || //StrRotate(
function.startsWith(new String(new char[]{0xF9, 0x3F})) || //Str
function.charAt(0) == '"'
) {
return true;
}
return false;
}
public static String supportAns(String content, int option) {
if (option == WHOLE_INSTRUCTION)
@ -936,7 +1115,7 @@ public class Parser {
public static String handleAlphaVar(String content, int option) {
//Handle var such that var[char-'A'] gives the correct variable
if (content.matches("[A-Z\\xCD\\xCE\\xC0]")) {
String result = "&var[" + getAlphaVar(content) + "]";
String result = getAlphaVar(content);
return supportAns(result, option);
}
return parse(content, option);
@ -951,30 +1130,86 @@ public class Parser {
public static String getAlphaVar(char var) {return getAlphaVar(""+var);}
public static String getAlphaVar(String var) {
String result = "VAR_";
if (var.length() != 1) {
error("Unknown var!");
} else if (var.charAt(0) >= 'A' && var.charAt(0) <= 'Z') {
return var;
result += String.valueOf(var.charAt(0)-'A');
} else if (var.charAt(0) == 0xCD) {
return "RADIUS";
result += "RADIUS";
} else if (var.charAt(0) == 0xCE) {
return "THETA";
result += "THETA";
} else if (var.charAt(0) == 0xC0) {
return "ANS";
result += "ANS";
} else {
error("Unknown var!");
}
error("Unknown var!");
return "";
return result;
}
public static String addBuffer() {
String result = "&buffer" + nbBuffers;
nbBuffers++;
public static String getMat(char mat) {
String result = "MAT_";
if (mat >= 'A' && mat <= 'Z') {
result += (mat-'A');
} else if (mat == 0xC0) {
result += "ANS";
} else {
error("Unknown mat "+mat+"!");
}
return result;
}
public static String getList(String list) {
if (list.length() == 1 && list.charAt(0) == 0xC0) {
return "LIST_ANS";
} else {
return handleIntConversion(parse(list));
}
}
public static String getStr(String str) {
if (str.length() > 2) {
error("Invalid str " + str + "!");
}
try {
int strno = Integer.valueOf(str);
if (strno < 1 || strno > 20) {
error("Invalid str number " + strno + "!");
}
} catch (NumberFormatException e) {
error("Invalid str " + 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 addMatBuffer() {return addBuffer(MAT_BUFFER);}
public static String addListBuffer() {return addBuffer(LIST_BUFFER);}
public static String addBuffer(int buffer) {
String result = "&" + bufferVars[buffer] + buffers[buffer];
buffers[buffer]++;
return result;
}
public static String printNonAscii(String content) {
String result = "";
for (int i = 0; i < content.length(); i++) {
if (content.charAt(i) >= 32 && content.charAt(i) < 127) {
result += content.charAt(i) + " ";
} else {
String hex = Integer.toHexString(content.charAt(i));
result += "0x" + hex + " ";
if (hex.length() > 2) {
error("Unhandled unicode character u+" + hex);
}
}
}
return result;
}
public static void error(String error) {
System.out.println("\n===ERROR: "+error+"===\n");
System.out.println("\nERROR: "+error+"\n");
System.exit(0);
}
}

View File

@ -10,12 +10,10 @@ public class Syscalls {
static String syscallContent = "";
static ArrayList<String> syscalls = new ArrayList<String>();
static ArrayList<String> syscallIDs = new ArrayList<String>();
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";