Browse Source

experimental recursive code parsing

Kajetan Johannes Hammerle 6 years ago
parent
commit
f3da52dd20

+ 16 - 6
src/me/hammerle/snuviscript/SnuviScript.java

@@ -10,7 +10,7 @@ import me.hammerle.snuviscript.code.ISnuviScheduler;
 import me.hammerle.snuviscript.code.Script;
 import me.hammerle.snuviscript.code.SnuviParser;
 import me.hammerle.snuviscript.code.SnuviUtils;
-import me.hammerle.snuviscript.config.SnuviConfig;
+import me.hammerle.snuviscript.exceptions.PreScriptException;
 import me.hammerle.snuviscript.token.Tokenizer;
 
 public class SnuviScript
@@ -64,12 +64,22 @@ public class SnuviScript
                 return 1;
             }
         };
-        //SnuviParser parser = new SnuviParser(logger, scheduler);
-        //parser.startScript(true, ".sbasic", "./test");  
         
-        List<String> list = SnuviUtils.readCode(".sbasic", "./test");
-        Tokenizer t = new Tokenizer(String.join("\n", list));
-        t.tokenize();
+        SnuviParser parser = new SnuviParser(logger, scheduler);
+        parser.startScript(true, ".sbasic", "./test");  
+        
+        try
+        {
+            List<String> list = SnuviUtils.readCode(".sbasic", "./test");           
+            Tokenizer t = new Tokenizer(String.join("\n", list));
+            t.tokenize();
+        }
+        catch(PreScriptException ex)
+        {
+            System.out.println(ex);
+            System.out.println(ex.getStartLine() + "   " + ex.getEndLine());
+            ex.printStackTrace();
+        }
         
         //System.out.println("spawn - " + conf.getLocation("spawn"));
         //parser.callEvent("testevent", null, null);      

+ 7 - 7
src/me/hammerle/snuviscript/code/Compiler.java

@@ -83,7 +83,7 @@ public class Compiler
     
     private void addCodeInstruction(String function, InputProvider[] input)
     {
-        code.add(new Instruction(line + lineOffset + 1, (byte) layer, FunctionLoader.getFunction(function), input));
+        code.add(new Instruction(line + lineOffset + 1, (byte) layer, new Function(FunctionLoader.getFunction(function), input)));
     }
     
     private void addLabel(String name, int line)
@@ -332,11 +332,11 @@ public class Compiler
         
         Instruction[] input = code.toArray(new Instruction[code.size()]);
         
