diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ed4f39a..06f56ef 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -7,20 +7,24 @@ so **be careful** on what you're doing! Read our [Code of Conduct](./CODE_OF_CONDUCT.md) to keep our community approachable and respectable. -Use the table of contents icon on the top left corner of this document to get to a specific section of this guide quickly. +--- -## New contributor guide +## Contributing code -To get an overview of the project, check out our [README](README.md). +### Before contributing -Here are some resources to help you get started with open source contributions: +You must know this before contributing: -- [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github) -- [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git) -- [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow) -- [Collaborating with pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests) +- Your contribution might be rejected for considerable reason(s). +- Your submitted code might be or will be ___ with or without you knowing. + - removed within the bounds of the project + - modified as needed or as necessary + - moved within the bounds of the project + - copied within the bounds of the project +- You will be known as a contributor of this repository. +- You might be called out to fix a bug created by your code if necessary. -To give us a suggestion on what utility to do next, you can open up an [issue](https://github.com/JumperBot/Unsafe-4-Bit/issues/new/choose). +--- ### How to start writing "the" code @@ -38,6 +42,8 @@ The first and most important step is getting to know yourself and your setup: Next step would be ***\*drum-roll\**** forking the repository! - You can now write the actual code. +--- + ### What to do when writing the code - Make the code **concise**. @@ -48,6 +54,8 @@ Next step would be ***\*drum-roll\**** forking the repository! - Take a look at some of the files to know what I meant by that. - Never forget to **test and compile** the code first on your machine before such reckless moves! +--- + ### What to do after writing the code - Check, test and compile your code into it's appropriate directory. @@ -57,14 +65,18 @@ Next step would be ***\*drum-roll\**** forking the repository! - Fill up the form! - Wait for me to accept your changes! +--- + ## Issues -### Create a new issue +### Creating a new issue If you spotted a problem or would like to create a new issue, [search if an issue already exists](https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-issues-and-pull-requests#search-by-the-title-body-or-comments). If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/JumperBot/Unsafe-4-Bit/issues/new/choose). +--- + ### Solve an issue Scan through our [existing issues](https://github.com/JumperBot/Unsafe-4-Bit/issues) to find one that interests you. diff --git a/README.md b/README.md index 06edfda..5d83393 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ and [compile](./src/README.md#UFBC) and [run](./src/README.md#UFB) the program! /* Write "Hello World" to memory index: 38 */ -wvar 38 8 5 12 12 15 0 23 15 18 12 4 +wvar 38 "Hello World" // Print the variable residing in memory index: 38 print 38 /* Jump to command no. 0 diff --git a/build/README.md b/build/README.md index 4dad4b8..dc70f04 100644 --- a/build/README.md +++ b/build/README.md @@ -37,7 +37,7 @@ java -jar UFB.jar [ -flags ] [ file ] --- -## Example +## Examples ```shell java UFB -pnv @@ -47,4 +47,5 @@ java UFB -nvp java UFB -pnhv java UFB -mn java UFB -c ../test/UFB/Main.ufb +java UFB -b ../test/UFB/Main.ufbb ``` \ No newline at end of file diff --git a/build/UFB.jar b/build/UFB.jar index c2f7a3e..27594bd 100644 Binary files a/build/UFB.jar and b/build/UFB.jar differ diff --git a/build/UFB/FlagManager.class b/build/UFB/FlagManager.class index 18b595a..e39b02c 100644 Binary files a/build/UFB/FlagManager.class and b/build/UFB/FlagManager.class differ diff --git a/build/UFB/Optimizer$1.class b/build/UFB/Optimizer$1.class index caca535..85369d2 100644 Binary files a/build/UFB/Optimizer$1.class and b/build/UFB/Optimizer$1.class differ diff --git a/build/UFB/Optimizer.class b/build/UFB/Optimizer.class index a1ee0b4..71b9bb9 100644 Binary files a/build/UFB/Optimizer.class and b/build/UFB/Optimizer.class differ diff --git a/build/UFB/Runner$1.class b/build/UFB/Runner$1.class new file mode 100644 index 0000000..aad50c4 Binary files /dev/null and b/build/UFB/Runner$1.class differ diff --git a/build/UFB/Runner.class b/build/UFB/Runner.class index b4bd570..24e58c8 100644 Binary files a/build/UFB/Runner.class and b/build/UFB/Runner.class differ diff --git a/build/UFB/UFB.class b/build/UFB/UFB.class index bcaa50e..fbfcc34 100644 Binary files a/build/UFB/UFB.class and b/build/UFB/UFB.class differ diff --git a/build/UFB/UFBC$1.class b/build/UFB/UFBC$1.class index 2d5b7e4..35240e0 100644 Binary files a/build/UFB/UFBC$1.class and b/build/UFB/UFBC$1.class differ diff --git a/build/UFB/UFBC$2.class b/build/UFB/UFBC$2.class new file mode 100644 index 0000000..eb8b50b Binary files /dev/null and b/build/UFB/UFBC$2.class differ diff --git a/build/UFB/UFBC.class b/build/UFB/UFBC.class index a0e512b..eec8cb5 100644 Binary files a/build/UFB/UFBC.class and b/build/UFB/UFBC.class differ diff --git a/build/build.sh b/build/build.sh index 634b8c1..492e83d 100644 --- a/build/build.sh +++ b/build/build.sh @@ -1,9 +1,11 @@ #!/bin/sh cd UFB -javac -verbose ../../src/UFB/*.java -d . -echo -jar --create --file=../UFB.jar --verbose --main-class=UFB *.class +echo "javac ../../src/UFB/*.java -d . -Xdiags:verbose" +javac ../../src/UFB/*.java -d . -Xdiags:verbose +echo "jar --create --file=../UFB.jar --main-class=UFB *.class" +jar --create --file=../UFB.jar --main-class=UFB *.class cd .. # Copy build/README.md to src/README.md -cp README.md ../src/README.md \ No newline at end of file +echo "cp README.md ../src/README.md" +cp README.md ../src/README.md diff --git a/src/README.md b/src/README.md index 4dad4b8..dc70f04 100644 --- a/src/README.md +++ b/src/README.md @@ -37,7 +37,7 @@ java -jar UFB.jar [ -flags ] [ file ] --- -## Example +## Examples ```shell java UFB -pnv @@ -47,4 +47,5 @@ java UFB -nvp java UFB -pnhv java UFB -mn java UFB -c ../test/UFB/Main.ufb +java UFB -b ../test/UFB/Main.ufbb ``` \ No newline at end of file diff --git a/src/UFB/FlagManager.java b/src/UFB/FlagManager.java index d89857c..60fab4f 100644 --- a/src/UFB/FlagManager.java +++ b/src/UFB/FlagManager.java @@ -24,16 +24,38 @@ class FlagManager{ final String flagString="[pnmvhclb]"; + final String[] longFlagsArr={ + "unoptimized" + }; final boolean[] isActivated=new boolean[flagString.length()-2]; + final boolean[] isLongActivated=new boolean[longFlagsArr.length]; final String file; - final Pattern flags=Pattern.compile(flagString); - final Pattern repeats=Pattern.compile("(\\w)\\1+"); public FlagManager(final String[]a){ + final Pattern flags=Pattern.compile(flagString); + final Pattern longFlags=Pattern.compile( + Arrays.toString(longFlagsArr).substring(1) + .replaceAll("\\]$", "") + .replace(", ", "|") + ); + final Pattern repeats=Pattern.compile("(\\w)\\1+"); + final Pattern doubleHyphens=Pattern.compile("^-+"); String fileName=""; for(final String s:a){ final String arg=s.trim(); if(arg.endsWith(".ufbb")||arg.endsWith(".ufb"))fileName=arg; - else if(arg.startsWith("-")){ + else if(arg.startsWith("--")){ + final String arg2=doubleHyphens.matcher(arg).replaceAll(""); + if(longFlags.matcher(arg2).matches()){ + for(int i=0;i. - * -**/ - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; - -import java.util.HashMap; - -class Optimizer{ - final char[] mem=new char[256]; - final int[] memInd=new int[256]; - final boolean[] aKnownNonNum=new boolean[256]; - final BufferedInputStream buffer; - final int size; - final int[] lines; - int furthestLine=-1; - final StringBuilder printProxy=new StringBuilder(); - final StringBuilder newCommands=new StringBuilder(); - public Optimizer(final String file)throws Exception{ - mem[0]=' '; - aKnownNonNum[0]=true; - for(int i=0;i<26;i++){ - final int ind=i+1; - aKnownNonNum[ind]=true; - mem[ind]=(char)(ind+64); - } - for(int i=0;i<10;i++)mem[i+27]=String.valueOf(i).charAt(0); - mem[37]='\n'; - for(int i=37;i<256;i++)aKnownNonNum[i]=true; - final File f=new File(file); - buffer=new BufferedInputStream(new FileInputStream(f)); - buffer.mark(Integer.MAX_VALUE); - size=(int)f.length(); - lines=new int[size]; - try{ - run(); - buffer.close(); - final String newFileName=file.substring(0, file.lastIndexOf("."))+".optimized.ufb"; - final File newGenCode=new File(newFileName); - try(final FileWriter writer=new FileWriter(newGenCode)){ - writer.write(newCommands.append("\nnvar 38").toString().trim().replaceAll("\n{2,}", "\n")); - } - UFBC.compile(newFileName, false); - newGenCode.delete(); - new File(file).delete(); - final File newCompiledFile=new File(newFileName+"b"); - newCompiledFile.renameTo(new File(file)); - }catch(final Exception e){ - buffer.close(); - if(!e.toString().contains("Code cannot be optimized"))throw new RuntimeException(e); - else System.out.println("Code cannot be optimized, but compilation is a success!"); - } - } - private void addToCommands(){ - final String converted=convertToMemory( - printProxy.toString() // i == -255, - == -254, . == -253 - ).replace("-255", "\nwvar 38 27\ndiv 38 27\nprint 38\nprint 255") - .replace("-254", "\nwvar 38 27\nsub 38 28\ntrim 38 1\nprint 38\nprint 255") - .replace("-253", "\nwvar 38 28\ndiv 38 29\nprint 39\nprint 255") - .replace("\n ", "\n"); - printProxy.setLength(0); - if(!converted.startsWith("\n"))newCommands.append("print "); - newCommands.append(converted).append("\n"); - } - private void run()throws Exception{ - final long start=System.currentTimeMillis(); - for(;byteInd5000){ - System.out.println("Optimizer: \"Timeout!\""); - throw new Exception("Code cannot be optimized, but compilation is a success!"); - } - if(furthestLine>-1&&lines[furthestLine] memMap=new HashMap<>(){{ - put(' ', 0); - put('A', 1); - put('B', 2); - put('C', 3); - put('D', 4); - put('E', 5); - put('F', 6); - put('G', 7); - put('H', 8); - put('I', 9); - put('J', 10); - put('K', 11); - put('L', 12); - put('M', 13); - put('N', 14); - put('O', 15); - put('P', 16); - put('Q', 17); - put('R', 18); - put('S', 19); - put('T', 20); - put('U', 21); - put('V', 22); - put('W', 23); - put('X', 24); - put('Y', 25); - put('Z', 26); - put('0', 27); - put('1', 28); - put('2', 29); - put('3', 30); - put('4', 31); - put('5', 32); - put('6', 33); - put('7', 34); - put('8', 35); - put('9', 36); - put('\n', 37); - put('\u0000', 38); - //hack-characters - put('i', -255); - put('-', -254); - put('.', -253); - }}; - private String convertToMemory(final String in){ - final StringBuilder output=new StringBuilder(); - for(final char c:in.toCharArray())output.append(memMap.get(c)).append(" "); - return output.toString().trim(); - } - int byteInd=0; - final byte[] byteArr=new byte[1]; - private int next(final int len){ - try{ - if(len==8){ - byteInd++; - for(long skipped=buffer.skip(byteInd-1);skipped255){ - System.arraycopy(temp, 0, mem, curInd, 255-curInd+1); - memInd[ind]=255; - return; - } - System.arraycopy(temp, 0, mem, curInd, temp.length); - curInd+=temp.length; - }else{ - final char[] tempty=rvar(ind); - if(curInd+tempty.length-1>255){ - System.arraycopy(tempty, 0, mem, curInd, 255-curInd+1); - memInd[ind]=255; - return; - } - System.arraycopy(tempty, 0, mem, curInd, tempty.length); - curInd+=tempty.length; - } - } - memInd[memIndex]=curInd-1; - return; - } - nvar(memIndex); - final int memEndPoint=memIndex+chars.length-1; - if(memEndPoint>255){ - System.arraycopy(chars, 0, mem, memIndex, 255-memIndex+1); - memInd[memIndex]=255; - return; - } - System.arraycopy(chars, 0, mem, memIndex, chars.length); - memInd[memIndex]=memEndPoint; - } - - private void nvar(final int ind){ - if(memInd[ind]==0)return; - final char[] temp=new char[memInd[ind]-ind+1]; // To Avoid For-Loops. - System.arraycopy(temp, 0, mem, ind, temp.length); - memInd[ind]=0; - } - - private void trim(){ - final int ind=next(8); - final int max=next(8); - if(max==0){ - nvar(ind); - return; - } - if(max>memInd[ind]-ind)return; - final char[] temp=rvar(ind); - nvar(ind); - System.arraycopy(temp, 0, mem, ind, max); - memInd[ind]=ind+max-1; - } - - private int findPeriod(final char[] arr){ - final int half=arr.length/2; - for(int i=0;i9){ - aKnownNonNum[ind]=true; - return new String(arr).hashCode(); - } - result[0]+=num; - result[0]*=10; - final int i2=decimalInd+1+i; - final int num2=arr[i2]-48; - if(num2<0||num2>9){ - aKnownNonNum[ind]=true; - return new String(arr).hashCode(); - } - result[1]+=num2; - result[1]/=10; - } - return (result[0]/10)+result[1]; - }else{ // BeCoz Long#parseLong() is slow and try-catch is expensive. - double result=0; - for(final char c:arr){ - final int num=c-48; - if(num<0||num>9){ - aKnownNonNum[ind]=true; - return new String(arr).hashCode(); - } - result+=num; - result*=10; - } - return result/10; - } - } - private void math(final int op){ - final int ind1=next(8); - final int ind2=next(8); - final char[] str2=rvar(ind2); - if(str2.length==0)return; // The earlier the call, the better. - final char[] str1=rvar(ind1); - if(str1.length<1&&str2.length>0){ - write(0, ind1, false, str2); - return; - } - try{ - final double num1=toNum(str1, ind1); - final double num2=toNum(str2, ind2); - final double result=(op==0)?num1+num2:(op==1)?num1-num2: - (op==2)?num1*num2:(op==3)?num1/num2: - (op==4)?num1%num2:(int) (num1/num2); - if(result!=result){ // Refer to Double#isNan(double v) - nvar(ind1); - mem[ind1]='i'; - memInd[ind1]=ind1; - return; - } - if(result%1==0) write(0, ind1, false, Long.toString((long)result).toCharArray()); - else write(0, ind1, false, Double.toString(result).toCharArray()); - }catch(final Exception e){ - nvar(ind1); - mem[ind1]='i'; - memInd[ind1]=ind1; - } - } - - final HashMap jumpBackFrequency=new HashMap(); - private boolean jump(final int op){ // Returns true if optimization should stop. - final int ind1=next(8); - final int ind2=next(8); - final char[] arg1=rvar(ind1); - final char[] arg2=rvar(ind2); - final int com=next(16); - if( - (op==0&&toNum(arg1, ind1)>toNum(arg2, ind2))|| - (op==1&&toNum(arg1, ind1)size){ - byteInd=size; - return; - } - for(;furthestLine++1){ - if(curByte<9)byteInd+=2; - else if(curByte>9){ - if(curByte<14)byteInd+=4; - else if(curByte==15)byteInd++; - else byteInd+=next(8)+1; - } - }else if(curByte==1)byteInd++; - else byteInd+=next(8)+1; - } - } - - private void print(){ - final int argCount=next(8); - for(int i=0;i100)addToCommands(); - } - } -} diff --git a/src/UFB/Runner.java b/src/UFB/Runner.java index 8dba730..f2b8857 100644 --- a/src/UFB/Runner.java +++ b/src/UFB/Runner.java @@ -25,24 +25,46 @@ import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.FileInputStream; +import java.io.FileWriter; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.util.HashMap; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + class Runner{ final char[] mem=new char[256]; final int[] memInd=new int[256]; final boolean[] aKnownNonNum=new boolean[256]; + final BufferedInputStream buffer; + final String fileName; final int size; final int[] lines; int furthestLine=-1; + + final boolean performance; final boolean nanoseconds; final boolean timeMethods; final boolean backwardsCompat; - public Runner(final String fileName, final boolean performance, - final boolean nanoseconds, final boolean timeMethods, - final boolean backwardsCompat)throws Exception{ + + public Runner( + final String fileName, final boolean performance, + final boolean nanoseconds, final boolean timeMethods, + final boolean backwardsCompat + )throws Exception{ + final File f=new File(fileName); + if(!f.exists()){ + System.out.println("File Provided Does Not Exist...\nTerminating..."); + System.exit(1); + } + buffer=new BufferedInputStream(new FileInputStream(f)); + buffer.mark(Integer.MAX_VALUE); + size=(int)f.length(); + lines=new int[size]; mem[0]=' '; aKnownNonNum[0]=true; for(int i=0;i<26;i++){ @@ -53,83 +75,68 @@ public Runner(final String fileName, final boolean performance, for(int i=0;i<10;i++)mem[i+27]=String.valueOf(i).charAt(0); mem[37]='\n'; for(int i=37;i<256;i++)aKnownNonNum[i]=true; + this.fileName=fileName; + this.performance=performance; this.nanoseconds=nanoseconds; this.timeMethods=timeMethods; this.backwardsCompat=backwardsCompat; - if(fileName.length()!=0){ - final File f=new File(fileName); - if(!f.exists()){ - System.out.println("File Provided Does Not Exist...\nTerminating..."); - System.exit(1); - } - buffer=new BufferedInputStream(new FileInputStream(f)); - buffer.mark(Integer.MAX_VALUE); - size=(int)f.length(); - lines=new int[size]; - try{ - if(performance){ + } + + public void run()throws Exception{ + final long runStart=(!nanoseconds)?System.currentTimeMillis():System.nanoTime(); + try{ + if(timeMethods){ + for(;byteInd-1&&lines[furthestLine]-1&&lines[furthestLine]-1&&lines[furthestLine]-1&&lines[furthestLine]255){ System.arraycopy(temp, 0, mem, curInd, 255-curInd+1); memInd[ind]=255; + final char[] converted=convertUnicode(new String(rvar(memIndex))).toCharArray(); + System.arraycopy(converted, 0, mem, memIndex, converted.length); + memInd[memIndex]=memIndex+converted.length-1; return; } System.arraycopy(temp, 0, mem, curInd, temp.length); @@ -222,13 +232,19 @@ private void write(final int argCount, final int memIndex, if(curInd+tempty.length-1>255){ System.arraycopy(tempty, 0, mem, curInd, 255-curInd+1); memInd[ind]=255; + final char[] converted=convertUnicode(new String(rvar(memIndex))).toCharArray(); + System.arraycopy(converted, 0, mem, memIndex, converted.length); + memInd[memIndex]=memIndex+converted.length-1; return; } System.arraycopy(tempty, 0, mem, curInd, tempty.length); curInd+=tempty.length; } } - memInd[memIndex]=curInd-1; + memInd[memIndex]=curInd-1; + final char[] converted=convertUnicode(new String(rvar(memIndex))).toCharArray(); + System.arraycopy(converted, 0, mem, memIndex, converted.length); + memInd[memIndex]=memIndex+converted.length-1; return; } nvar(memIndex); @@ -272,7 +288,7 @@ private int findPeriod(final char[] arr){ return -1; } private double toNum(final char[] arr, final int ind){ - if(aKnownNonNum[ind])return new String(arr).hashCode(); + if(aKnownNonNum[ind])return hash(arr); final int decimalInd=findPeriod(arr); if(decimalInd!=-1){ final double[] result=new double[2]; @@ -280,7 +296,7 @@ private double toNum(final char[] arr, final int ind){ final int num=arr[i]-48; if(num<0||num>9){ aKnownNonNum[ind]=true; - return new String(arr).hashCode(); + return hash(arr); } result[0]+=num; result[0]*=10; @@ -288,7 +304,7 @@ private double toNum(final char[] arr, final int ind){ final int num2=arr[i2]-48; if(num2<0||num2>9){ aKnownNonNum[ind]=true; - return new String(arr).hashCode(); + return hash(arr); } result[1]+=num2; result[1]/=10; @@ -300,7 +316,8 @@ private double toNum(final char[] arr, final int ind){ final int num=c-48; if(num<0||num>9){ aKnownNonNum[ind]=true; - return new String(arr).hashCode(); + return hash(arr); + // return new String(arr).hashCode(); } result+=num; result*=10; @@ -308,6 +325,23 @@ private double toNum(final char[] arr, final int ind){ return result/10; } } + // A rip-off of String#hashCode(); + // It just does too much, had to rewrite it. + private long hash(final char[] arr){ + int hash=0; + for(int i=0;i9){ } } - final PrintWriter out=new PrintWriter(new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(FileDescriptor.out), "UTF-8"), 512 - )); + // TODO: Stop people from removing this; historically important. + // final PrintWriter out=new PrintWriter(new BufferedWriter( + // new OutputStreamWriter(new FileOutputStream(FileDescriptor.out), "UTF-8"), 512 + // )); + // private void print(){ + // final int argCount=next(8); + // for(int i=0;i"); write(0, ind, false, scan.readLine().toCharArray()); } -} + + public void runOptimized()throws Exception{ + scan.close(); + try{ + scan.close(); + final long start=System.currentTimeMillis(); + for(;byteInd5000){ + System.out.println("Optimizer: \"Timeout!\""); + throw new Exception("Code cannot be optimized, but compilation is a success!"); + } + if(furthestLine>-1&&lines[furthestLine] memMap=new HashMap<>(){{ + put(' ', 0); put('A', 1); put('B', 2); put('C', 3); put('D', 4); + put('E', 5); put('F', 6); put('G', 7); put('H', 8); put('I', 9); + put('J', 10); put('K', 11); put('L', 12); put('M', 13); put('N', 14); + put('O', 15); put('P', 16); put('Q', 17); put('R', 18); put('S', 19); + put('T', 20); put('U', 21); put('V', 22); put('W', 23); put('X', 24); + put('Y', 25); put('Z', 26); + put('0', 27); put('1', 28); put('2', 29); put('3', 30); put('4', 31); + put('5', 32); put('6', 33); put('7', 34); put('8', 35); put('9', 36); + put('\n', 37); + put('\u0000', 38); + //hack-characters + put('i', -255); put('-', -254); put('.', -253); + }}; + + final HashMap jumpBackFrequency=new HashMap(); + private boolean jumpOptimizer(final int op){ // Returns true if optimization should stop. + final int ind1=next(8); + final int ind2=next(8); + final char[] arg1=rvar(ind1); + final char[] arg2=rvar(ind2); + final int com=next(16); + if( + (op==0&&toNum(arg1, ind1)>toNum(arg2, ind2))|| + (op==1&&toNum(arg1, ind1)249){ + final int length=printProxy.length()-printProxy.toString().lastIndexOf("U"); + if(length<5) + untilDump=5-length; + else + addToCommands(); + } + final int argCount=next(8); + for(int i=0;i254)addToCommands(); + } + } +} \ No newline at end of file diff --git a/src/UFB/UFB.java b/src/UFB/UFB.java index 5cf808b..6f24ef2 100644 --- a/src/UFB/UFB.java +++ b/src/UFB/UFB.java @@ -19,22 +19,21 @@ **/ class UFB{ - //----------------------------------------------------------------------// - /**TODO: ALWAYS CHANGE VERSION TAG. - * DO NOT Change '1' in "1.*.*". - * MINOR CHANGES should go in "1.MINOR.*". - * PATCH CHANGES should go in "1.*.PATCH". - * MINOR CHANGES should give new commands/major features. - * PATCH CHANGES should give new flags/performance-boosts/bug-fixes/etc. - **/ - final static String version_tag="v1.3.0"; - //----------------------------------------------------------------------// public static void main(final String[]a)throws Exception{ final FlagManager flagManager=new FlagManager(a); if(flagManager.isFlagActivated('v')){ + //----------------------------------------------------------------------// + /**TODO: ALWAYS CHANGE SEMANTIC VERSION BEFORE RELEASING. + * DO NOT Change '1' in "1.*.*". + * MINOR CHANGES should go in "1.MINOR.*". + * PATCH CHANGES should go in "1.*.PATCH". + * MINOR CHANGES should give new commands/major features. + * PATCH CHANGES should give new flags/performance-boosts/bug-fixes/etc. + **/ + //----------------------------------------------------------------------// System.out.printf( "UFB version: %s (master)\n%s\n\n", - version_tag, + "v1.4.0", "Flag triggered, continuing anyway..." ); } @@ -87,16 +86,22 @@ public static void main(final String[]a)throws Exception{ } if(flagManager.isFlagActivated('c')){ if(fileName.endsWith(".ufbb")){ - System.out.println("Could not compile an already compiled source code."); - System.out.println("Remove the compilation flag to run the compiled program."); + System.out.printf( + "%s\n%s\n", + "Could not compile an already compiled source code.", + "Remove the compilation flag to run the compiled program." + ); return; } - new UFBC(fileName); + new UFBC().compile(fileName, !flagManager.isLongFlagActivated("unoptimized")); return; } if(fileName.endsWith(".ufb")){ - System.out.println("Could not run uncompiled source code."); - System.out.println("Add the compilation flag to compile the program."); + System.out.printf( + "%s\n%s\n", + "Could not run uncompiled source code.", + "Add the compilation flag to compile the program." + ); return; } new Runner( @@ -105,6 +110,6 @@ public static void main(final String[]a)throws Exception{ flagManager.isFlagActivated('n'), flagManager.isFlagActivated('m'), flagManager.isFlagActivated('b') - ); + ).run(); } } \ No newline at end of file diff --git a/src/UFB/UFBC.java b/src/UFB/UFBC.java index ae63877..ebfb5b6 100644 --- a/src/UFB/UFBC.java +++ b/src/UFB/UFBC.java @@ -26,7 +26,7 @@ import java.util.Arrays; import java.util.ArrayList; import java.util.HashMap; - +import java.util.regex.Matcher; import java.util.regex.Pattern; class UFBC{ @@ -40,153 +40,210 @@ class UFBC{ * 12 - 1100 - je | 13 - 1101 - jne * 14 - 1110 - print | 15 - 1111 - read **/ - final static Pattern allowed=Pattern.compile("[^a-zA-Z0-9 \n-|,\t]"); - final static Pattern divider=Pattern.compile("[-|, \t]+"); - final static Pattern empties=Pattern.compile(" *\n+ *"); - final static Pattern comment=Pattern.compile("//.*\n*"); - final static Pattern morecom=Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL); - final static StringBuilder errors=new StringBuilder(); - public UFBC(final String fileName)throws Exception{ - compile(fileName, true); - } - public static void compile(final String fileName, final boolean recompile)throws Exception{ + final Pattern divider=Pattern.compile("[-|, \t]+"); + final Pattern empties=Pattern.compile(" *\n+ *"); + final Pattern comment=Pattern.compile("//.*\n*"); + final Pattern morecom=Pattern.compile("/\\*.*?\\*/", Pattern.DOTALL); + final StringBuilder errors=new StringBuilder(); + public UFBC(){} + public void compile(final String fileName, final boolean recompile)throws Exception{ final StringBuilder inBuilder=new StringBuilder(); try(final BufferedReader scan=new BufferedReader(new FileReader(fileName))){ String temp; while((temp=scan.readLine())!=null)inBuilder.append(temp).append("\n"); } - final String input=inBuilder.toString(); - final String[] arr=empties.split( + String input=inBuilder.toString(); + final Pattern dividerInString=Pattern.compile("\".*([-|, \t]).*\""); + try{ + for(final Matcher m=dividerInString.matcher(input);m.find();) + for(final Matcher m2=divider.matcher(input);m2.find(m.start());){ + input=new StringBuilder(input.substring(0, m2.start())) + .append("UU") + .append(manPadding(Integer.toString(m2.group().charAt(0)+0), 4)) + .append(input.substring(m2.start()+1)).toString(); + m.reset(input).find(); + m2.reset(input); + } + }catch(final Exception e){} + final String[] arr=empties.split( divider.matcher( - allowed.matcher( - comment.matcher( - morecom.matcher( - input.toLowerCase() - ).replaceAll("\n") - ).replaceAll("\n") - ).replaceAll("") + comment.matcher( + morecom.matcher( + input + ).replaceAll("\n") + ).replaceAll("\n") ).replaceAll(" ") ); final StringBuilder warnings=new StringBuilder(); final ArrayList list=new ArrayList<>(); + final Pattern jumps=Pattern.compile("j(m|l|e|ne)", Pattern.CASE_INSENSITIVE); + final Pattern maths=Pattern.compile("add|sub|mul|div|r*mod", Pattern.CASE_INSENSITIVE); + final Pattern pwvar=Pattern.compile("wvar|print", Pattern.CASE_INSENSITIVE); boolean cancelOptimization=false; for(final String arrTemp:arr){ - final String[] temp=divider.split(arrTemp); - if(temp.length<2&&temp.length>0&&!temp[0].equals("nop")) - warnings.append("Warning: |\n") - .append(" Command: |\n") - .append(" \"") - .append(temp[0]) - .append("\" Will Be Ignored For It Has No Arguments: |\n") - .append(" ") - .append(lineGen(temp)); - else{ + final String[] realTemp=divider.split(arrTemp); + final ArrayList tempList=new ArrayList<>(); + for(String s:realTemp){ + if(s.startsWith("\"")&&s.endsWith("\"")) + for(final String s2:convertToMem(s.substring(1, s.length()-1))) + tempList.add(s2); + else + tempList.add(s); + } + final String[] temp=tempList.toArray(new String[tempList.size()]); + if(temp.length<2&&temp.length>0&&!temp[0].equalsIgnoreCase("nop")){ + if(!(temp[0].equals("\n")||temp[0].trim().isEmpty())) + warnings.append("Warning: |\n") + .append(" Command: |\n") + .append(" \"") + .append(temp[0]) + .append("\" Will Be Ignored For It Has No Arguments: |\n") + .append(" ") + .append(lineGen(temp)); + }else{ boolean isCommand=true; - switch(temp[0]){ - case "trim": - checkLength(temp, 3); - break; - case "nvar": - if(checkLength(temp, 2))break; - checkIfMemSafe(temp, temp[1]); - break; - case "read": - if(checkLength(temp, 2))break; - checkIfMemSafe(temp, temp[1]); - cancelOptimization=true; - break; - case "jm": - case "jl": - case "je": - case "jne": - if(checkLength(temp, 4))break; - case "add": - case "sub": - case "mul": - case "div": - case "mod": - case "rmod": - if(!temp[0].startsWith("j")){ - if(checkLength(temp, 3))break; - checkIfMemSafe(temp, temp[1]); - } - for(byte i=1;i<3;i++)checkIfMem(temp, temp[i]); - break; - case "wvar": - case "print": - if(temp.length>Byte.MAX_VALUE-1){ - error( - temp, "Command", temp[0], - "Has Too Many Arguments" - ); - break; - } - if(temp[0].startsWith("w"))checkIfMemSafe(temp, temp[1]); - for(byte i=2;i256) + error( + realTemp, "Command", temp[0], + "Has Too Many Arguments", + lineGen(temp) + ); + else{ + if(temp[0].startsWith("w")) + checkIfMemSafe(temp, temp[1]); + for(short i=2;i mems=new ArrayList<>(); + boolean backSlash=false; + for(final char c:in.toCharArray()){ + if(memMap.containsKey(c)) + mems.add(memMap.get(c).toString()); + else{ + if(c=='\\'){ + if(backSlash){ + backSlash=false; + mems.add("21"); + mems.add("21"); + for(final char c2:manPadding(Integer.toString('\\'), 4).toCharArray()) + mems.add(memMap.get(c2).toString()); + }else{ + backSlash=true; + } + }else if(backSlash){ + if(c=='n'){ + mems.add("37"); + }else{ + mems.add("21"); + mems.add("21"); + for(final char c2:manPadding(Integer.toString((int)c), 4).toCharArray()) + mems.add(memMap.get(c2).toString()); + } + backSlash=false; + }else{ + mems.add("21"); + mems.add("21"); + for(final char c2:manPadding(Integer.toString((int)c), 4).toCharArray()) + mems.add(memMap.get(c2).toString()); + } + } + } + return mems.toArray(new String[mems.size()]); + } + final HashMap memMap=new HashMap<>(){{ + put(' ', 0); put('A', 1); put('B', 2); put('C', 3); put('D', 4); + put('E', 5); put('F', 6); put('G', 7); put('H', 8); put('I', 9); + put('J', 10); put('K', 11); put('L', 12); put('M', 13); put('N', 14); + put('O', 15); put('P', 16); put('Q', 17); put('R', 18); put('S', 19); + put('T', 20); put('U', 21); put('V', 22); put('W', 23); put('X', 24); + put('Y', 25); put('Z', 26); + put('0', 27); put('1', 28); put('2', 29); put('3', 30); put('4', 31); + put('5', 32); put('6', 33); put('7', 34); put('8', 35); put('9', 36); + put('\n', 37); + }}; + private void writeToFile(final String outName, final ArrayList list)throws Exception{ + final File outFile=new File(outName); + outFile.createNewFile(); + try(final FileOutputStream stream=new FileOutputStream(outFile)){ + for(int i=0;i255) error( @@ -200,7 +257,7 @@ private static void checkIfMem(final String[] temp, final String s){ ); } } - private static void checkIfMemSafe(final String[] temp, final String s){ + private void checkIfMemSafe(final String[] temp, final String s){ try{ if(Long.parseLong(s)<38) error( @@ -215,7 +272,7 @@ private static void checkIfMemSafe(final String[] temp, final String s){ } } // false if error is not thrown. Misleading eh? - private static boolean checkLength(final String[] temp, final int length){ + private boolean checkLength(final String[] temp, final int length){ if(temp.length!=length){ final String num=(length<1)?"Zero":(length==1)?"One":(length==2)?"Two":"Three"; error( @@ -226,40 +283,66 @@ private static boolean checkLength(final String[] temp, final int length){ } return false; } - private static String lineGen(final String[]temp){ + private String lineGen(final String[]temp){ return Arrays.toString(temp).substring(1).replace(", ", " ").replace("]", "\n\n"); } - private static void error(final String[] temp, final String... in){ - errors.append("Error: |\n") - .append(String.format(" %s: |\n", in[0])) - .append(String.format(" \"%s\" %s: |\n", in[1], in[2])) - .append(String.format(" %s", lineGen(temp))); + private void error(final String[] temp, final String... in){ + if(in.length<4) + errors.append("Error: |\n") + .append(String.format(" %s: |\n", in[0])) + .append(String.format(" \"%s\" %s: |\n", in[1], in[2])) + .append(String.format(" %s", lineGen(temp))); + else + errors.append("Error: |\n") + .append(String.format(" %s: |\n", in[0])) + .append(String.format(" \"%s\" %s: |\n", in[1], in[2])) + .append(String.format(" %s", convertUnicode(lineGen(temp).replace("\n\n", "\n")))) + .append(String.format(" %s: |\n", "Which Is When Converted")) + .append(String.format(" %s", in[3])); } - private static String manPadding(final String str, final int i){ - final StringBuilder reverse=new StringBuilder(str).reverse(); - while(reverse.length()i)reverse.delete(0, 1); - return reverse.reverse().toString(); + private long toLongAbsolute(final char[] arr){ + // BeCoz Long#parseLong() is slow and try-catch is expensive. + long result=0; + for(final char c:arr){ + result+=c-48; + result*=10; + } + return result/10; + } + final Pattern unicode=Pattern.compile("(uu|UU)(\\d{1,4})"); + private String convertUnicode(final String in){ + if(in.length()<2)return in; + String temp=in; + try{ + for(final Matcher m=unicode.matcher(temp);m.find();m.reset(temp)){ + temp=new StringBuilder(temp.substring(0, m.start())) + .append((char)toLongAbsolute( + temp.substring(m.start()+2, m.end()).toCharArray() + )) + .append(temp.substring(m.end())).toString(); + } + }catch(final Exception e){} + return temp; + } + public static String manPadding(final String str, final int i){ + return String.format( + new StringBuilder("%").append(i).append("s").toString(), + str + ).replace(" ", "0"); } - final static HashMap binaryMap=new HashMap<>(){{ - put("wvar" , 0 ); - put("nvar" , 1 ); - put("trim" , 2 ); - put("add" , 3 ); - put("sub" , 4 ); - put("mul" , 5 ); - put("div" , 6 ); - put("mod" , 7 ); - put("rmod" , 8 ); - put("nop" , 9 ); - put("jm" , 10); - put("jl" , 11); - put("je" , 12); - put("jne" , 13); - put("print", 14); - put("read" , 15); + final HashMap binaryMap=new HashMap<>(){{ + final String[] commands={ + "wvar", "nvar", "trim", + "add", "sub", "mul", "div", "mod", "rmod", + "nop", + "jm", "jl", "je", "jne", + "print", "read" + }; + for(short i=0;i