-        /*for(Instruction in : input)
+        for(Instruction in : input)
         {
             System.out.println(in);
         }
-        System.out.println("__________________________________");*/
+        System.out.println("__________________________________");
         /*labels.entrySet().stream().forEach((e) -> 
         {
             System.out.println("LABEL " + e.getKey() + " " + e.getValue());
@@ -583,11 +583,11 @@ public class Compiler
                         case SUB:
                             sy = Syntax.UNARY_SUB;
                             break;
-                        case INC:
-                            sy = Syntax.POST_INC;
+                        case POST_INC:
+                            sy = Syntax.INC;
                             break;
-                        case DEC:
-                            sy = Syntax.POST_DEC;
+                        case POST_DEC:
+                            sy = Syntax.DEC;
                             break;
                         default:
                             throw new PreScriptException("missing syntax argument", line);

+ 5 - 0
src/me/hammerle/snuviscript/code/Function.java

@@ -14,6 +14,11 @@ public class Function extends InputProvider
         this.function = function;
         this.input = input;
     }
+    
+    public InputProvider[] getArguments()
+    {
+        return input;
+    }
 
     @Override
     public String toString() 

+ 41 - 30
src/me/hammerle/snuviscript/code/FunctionLoader.java

@@ -47,7 +47,7 @@ public class FunctionLoader
         FUNCTIONS.put(alias, FUNCTIONS.get(original));
     }
     
-    protected static BasicFunction getFunction(String f)
+    public static BasicFunction getFunction(String f)
     {
         final String function = f.toLowerCase();
         return FUNCTIONS.getOrDefault(function, new BasicFunction(function, (sc, in) -> 
@@ -550,22 +550,24 @@ public class FunctionLoader
         // var setter
         registerFunction("=", (sc, in) -> 
         {
-            in[0].set(sc, in[1].get(sc));
-            return Void.TYPE;
+            Object o = in[1].get(sc);
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction("+=", (sc, in) -> 
         {
-            in[0].set(sc, in[0].getDouble(sc) + in[1].getDouble(sc));
-            return Void.TYPE;
+            Object o = in[0].getDouble(sc) + in[1].getDouble(sc);
+            in[0].set(sc, o);
+            return o;
         });
-        registerFunction("++", (sc, in) -> 
+        registerFunction("p++", (sc, in) -> 
         {
             double d = in[0].getDouble(sc);
             in[0].set(sc, d + 1.0);
             return d;
         });
-        registerAlias("++", "inc");
-        registerFunction("p+", (sc, in) -> 
+        registerAlias("p++", "inc");
+        registerFunction("++", (sc, in) -> 
         {
             double d = in[0].getDouble(sc) + 1.0;
             in[0].set(sc, d);
@@ -573,17 +575,18 @@ public class FunctionLoader
         });
         registerFunction("-=", (sc, in) -> 
         {
-            in[0].set(sc, in[0].getDouble(sc) - in[1].getDouble(sc));
-            return Void.TYPE;
+            Object o = in[0].getDouble(sc) - in[1].getDouble(sc);
+            in[0].set(sc, o);
+            return o;
         });
-        registerFunction("--", (sc, in) -> 
+        registerFunction("p--", (sc, in) -> 
         {
             double d = in[0].getDouble(sc);
             in[0].set(sc, d - 1.0);
             return d;
         });
-        registerAlias("--", "dec");
-        registerFunction("p-", (sc, in) -> 
+        registerAlias("p--", "dec");
+        registerFunction("--", (sc, in) -> 
         {
             double d = in[0].getDouble(sc) - 1.0;
             in[0].set(sc, d);
@@ -591,43 +594,51 @@ public class FunctionLoader
         });
         registerFunction("*=", (sc, in) -> 
         {
-            in[0].set(sc, in[0].getDouble(sc) * in[1].getDouble(sc));
-            return Void.TYPE;
+            Object o = in[0].getDouble(sc) * in[1].getDouble(sc);
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction("/=", (sc, in) -> 
         {
-            in[0].set(sc, in[0].getDouble(sc) / in[1].getDouble(sc));
-            return Void.TYPE;
+            Object o = in[0].getDouble(sc) / in[1].getDouble(sc);
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction("%=", (sc, in) -> 
         {
-            in[0].set(sc, (double) (in[0].getInt(sc) % in[1].getInt(sc)));
-            return Void.TYPE;
+            Object o = (double) (in[0].getInt(sc) % in[1].getInt(sc));
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction("<<=", (sc, in) -> 
         {
-            in[0].set(sc, (double) (in[0].getInt(sc) << in[1].getInt(sc)));
-            return Void.TYPE;
+            Object o = (double) (in[0].getInt(sc) << in[1].getInt(sc));
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction(">>=", (sc, in) -> 
         {
-            in[0].set(sc, (double) (in[0].getInt(sc) >> in[1].getInt(sc)));
-            return Void.TYPE;
+            Object o = (double) (in[0].getInt(sc) >> in[1].getInt(sc));
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction("&=", (sc, in) -> 
         {
-            in[0].set(sc, (double) (in[0].getInt(sc) & in[1].getInt(sc)));
-            return Void.TYPE;
+            Object o = (double) (in[0].getInt(sc) & in[1].getInt(sc));
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction("^=", (sc, in) -> 
         {
-            in[0].set(sc, (double) (in[0].getInt(sc) ^ in[1].getInt(sc)));
-            return Void.TYPE;
+            Object o = (double) (in[0].getInt(sc) ^ in[1].getInt(sc));
+            in[0].set(sc, o);
+            return o;
         });
         registerFunction("|=", (sc, in) -> 
         {
-            in[0].set(sc, (double) (in[0].getInt(sc) | in[1].getInt(sc)));
-            return Void.TYPE;
+            Object o = (double) (in[0].getInt(sc) | in[1].getInt(sc));
+            in[0].set(sc, o);
+            return o;
         });
         
         // var stuff
@@ -788,7 +799,7 @@ public class FunctionLoader
         registerFunction("next", (sc, in) -> 
         {
             int line = sc.currentLine + in[0].getInt(sc);
-            InputProvider[] f = sc.code[line].getParameters();
+            InputProvider[] f = sc.code[line].getArguments();
             // for(var, start, end, step)
             double current = f[0].getDouble(sc) + f[3].getDouble(sc);
             f[0].set(sc, current);

+ 12 - 25
src/me/hammerle/snuviscript/code/Instruction.java

@@ -3,16 +3,13 @@ package me.hammerle.snuviscript.code;
 public class Instruction
 {
     private final int realLine;
-    private final byte layer;
+    private final byte layer;   
+    private final InputProvider input;
     
-    private final BasicFunction function;
-    private final InputProvider[] input;
-    
-    public Instruction(int realLine, byte layer, BasicFunction function, InputProvider[] input)
+    public Instruction(int realLine, byte layer, InputProvider input)
     {
         this.realLine = realLine;
         this.layer = layer;
-        this.function = function;
         this.input = input;
     }
 
@@ -25,10 +22,14 @@ public class Instruction
     {
         return realLine;
     }
-
-    public InputProvider[] getParameters() 
+    
+    public InputProvider[] getArguments()
     {
-        return input;
+        if(input instanceof Function)
+        {
+            return ((Function) input).getArguments();
+        }
+        return null; 
     }
     
     @Override
@@ -49,26 +50,12 @@ public class Instruction
             sb.append("    ");
         }
         
-        sb.append(function.getName());
-        sb.append("(");
-        
-        for(InputProvider in : input)
-        {
-            sb.append(in);
-            sb.append(", ");
-        }
-        if(input.length > 0)
-        {
-            sb.delete(sb.length() - 2, sb.length());
-        }
-        
-        sb.append(")");
-        
+        sb.append(input);
         return sb.toString();
     }
     
     public void execute(Script sc)
     {
-        function.execute(sc, input);
+        input.get(sc);
     }
 }

+ 1 - 1
src/me/hammerle/snuviscript/code/SignInverter.java

@@ -30,6 +30,6 @@ public class SignInverter extends InputProvider
     @Override
     public String toString() 
     {
-        return "invertSign(" + input + ")";
+        return "-(" + input + ")";
     }
 }

+ 4 - 4
src/me/hammerle/snuviscript/code/Syntax.java

@@ -4,9 +4,9 @@ public enum Syntax
 {
     UNKNOWN(" ", 0, 0),
     INC("++", 2, 1),
-    POST_INC("p+", 2, 1),
+    POST_INC("p++", 2, 1),
     DEC("--", 2, 1),
-    POST_DEC("p-", 2, 1),
+    POST_DEC("p--", 2, 1),
     INVERT("!", 2, 1),
     BIT_INVERT("~", 2, 1),
     MUL("*", 3),
@@ -88,7 +88,7 @@ public enum Syntax
                         switch(s.charAt(1))
                         {
                             case '=':  return ADD_SET;
-                            case '+':  return INC;
+                            case '+':  return POST_INC;
                         }
                     }
                     break;
@@ -102,7 +102,7 @@ public enum Syntax
                         switch(s.charAt(1))
                         {
                             case '=':  return SUB_SET;
-                            case '-':  return DEC;
+                            case '-':  return POST_DEC;
                         }
                     }
                     break;

+ 186 - 0
src/me/hammerle/snuviscript/token/Expression.java

@@ -0,0 +1,186 @@
+package me.hammerle.snuviscript.token;
+
+import java.util.LinkedList;
+
+public abstract class Expression 
+{
+    public static class Grouping extends Expression
+    {
+        private final Expression exp;
+        
+        public Grouping(Expression exp)
+        {
+            this.exp = exp;
+        }
+
+        @Override
+        public String toString()
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.append('(');
+            sb.append(exp);
+            sb.append(')');
+            return sb.toString();
+        }
+    }
+    
+    public static abstract class PostFunction extends Expression
+    {
+        private final String name;
+        private final LinkedList<Expression> exp = new LinkedList<>();
+        private final char start;
+        private final char end;
+        
+        public PostFunction(String name, char start, char end)
+        {
+            this.name = name;
+            this.start = start;
+            this.end = end;
+        }
+
+        @Override
+        public String toString()
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.append(name);
+            sb.append(start);
+            exp.forEach(e -> 
+            {
+                sb.append(e);
+                sb.append(", ");
+            });
+            if(!exp.isEmpty())
+            {
+                sb.delete(sb.length() - 2, sb.length());
+            }
+            sb.append(end);
+            return sb.toString();
+        }
+        
+        public void addExpression(Expression exp)
+        {
+            this.exp.add(exp);
+        }
+    }
+    
+    public static class Function extends PostFunction
+    {
+        public Function(String name)
+        {
+            super(name, '(', ')');
+        }
+    }
+    
+    public static class Array extends PostFunction
+    {
+        public Array(String name)
+        {
+            super(name, '[', ']');
+        }
+    }
+    
+    public static class Binary extends Expression
+    {
+        private final Expression left;
+        private final Token t;
+        private final Expression right;
+        
+        public Binary(Expression left, Token t, Expression right)
+        {
+            this.left = left;
+            this.t = t;
+            this.right = right;
+        }
+
+        @Override
+        public String toString() 
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.append('(');
+            sb.append(left);
+            sb.append(' ');
+            sb.append(t);
+            sb.append(' ');
+            sb.append(right);
+            sb.append(')');
+            return sb.toString();
+        } 
+    }
+    
+    public static class PreUnary extends Expression
+    {
+        private final Token t;
+        private final Expression right;
+        
+        public PreUnary(Token t, Expression right)
+        {
+            this.t = t;
+            this.right = right;
+        }
+        
+        @Override
+        public String toString() 
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.append('(');
+            sb.append(t);
+            sb.append(right);
+            sb.append(')');
+            return sb.toString();
+        } 
+    }
+    
+    public static class PostUnary extends Expression
+    {
+        private final Expression left;
+        private final Token t;
+        
+        public PostUnary(Expression left, Token t)
+        {
+            this.left = left;
+            this.t = t;
+        }
+        
+        @Override
+        public String toString() 
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.append('(');
+            sb.append(left);
+            sb.append(t);
+            sb.append(')');
+            return sb.toString();
+        } 
+    }
+    
+    public static class Literal extends Expression
+    {
+        private final Object o;
+        
+        public Literal(Object o)
+        {
+            this.o = o;
+        }
+
+        @Override
+        public String toString() 
+        {
+            if(o != null)
+            {
+                if(o.getClass() == String.class)
+                {
+                    StringBuilder sb = new StringBuilder();
+                    sb.append('"');
+                    sb.append(o);
+                    sb.append('"');
+                    return sb.toString();
+                }
+                else
+                {
+                    return o.toString();
+                }
+            }
+            return "null";
+        }  
+    }
+}

+ 618 - 2
src/me/hammerle/snuviscript/token/Parser.java

@@ -1,11 +1,627 @@
 package me.hammerle.snuviscript.token;
 
+import java.util.HashMap;
 import java.util.LinkedList;
+import java.util.Stack;
+import me.hammerle.snuviscript.array.DynamicArray;
+import me.hammerle.snuviscript.code.Function;
+import me.hammerle.snuviscript.code.FunctionLoader;
+import me.hammerle.snuviscript.code.InputProvider;
+import me.hammerle.snuviscript.code.Instruction;
+import me.hammerle.snuviscript.code.JumpData;
+import me.hammerle.snuviscript.code.SignInverter;
+import me.hammerle.snuviscript.constants.ConstantBoolean;
+import me.hammerle.snuviscript.constants.ConstantDouble;
+import me.hammerle.snuviscript.constants.ConstantNull;
+import me.hammerle.snuviscript.constants.ConstantString;
+import me.hammerle.snuviscript.exceptions.PreScriptException;
+import static me.hammerle.snuviscript.token.TokenType.*;
+import me.hammerle.snuviscript.variable.ArrayVariable;
+import me.hammerle.snuviscript.variable.Variable;
 
 public class Parser 
 {
-    public Parser(LinkedList<TokenData> data)
+    private final HashMap<String, Variable> vars = new HashMap<>();
+    private final HashMap<String, Integer> labels = new HashMap<>();
+    
+    private boolean tryState = false;
+    private boolean cancel = false;
+    
+    private class JumpWrapper
     {
+        private final JumpData data;
+        private final String function;
         
+        public JumpWrapper(JumpData data, String function)
+        {
+            this.data = data;
+            this.function = function;
+        }
     }
-}
+    
+    private final Stack<JumpWrapper> jumps = new Stack<>();
+    private final Stack<JumpWrapper> loopJumps = new Stack<>();
+    private final LinkedList<JumpData> breakContinueJumps = new LinkedList<>();
+    
+    private final Token[] tokens;
+    private int current = 0;
+    private int layer = 0;
+    
+    private final LinkedList<Instruction> inst = new LinkedList<>();
+    
+    public Parser(LinkedList<Token> tokens)
+    {
+        this.tokens = tokens.toArray(new Token[tokens.size()]);
+        //tokens.forEach(t -> System.out.println(t));
+    }
+    
+    // -------------------------------------------------------------------------
+    // utility
+    // -------------------------------------------------------------------------
+    
+    private boolean match(TokenType... types) 
+    {
+        for(TokenType type : types) 
+        {
+            if(check(type)) 
+            {
+                advance();
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    private boolean check(TokenType tokenType) 
+    {
+        if(current >= tokens.length) 
+        {
+            return false;
+        }
+        return tokens[current].getToken() == tokenType;
+    }
+    
+    private Token advance() 
+    {
+        if(current < tokens.length)
+        {
+            current++;
+        }
+        return previous();
+    }
+
+    private Token previous() 
+    {
+        return tokens[current - 1];
+    }
+    
+    private void consume(TokenType type, String s)
+    {
+        if(tokens[current].getToken() != type)
+        {
+            throw new PreScriptException(s, tokens[current].getLine());
+        }
+        current++;
+    }
+    
+    private void peek(TokenType type, String s)
+    {
+        if(tokens[current].getToken() != type)
+        {
+            throw new PreScriptException(s, tokens[current].getLine());
+        }
+    }
+    
+    // -------------------------------------------------------------------------
+    // parsing precedence layers
+    // http://en.cppreference.com/w/c/language/operator_precedence
+    // -------------------------------------------------------------------------
+    
+    private void addInstruction(int line, String function, InputProvider... in)
+    {
+        inst.add(new Instruction(line, (byte) layer, new Function(FunctionLoader.getFunction(function), in)));
+    }
+    
+    public Instruction[] parseTokens()
+    {
+        while(current < tokens.length && tokens[current].getToken() != END_OF_FILE)
+        {
+            if(match(LABEL))
+            {
+                if(labels.put(previous().getData().toString(), inst.size()) != null)
+                {
+                    throw new PreScriptException("label duplicate", previous().getLine());
+                }
+                match(SEMICOLON);
+            }
+            
+            int line = tokens[current].getLine();
+            inst.add(new Instruction(line, (byte) layer, parseExpression()));
+            tryState = false;
+            if(cancel)
+            {
+                cancel = false;
+                continue;
+            }
+            
+            if(match(OPEN_CURVED_BRACKET))
+            {
+                layer++;
+            }
+            else
+            {
+                consume(SEMICOLON, "unexpected token after expression: " + tokens[current]);
+            }
+
+            while(match(CLOSE_CURVED_BRACKET))
+            {
+                layer--;
+                
+                if(jumps.isEmpty())
+                {
+                    throw new PreScriptException("} without a corresponding function and / or {", previous().getLine());
+                }
+                JumpWrapper data = jumps.pop();
+                switch(data.function)
+                {
+                    case "try":
+                    {
+                        peek(CATCH, "try without catch");
+                        data.data.setRelativeJump(inst.size());
+                        tryState = true;
+                        break;
+                    }
+                    case "catch":
+                    {
+                        data.data.setRelativeJump(inst.size());
+                        break;
+                    }
+                    case "else":
+                    case "elseif":
+                    case "if":
+                    {
+                        data.data.setRelativeJump(inst.size() + 1);
+                        addInstruction(previous().getLine(), "endif");
+                        break;
+                    }
+                    case "for":
+                    {
+                        loopJumps.pop();
+                        createBreakContinue(inst.size());
+                        JumpData jump = data.data;
+                        jump.setRelativeJump(inst.size());
+                        addInstruction(previous().getLine(), "next", new JumpData(-jump.getInt(null) - 1));
+                        break;
+                    }
+                    case "while":
+                    {
+                        loopJumps.pop();
+                        createBreakContinue(inst.size());
+
+                        JumpData jump = data.data;
+                        jump.setRelativeJump(inst.size() + 1);
+                        addInstruction(previous().getLine(), "wend", new JumpData(-jump.getInt(null) - 1));
+                        break;
+                    }
+                }
+            }
+        }
+        return inst.toArray(new Instruction[inst.size()]);
+    }
+    
+    private void createBreakContinue(int current)
+    {
+        breakContinueJumps.forEach(jump -> jump.setRelativeJump(current));
+        breakContinueJumps.clear();
+    }
+    
+    private InputProvider binaryFunction(InputProvider left, Object t, InputProvider right)
+    {
+        return new Function(FunctionLoader.getFunction(t.toString()), new InputProvider[] {left, right});
+    }
+    
+    private InputProvider unaryFunction(InputProvider in, Object t)
+    {
+        return new Function(FunctionLoader.getFunction(t.toString()), new InputProvider[] {in});
+    }
+    
+    private InputProvider parseExpression()
+    {
+        return parseAssignment();
+    }
+    
+    // level 14
+    private InputProvider parseAssignment() 
+    {
+        InputProvider expr = parseLogicalOr();
+        while(match(SET, ADD_SET, SUB_SET, MUL_SET, DIV_SET, MOD_SET, LEFT_SHIFT_SET, RIGHT_SHIFT_SET, BIT_AND_SET, BIT_XOR_SET, BIT_OR_SET)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseAssignment();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 12
+    private InputProvider parseLogicalOr() 
+    {
+        InputProvider expr = parseLogicalAnd();
+        while(match(OR)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseLogicalAnd();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 11
+    private InputProvider parseLogicalAnd() 
+    {
+        InputProvider expr = parseBitOr();
+        while(match(AND)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseBitOr();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 10
+    private InputProvider parseBitOr() 
+    {
+        InputProvider expr = parseBitXor();
+        while(match(BIT_OR)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseBitXor();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 9
+    private InputProvider parseBitXor() 
+    {
+        InputProvider expr = parseBitAnd();
+        while(match(BIT_XOR)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseBitAnd();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 8
+    private InputProvider parseBitAnd() 
+    {
+        InputProvider expr = parseEquality();
+        while(match(BIT_AND)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseEquality();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 7
+    private InputProvider parseEquality() 
+    {
+        InputProvider expr = parseComparison();
+        while(match(EQUAL, NOT_EQUAL)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseComparison();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 6
+    private InputProvider parseComparison() 
+    {
+        InputProvider expr = parseShifting();
+        while(match(GREATER, GREATER_EQUAL, LESS, LESS_EQUAL)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseShifting();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 5
+    private InputProvider parseShifting() 
+    {
+        InputProvider expr = parseAddition();
+        while(match(LEFT_SHIFT, RIGHT_SHIFT)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseAddition();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 4
+    private InputProvider parseAddition() 
+    {
+        InputProvider expr = parseMultiplication();
+        while(match(SUB, ADD)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseMultiplication();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+
+    // level 3
+    private InputProvider parseMultiplication() 
+    {
+        InputProvider expr = parseUnary();
+        while(match(DIV, MUL, MOD)) 
+        {
+            Token operator = previous();
+            InputProvider right = parseUnary();
+            expr = binaryFunction(expr, operator, right);
+        }
+        return expr;
+    }
+    
+    // level 2
+    private InputProvider parseUnary() 
+    {
+        if(match(INVERT, SUB, BIT_INVERT, INC, DEC)) 
+        {
+            if(previous().getToken() == SUB)
+            {
+                return new SignInverter(parseUnary());
+            }
+            Token operator = previous();
+            InputProvider right = parseUnary();
+            return unaryFunction(right, operator);
+        }
+        return parsePost();
+    }
+    
+    // level 1
+    private InputProvider parsePost() 
+    {
+        InputProvider expr = primary();
+        while(true) 
+        {
+            if(match(INC, DEC))
+            {
+                Token operator = previous();
+                expr = unaryFunction(expr, "p" + operator);
+            }
+            else if(match(OPEN_BRACKET))
+            {
+                expr = new Function(FunctionLoader.getFunction(expr.toString()), parseArguments(CLOSE_BRACKET));     
+            }
+            else if(match(OPEN_SQUARE_BRACKET))
+            {
+                String name = expr.toString();
+                Variable oldVar = vars.get(name);
+                if(oldVar == null)
+                {
+                    oldVar = new ArrayVariable(name);
+                    vars.put(name, oldVar);
+                }
+                return new DynamicArray(oldVar, parseArguments(CLOSE_SQUARE_BRACKET));
+            }
+            else
+            {
+                break;
+            }
+        }
+        return expr;
+    }
+    
+    private InputProvider[] parseArguments(TokenType close)
+    {
+        if(match(close))
+        {
+            return new InputProvider[0];
+        }
+        LinkedList<InputProvider> list = new LinkedList<>();
+        while(true)
+        {
+            list.add(parseExpression());
+            if(match(close))
+            {
+                return list.toArray(new InputProvider[list.size()]);
+            }
+            consume(COMMA, "missing ',' in function");
+        }
+    }
+    
+    private InputProvider primary() 
+    {
+        if(match(FALSE)) 
+        {
+            return ConstantBoolean.FALSE;
+        }
+        else if(match(TRUE)) 
+        {
+            return ConstantBoolean.TRUE;
+        }
+        else if(match(NULL)) 
+        {
+            return ConstantNull.NULL;
+        }
+        else if(match(DOUBLE)) 
+        {
+            return new ConstantDouble((double) previous().getData());
+        }
+        else if(match(TEXT)) 
+        {
+            return new ConstantString((String) previous().getData());
+        }
+        else if(match(VAR)) 
+        {
+            String name = (String) previous().getData();
+            Variable v = vars.get(name);
+            if(v == null)
+            {
+                v = new Variable(name);
+                vars.put(name, v);
+            }
+            return v;
+        }
+        else if(match(IF, ELSE_IF))
+        {
+            String name = previous().getToken() == IF ? "if" : "elseif";
+            
+            consume(OPEN_BRACKET, "if without (");
+            
+            InputProvider[] input = parseArguments(CLOSE_BRACKET);
+            InputProvider[] realInput = new InputProvider[input.length + 1];
+            System.arraycopy(input, 0, realInput, 0, input.length);
+            
+            JumpData jump = new JumpData(inst.size());
+            realInput[input.length] = jump;
+            jumps.push(new JumpWrapper(jump, name));
+            return new Function(FunctionLoader.getFunction(name), realInput);
+        }
+        else if(match(ELSE))
+        {
+            peek(OPEN_CURVED_BRACKET, "unexpected token after 'else': " + tokens[current]);
+            JumpData jump = new JumpData(inst.size());
+            jumps.push(new JumpWrapper(jump, "else"));
+            return unaryFunction(jump, "else");
+        }
+        else if(match(FOR))
+        {
+            consume(OPEN_BRACKET, "for without (");
+            // expected syntax
+            // for(var, start, end, step)
+            // for(var, start, end)
+            InputProvider[] input = parseArguments(CLOSE_BRACKET);
+            if(input.length != 3 && input.length != 4)
+            {
+                throw new PreScriptException("invalid 'for' syntax", previous().getLine());
+            }
+            InputProvider[] realInput = new InputProvider[5];
+
+            System.arraycopy(input, 0, realInput, 0, input.length);
+
+            if(input.length == 3)
+            {
+                realInput[3] = new ConstantDouble(1.0);
+            }
+
+            JumpData jump = new JumpData(inst.size());
+            realInput[4] = jump;
+            JumpWrapper wrapper = new JumpWrapper(jump, "for");
+            jumps.push(wrapper);
+            loopJumps.push(wrapper);
+            return new Function(FunctionLoader.getFunction("for"), realInput);
+        }
+        else if(match(WHILE))
+        {
+            consume(OPEN_BRACKET, "for without (");
+            // expected syntax
+            // while(condition)
+            InputProvider[] input = parseArguments(CLOSE_BRACKET);
+            if(input.length != 1)
+            {
+                throw new PreScriptException("invalid conditions at 'while'", previous().getLine());
+            }
+            InputProvider[] realInput = new InputProvider[2];
+            realInput[0] = input[0];
+
+            JumpData jump = new JumpData(inst.size());
+            realInput[1] = jump;
+
+            JumpWrapper wrapper = new JumpWrapper(jump, "while");
+            jumps.push(wrapper);
+            loopJumps.push(wrapper);
+
+            return new Function(FunctionLoader.getFunction("while"), realInput);
+        }
+        else if(match(FUNCTION))
+        {
+            cancel = true;
+            int counter = 0;
+            while(current < tokens.length && tokens[current].getToken() != OPEN_CURVED_BRACKET)
+            {
+                current++;
+            }
+            counter++;
+            current++;
+            while(current < tokens.length && counter != 0)
+            {
+                if(tokens[current].getToken() == OPEN_CURVED_BRACKET)
+                {
+                    counter++;
+                }
+                else if(tokens[current].getToken() == CLOSE_CURVED_BRACKET)
+                {
+                    counter--;
+                }
+                current++;
+            }
+            return new Function(FunctionLoader.getFunction("nothing"), new InputProvider[0]);
+        }
+        else if(match(BREAK))
+        {
+            if(loopJumps.isEmpty())
+            {
+                throw new PreScriptException("break without a loop", previous().getLine());
+            }
+            JumpData jump = new JumpData(inst.size() - 1);
+            breakContinueJumps.add(jump);
+            return unaryFunction(jump, "break");
+        }
+        else if(match(CONTINUE))
+        {
+            if(loopJumps.isEmpty())
+            {
+                throw new PreScriptException("continue without a loop", previous().getLine());
+            }
+            JumpData jump = new JumpData(inst.size());
+            breakContinueJumps.add(jump);
+            return unaryFunction(jump, "continue");
+        }
+        else if(match(RETURN))
+        {
+            if(match(SEMICOLON))
+            {
+                current--;
+                return new Function(FunctionLoader.getFunction("return"), new InputProvider[0]);
+            }
+            return unaryFunction(parseExpression(), "return");
+        }
+        else if(match(TRY))
+        {
+            peek(OPEN_CURVED_BRACKET, "unexpected token after 'try': " + tokens[current]);
+            JumpData jump = new JumpData(inst.size());
+            jumps.push(new JumpWrapper(jump, "try"));
+            return unaryFunction(jump, "try");
+        }
+        else if(match(CATCH))
+        {
+            if(!tryState)
+            {
+                throw new PreScriptException("catch without try", previous().getLine());
+            }
+            peek(OPEN_CURVED_BRACKET, "unexpected token after 'catch': " + tokens[current]);
+            JumpData jump = new JumpData(inst.size());
+            jumps.push(new JumpWrapper(jump, "catch"));
+            return unaryFunction(jump, "catch");
+        }
+        else if(match(OPEN_BRACKET)) 
+        {
+            InputProvider expr = parseExpression();
+            consume(CLOSE_BRACKET, "'(' without ')'");
+            return expr;
+        }
+        throw new PreScriptException("unexpected token: " + tokens[current], tokens[current].getLine());
+    }
+}

+ 44 - 56
src/me/hammerle/snuviscript/token/Token.java

@@ -1,62 +1,50 @@
 package me.hammerle.snuviscript.token;
 
-public enum Token
+public class Token 
 {
-    VAR,
-    INT,
-    DOUBLE,
-    LABEL,
+    private final TokenType t;
+    private final int line;
+    private final Object o;
     
-    INC, // ++
-    DEC, // --
-    INVERT, // !
-    BIT_INVERT, // ~
-    MUL, // *
-    DIV, // /
-    MOD, // %
-    ADD, // +
-    SUB, // -
-    LEFT_SHIFT, // <<
-    RIGHT_SHIFT, // >>
-    SMALLER, // <
-    SMALLER_EQUAL, // <=
-    GREATER, // >
-    GREATER_EQUAL, // >=
-    EQUAL, // ==
-    NOT_EQUAL, // !=
-    BIT_AND, // &
-    BIT_XOR, // ^
-    BIT_OR, // |
-    AND, // &&
-    OR, // ||
-    SET, // =
-    ADD_SET, // +=
-    SUB_SET, // -=
-    MUL_SET, // *=
-    DIV_SET, // /=
-    MOD_SET, // %=
-    LEFT_SHIFT_SET, // <<=
-    RIGHT_SHIFT_SET, // >>=
-    BIT_AND_SET, // &=
-    BIT_XOR_SET, // ^=
-    BIT_OR_SET, // |=
-    COMMA, // ,
-    OPEN_BRACKET, // (
-    CLOSE_BRACKET, // )
-    OPEN_SQUARE_BRACKET, // [
-    CLOSE_SQUARE_BRACKET, // ]
-    OPEN_CURVED_BRACKET, // {
-    CLOSE_CURVED_BRACKET, // }
-    SEMICOLON, // ;
+    public Token(TokenType t, int line, Object o)
+    {
+        this.t = t;
+        this.line = line;
+        this.o = o;
+    }
     
-    IF,
-    ELSE,
-    FOR,
-    WHILE,
-    FUNCTION,
-    BREAK,
-    CONTINUE,
-    RETURN,
-    GOTO,
-    GOSUB
+    public Token(TokenType t, int line)
+    {
+        this(t, line, null);
+    }
+    
+    public TokenType getToken()
+    {
+        return t;
+    }
+    
+    public Object getData()
+    {
+        return o;
+    }
+    
+    public int getLine()
+    {
+        return line;
+    }
+
+    @Override
+    public String toString() 
+    {
+        if(o != null)
+        {
+            StringBuilder sb = new StringBuilder();
+            sb.append(t);
+            sb.append('(');
+            sb.append(o);
+            sb.append(')');
+            return sb.toString();
+        }
+        return t.toString();
+    }
 }

+ 0 - 36
src/me/hammerle/snuviscript/token/TokenData.java

@@ -1,36 +0,0 @@
-package me.hammerle.snuviscript.token;
-
-public class TokenData 
-{
-    private final Token t;
-    private final int line;
-    private final Object o;
-    
-    public TokenData(Token t, int line, Object o)
-    {
-        this.t = t;
-        this.line = line;
-        this.o = o;
-    }
-    
-    public TokenData(Token t, int line)
-    {
-        this(t, line, null);
-    }
-
-    @Override
-    public String toString() 
-    {
-        StringBuilder sb = new StringBuilder();
-        sb.append(t);
-        sb.append('(');
-        sb.append(line);
-        if(o != null)
-        {
-            sb.append(", ");
-            sb.append(o);
-        }
-        sb.append(')');
-        return sb.toString();
-    }
-}

+ 81 - 0
src/me/hammerle/snuviscript/token/TokenType.java

@@ -0,0 +1,81 @@
+package me.hammerle.snuviscript.token;
+
+public enum TokenType
+{
+    DOUBLE("double"),
+    TRUE("true"),
+    FALSE("false"),
+    NULL("null"),
+    TEXT("String"),
+    LABEL("Label"),
+    VAR("var"),
+    
+    INC("++"),
+    DEC("--"),
+    INVERT("!"), 
+    BIT_INVERT("~"), 
+    MUL("*"), 
+    DIV("/"), 
+    MOD("%"), 
+    ADD("+"), 
+    SUB("-"), 
+    LEFT_SHIFT("<<"), 
+    RIGHT_SHIFT(">>"), 
+    LESS("<"), 
+    LESS_EQUAL("<="), 
+    GREATER(">"), 
+    GREATER_EQUAL(">="), 
+    EQUAL("=="), 
+    NOT_EQUAL("!="), 
+    BIT_AND("&"), 
+    BIT_XOR("^"), 
+    BIT_OR("|"), 
+    AND("&&"), 
+    OR("||"), 
+    SET("="), 
+    ADD_SET("+="), 
+    SUB_SET("-="), 
+    MUL_SET("*="), 
+    DIV_SET("/="), 
+    MOD_SET("%="), 
+    LEFT_SHIFT_SET("<<="), 
+    RIGHT_SHIFT_SET(">>="), 
+    BIT_AND_SET("&="), 
+    BIT_XOR_SET("^="), 
+    BIT_OR_SET("|="), 
+    COMMA(","), 
+    OPEN_BRACKET("("), 
+    CLOSE_BRACKET(")"), 
+    OPEN_SQUARE_BRACKET("["), 
+    CLOSE_SQUARE_BRACKET("]"), 
+    OPEN_CURVED_BRACKET("{"), 
+    CLOSE_CURVED_BRACKET("}"), 
+    SEMICOLON(";"), 
+    
+    IF("if"),
+    ELSE_IF("elseif"),
+    ELSE("else"),
+    FOR("for"),
+    WHILE("while"),
+    FUNCTION("function"),
+    BREAK("break"),
+    CONTINUE("continue"),
+    RETURN("return"),
+    TRY("try"),
+    CATCH("catch"),
+    
+    END_OF_FILE("end_of_file");
+    
+    private final String name;
+    
+    TokenType(String name)
+    {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() 
+    {
+        return name;
+    }
+}

+ 134 - 100
src/me/hammerle/snuviscript/token/Tokenizer.java

@@ -1,6 +1,7 @@
 package me.hammerle.snuviscript.token;
 
 import java.util.LinkedList;
+import me.hammerle.snuviscript.code.Instruction;
 import me.hammerle.snuviscript.exceptions.PreScriptException;
 
 public class Tokenizer 
@@ -8,7 +9,7 @@ public class Tokenizer
     private final char[] code;
     private int line;
     
-    private final LinkedList<TokenData> data;
+    private final LinkedList<Token> data;
     
     public Tokenizer(String code)
     {
@@ -16,14 +17,14 @@ public class Tokenizer
         this.data = new LinkedList<>();
     }
     
-    private void addToken(Token t)
+    private void addToken(TokenType t)
     {
-        data.add(new TokenData(t, line));
+        data.add(new Token(t, line + 1));
     }
     
-    private void addToken(Token t, Object o)
+    private void addToken(TokenType t, Object o)
     {
-        data.add(new TokenData(t, line, o));
+        data.add(new Token(t, line + 1, o));
     }
     
     public void tokenize()
@@ -35,78 +36,64 @@ public class Tokenizer
             {
                 int old = index;
                 index++;
-                while(index < code.length && Character.isLetterOrDigit(code[index]))
+                while(index < code.length && (Character.isLetterOrDigit(code[index]) || code[index] == '.' || code[index] == '_'))
                 {
                     index++;
                 }
                 String s = new String(code, old, index - old);
                 switch(s)
                 {
-                    case "if": addToken(Token.IF); break;
-                    case "else": addToken(Token.ELSE); break;
-                    case "for": addToken(Token.FOR); break;
-                    case "while": addToken(Token.WHILE); break;
-                    case "function": addToken(Token.FUNCTION); break;
-                    case "break": addToken(Token.BREAK); break;
-                    case "continue": addToken(Token.CONTINUE); break;
-                    case "return": addToken(Token.RETURN); break;
-                    case "goto": addToken(Token.GOTO); break;
-                    case "gosub": addToken(Token.GOSUB); break;
+                    case "if": addToken(TokenType.IF); break;
+                    case "elseif": addToken(TokenType.ELSE_IF); break;
+                    case "else": addToken(TokenType.ELSE); break;
+                    case "for": addToken(TokenType.FOR); break;
+                    case "while": addToken(TokenType.WHILE); break;
+                    case "function": addToken(TokenType.FUNCTION); break;
+                    case "break": addToken(TokenType.BREAK); break;
+                    case "continue": addToken(TokenType.CONTINUE); break;
+                    case "return": addToken(TokenType.RETURN); break;
+                    case "try": addToken(TokenType.TRY); break;
+                    case "catch": addToken(TokenType.CATCH); break;
                     default:
-                        addToken(Token.VAR, s);
+                        addToken(TokenType.VAR, s);
                 }
                 index--;
             }
             else if(Character.isDigit(code[index]))
             {
-                int value = code[index] - '0';
+                int old = index;
                 index++;
-                boolean b = true;
                 while(index < code.length)
                 {
-                    if(Character.isDigit(code[index]))
+                    switch(code[index])
                     {
-                        if(value <= (2147483647 - code[index] + '0') / 10)
-                        {
-                            value = value * 10 + code[index] - '0';
-                        }
-                        else
+                        case '0':
+                        case '1':
+                        case '2':
+                        case '3':
+                        case '4':
+                        case '5':
+                        case '6':
+                        case '7':
+                        case '8':
+                        case '9':
                         {
-                            throw new PreScriptException("int to big", line);
+                            index++;
+                            continue;
                         }
-                    }
-                    else if(code[index] == '.')
-                    {
-                        index++;
-                        double dValue = value;
-                        double factor = 10.0;
-                        while(index < code.length)
+                        case '.':
                         {
-                            if(Character.isDigit(code[index]))
-                            {
-                                dValue = dValue + (code[index] - '0') / factor;
-                                factor *= 10.0;
-                            }
-                            else
+                            index++;
+                            while(index < code.length && Character.isDigit(code[index]))
                             {
-                                break;
+                                index++;
                             }
-                            index++;
+                            break;
                         }
-                        addToken(Token.DOUBLE, dValue);
-                        b = false;
-                        break;
                     }
-                    else
-                    {
-                        break;
-                    }
-                    index++;
-                }
-                if(b)
-                {
-                    addToken(Token.INT, value);
+                    break;
                 }
+                addToken(TokenType.DOUBLE, Double.parseDouble(new String(code, old, index - old)));
                 index--;
             }
             else
@@ -117,60 +104,82 @@ public class Tokenizer
                     switch(code[index])
                     {
                         case '\n':
+                        {
                             line++;
                             break;
+                        }
                         case '@':
+                        {
                             int old = index;
                             index++;
-                            while(index < code.length && Character.isLetterOrDigit(code[index]))
+                            while(index < code.length && (Character.isLetterOrDigit(code[index]) || code[index] == '.' || code[index] == '_'))
                             {
                                 index++;
                             }
-                            addToken(Token.LABEL, new String(code, old, index - old));
+                            addToken(TokenType.LABEL, new String(code, old, index - old));
                             index--;
                             break;
+                        }
+                        case '"':
+                        {
+                            int old = index + 1;
+                            index++;
+                            while(index < code.length && code[index] != '"')
+                            {
+                                index++;
+                            }
+                            addToken(TokenType.TEXT, new String(code, old, index - old));
+                            break;
+                        }
                         case '+':
+                        {
                             switch(code[index + 1])
                             {
                                 case '+':
-                                    addToken(Token.INC);
+                                    addToken(TokenType.INC);
                                     index++;
                                     break;
                                 case '=':
-                                    addToken(Token.ADD_SET);
+                                    addToken(TokenType.ADD_SET);
                                     index++;
                                     break;
                                 default:
-                                    addToken(Token.ADD);
+                                    addToken(TokenType.ADD);
                             }
                             break;
+                        }
                         case '-':
+                        {
                             switch(code[index + 1])
                             {
                                 case '-':
-                                    addToken(Token.DEC);
+                                    addToken(TokenType.DEC);
                                     index++;
                                     break;
                                 case '=':
-                                    addToken(Token.SUB_SET);
+                                    addToken(TokenType.SUB_SET);
                                     index++;
                                     break;
                                 default:
-                                    addToken(Token.SUB);
+                                    addToken(TokenType.SUB);
                             }
                             break;
+                        }
                         case '*':
+                        {
                             if(code[index + 1] == '=')
                             {
-                                addToken(Token.MUL_SET);
+                                addToken(TokenType.MUL_SET);
                                 index++;
                             }
                             else
                             {
-                                addToken(Token.MUL);
+                                addToken(TokenType.MUL);
                             }
                             break;
+                        }
                         case '/':
+                        {
                             switch(code[index + 1])
                             {
                                 case '/':
@@ -183,7 +192,7 @@ public class Tokenizer
                                     break;
                                 case '*':
                                     index += 2;
-                                    while(code[index] != '*' && code[index + 1] != '/')
+                                    while(code[index] != '*' || code[index + 1] != '/')
                                     {
                                         if(code[index] == '\n')
                                         {
@@ -194,162 +203,181 @@ public class Tokenizer
                                     index++;
                                     break;
                                 case '=':
-                                    addToken(Token.DIV_SET);
+                                    addToken(TokenType.DIV_SET);
                                     index++;
                                     break;
                                 default:
-                                    addToken(Token.DIV);
+                                    addToken(TokenType.DIV);
                             }
                             break;
+                        }
                         case '!':
+                        {
                             if(code[index + 1] == '=')
                             {
-                                addToken(Token.NOT_EQUAL);
+                                addToken(TokenType.NOT_EQUAL);
                                 index++;
                                 break;
                             }
                             else
                             {
-                                addToken(Token.INVERT);
+                                addToken(TokenType.INVERT);
                             }
                             break;
+                        }
                         case '~':
-                            addToken(Token.BIT_INVERT);
+                        {
+                            addToken(TokenType.BIT_INVERT);
                             break;
+                        }
                         case '%':
+                        {
                             if(code[index + 1] == '=')
                             {
-                                addToken(Token.MOD_SET);
+                                addToken(TokenType.MOD_SET);
                                 index++;
                             }
                             else
                             {
-                                addToken(Token.MOD);
+                                addToken(TokenType.MOD);
                             }
                             break;
+                        }
                         case '<':
+                        {
                             switch(code[index + 1])
                             {
                                 case '<':
                                     if(code[index + 2] == '=')
                                     {
-                                        addToken(Token.LEFT_SHIFT_SET);
+                                        addToken(TokenType.LEFT_SHIFT_SET);
                                         index += 2;
                                     }
                                     else
                                     {
-                                        addToken(Token.LEFT_SHIFT);
+                                        addToken(TokenType.LEFT_SHIFT);
                                         index++;
                                     }
                                     break;
                                 case '=':
-                                    addToken(Token.SMALLER_EQUAL);
+                                    addToken(TokenType.LESS_EQUAL);
                                     index++;
                                     break;
                                 default:
-                                    addToken(Token.SMALLER);
+                                    addToken(TokenType.LESS);
                             }
                             break;
+                        }
                         case '>':
+                        {
                             switch(code[index + 1])
                             {
                                 case '>':
                                     if(code[index + 2] == '=')
                                     {
-                                        addToken(Token.RIGHT_SHIFT_SET);
+                                        addToken(TokenType.RIGHT_SHIFT_SET);
                                         index += 2;
                                     }
                                     else
                                     {
-                                        addToken(Token.RIGHT_SHIFT);
+                                        addToken(TokenType.RIGHT_SHIFT);
                                         index++;
                                     }
                                     break;
                                 case '=':
-                                    addToken(Token.GREATER_EQUAL);
+                                    addToken(TokenType.GREATER_EQUAL);
                                     index++;
                                     break;
                                 default:
-                                    addToken(Token.GREATER);
+                                    addToken(TokenType.GREATER);
                             }
                             break;
-                        case '=':
+                        }
+                        case '=': 
+                        {
                             if(code[index + 1] == '=')
                             {
-                                addToken(Token.EQUAL);
+                                addToken(TokenType.EQUAL);
                                 index++;
                                 break;
                             }
                             else
                             {
-                                addToken(Token.SET);
+                                addToken(TokenType.SET);
                             }
                             break;
+                        }
                         case '&':
+                        {
                             switch(code[index + 1])
                             {
                                 case '&':
-                                    addToken(Token.AND);
+                                    addToken(TokenType.AND);
                                     index++;
                                     break;
                                 case '=':
-                                    addToken(Token.BIT_AND_SET);
+                                    addToken(TokenType.BIT_AND_SET);
                                     index++;
                                     break;
                                 default:
-                                    addToken(Token.BIT_AND);
+                                    addToken(TokenType.BIT_AND);
                             }
                             break;
+                        }
                         case '^':
+                        {
                             if(code[index + 1] == '=')
                             {
-                                addToken(Token.BIT_XOR_SET);
+                                addToken(TokenType.BIT_XOR_SET);
                                 index++;
                                 break;
                             }
                             else
                             {
-                                addToken(Token.BIT_XOR);
+                                addToken(TokenType.BIT_XOR);
                             }
                             break;
+                        }
                         case '|':
+                        {
                             switch(code[index + 1])
                             {
                                 case '|':
-                                    addToken(Token.OR);
+                                    addToken(TokenType.OR);
                                     index++;
                                     break;
                                 case '=':
-                                    addToken(Token.BIT_OR_SET);
+                                    addToken(TokenType.BIT_OR_SET);
                                     index++;
                                     break;
                                 default:
-                                    addToken(Token.BIT_OR);
+                                    addToken(TokenType.BIT_OR);
                             }
                             break;
+                        }
                         case ',':
-                            addToken(Token.COMMA);
+                            addToken(TokenType.COMMA);
                             break;
                         case '(':
-                            addToken(Token.OPEN_BRACKET);
+                            addToken(TokenType.OPEN_BRACKET);
                             break;
                         case ')':
-                            addToken(Token.CLOSE_BRACKET);
+                            addToken(TokenType.CLOSE_BRACKET);
                             break;
                         case '[':
-                            addToken(Token.OPEN_SQUARE_BRACKET);
+                            addToken(TokenType.OPEN_SQUARE_BRACKET);
                             break;
                         case ']':
-                            addToken(Token.CLOSE_SQUARE_BRACKET);
+                            addToken(TokenType.CLOSE_SQUARE_BRACKET);
                             break;
                         case '{':
-                            addToken(Token.OPEN_CURVED_BRACKET);
+                            addToken(TokenType.OPEN_CURVED_BRACKET);
                             break;
                         case '}':
-                            addToken(Token.CLOSE_CURVED_BRACKET);
+                            addToken(TokenType.CLOSE_CURVED_BRACKET);
                             break;
                         case ';':
-                            addToken(Token.SEMICOLON);
+                            addToken(TokenType.SEMICOLON);
                             break;
                     }
                 }
@@ -358,8 +386,14 @@ public class Tokenizer
                     throw new PreScriptException("unexpected code end", startLine, line);
                 }
             }
-        }
+        }       
+        addToken(TokenType.END_OF_FILE);
+        //data.forEach(e -> System.out.println(e));
         
-        data.forEach(d -> System.out.println(d));
+        Parser p = new Parser(data);
+        for(Instruction in : p.parseTokens())
+        {
+            System.out.println(in);
+        }
     }
 }

+ 1 - 0
src/me/hammerle/snuviscript/variable/LocalVariable.java

@@ -1,6 +1,7 @@
 package me.hammerle.snuviscript.variable;
 
 import java.util.HashMap;
+import me.hammerle.snuviscript.code.InputProvider;
 import me.hammerle.snuviscript.code.Script;
 
 public class LocalVariable extends Variable

+ 8 - 8
test.sbasic

@@ -1,9 +1,9 @@
-wusi = 7483647.3;
-hallo = 2147483647;
-wusi++;
-b = wusi - 3;
-if(wusi < b && wusi == 53)
+i = 5;
+i = 2;
+i = i+i++;
+
+function wusi(a, b)
 {
-    print(a);
-}
-print(b);
+    print("HALLO");
+    return;
+}