2
0
Эх сурвалжийг харах

operator precedence fixes

Vladislav Folts 12 жил өмнө
parent
commit
bfb1492d00

+ 28 - 84
src/context.js

@@ -3,7 +3,7 @@ var Code = require("code.js");
 var Errors = require("errors.js");
 var Lexer = require("lexer.js");
 var Module = require("module.js");
-var precedence = require("operator.js").precedence;
+var op = require("operator.js");
 var Parser = require("parser.js");
 var Procedure = require("procedure.js");
 var ImportRTL = require("rtl.js");
@@ -194,6 +194,7 @@ exports.Designator = ChainedContext.extend({
 		this.__currentType = undefined;
 		this.__info = undefined;
 		this.__code = new Code.SimpleGenerator();
+        this.__indexExpression = undefined;
 		this.__derefCode = undefined;
 		this.__propCode = undefined;
 	},
@@ -225,7 +226,9 @@ exports.Designator = ChainedContext.extend({
 		this.__code.write(id);
 	},
 	codeGenerator: function(){return this.__code;},
-	handleExpression: function(e){
+	handleExpression: function(e){this.__indexExpression = e;},
+    __handleIndexExpression: function(){
+        var e = this.__indexExpression;
         var expType = e.type();
 		if (expType != basicTypes.int)
 			throw new Errors.Error("'INTEGER' expression expected, got '" + expType.name() + "'");
@@ -240,13 +243,11 @@ exports.Designator = ChainedContext.extend({
 								 + ", got " + value );
 		this.__currentType = type.elementsType();
 		this.__info = new Type.Variable(this.__currentType, false, this.__info.isReadOnly());
-        var designator = e.designator();
-		if (designator)
-			writeDerefDesignatorCode(designator, this.__code);
 	},
 	handleLiteral: function(s){
 		if (s == "]" || s == ","){
-			var indexCode = this.__code.result();
+            this.__handleIndexExpression();
+			var indexCode = this.__indexExpression.deref().code();
 			this.__propCode = indexCode;
 			this.__code = new Code.SimpleGenerator(this.__derefCode + "[" + indexCode + "]");
 			}
@@ -584,111 +585,54 @@ function makeUnaryOperator(op, code){
 	};
 }
 
-function makeBinaryOperator(op, code){
-	return function(left, right){
-		var leftValue = left.constValue();
-		var rightValue = right.constValue();
-		var value = (leftValue !== undefined && rightValue !== undefined)
-			? op(leftValue, rightValue) : undefined;
-
-        var leftCode = left.deref().code();
-        var rightCode = right.deref().code();
-        var expCode = (typeof code == "function")
-                    ? code(leftCode, rightCode)
-                    : leftCode + code + rightCode;
-		return new Code.Expression(expCode,	left.type(), undefined,	value);
-	};
-}
-
 exports.AddOperator = ChainedContext.extend({
 	init: function AddOperatorContext(context){
 		ChainedContext.prototype.init.bind(this)(context);
 	},
 	handleLiteral: function(s){
 		var parent = this.parent();
-		if (s == "+"){
-			if (parent.type() == basicTypes.set)
-				parent.handleBinaryOperator(
-					makeBinaryOperator(function(x, y){return x | y;}, " | "));
-			else
-				parent.handleBinaryOperator(
-					makeBinaryOperator(function(x, y){return x + y;}, " + "));
-		}
-		else if (s == "-"){
-			if (parent.type() == basicTypes.set)
-				parent.handleBinaryOperator(
-					makeBinaryOperator(function(x, y){return x & ~y;}, " & ~"));
-			else
-				parent.handleBinaryOperator(
-					makeBinaryOperator(function(x, y){return x - y;}, " - "));
-		}
+        var type = parent.type();
+        var o;
+		if (s == "+")
+			o = (type == basicTypes.set) ? op.setUnion : op.add;
+		else if (s == "-")
+			o = (type == basicTypes.set) ? op.setDiff : op.sub;
 		else if (s == "OR"){
-			var type = parent.type();
 			if (type != basicTypes.bool)
 				throw new Errors.Error("BOOLEAN expected as operand of 'OR', got '"
 									 + type.name() + "'");
-			parent.handleBinaryOperator(
-				makeBinaryOperator(function(x, y){return x || y;}, " || "));
+			o = op.or;
 		}
+        if (o)
+            parent.handleBinaryOperator(o);
 	}
 });
-/*
-var Operator = Class.extend({
-	init: function Operator(eval, code){
-		this.__eval = eval;
-		this.__code = code;
-	},
-	eval: function(x, y){return this.__eval(x, y);},
-	code: function(x, y){return this.__code(x, y);},
-	expression: function(x, y){
-		var xValue = x ? x.constValue() : undefined;
-		var yValue = y.constValue();
-		var value = ((!x || xValue) && yValue) ? this.__eval(xValue, yValue) : undefined;
-		return new Code.Expression(
-			this.__code(x ? x.code() : undefined, y.code()),
-			y.type(),
-			undefined,
-			value
-			);
-	}
-});
-*/
+
 exports.MulOperator = ChainedContext.extend({
 	init: function MulOperatorContext(context){
 		ChainedContext.prototype.init.bind(this)(context);
 	},
 	handleLiteral: function(s){
 		var parent = this.parent();
+        var type = parent.type();
+        var o;
 		if (s == "*")
-			if (parent.type() == basicTypes.set)
-				parent.handleOperator(makeBinaryOperator(
-					  function(x, y){return x & y;}, " & "));
-			else
-				parent.handleOperator(makeBinaryOperator(
-					  function(x, y){return x * y;}, " * "));
+			o = (type == basicTypes.set) ? op.setIntersection : op.mul;
 		else if (s == "/")
-			if (parent.type() == basicTypes.set)
-				parent.handleOperator(makeBinaryOperator(
-					  function(x, y){return x ^ y;}, " ^ "));
-			else
-				parent.handleOperator(makeBinaryOperator(
-					  function(x, y){return x / y;}, " / "));
+			o = (type == basicTypes.set) ? op.setSymmetricDiff : op.divFloat;
 		else if (s == "DIV")
-			parent.handleOperator(makeBinaryOperator(
-				  function(x, y){return (x / y) >> 0;}
-				, function(x, y){return "(" + x + " / " + y + ") >> 0";}
-				));
+			o = op.div;
 		else if (s == "MOD")
-			parent.handleOperator(makeBinaryOperator(
-				  function(x, y){return x % y;}, " % "));
+			o = op.mod;
 		else if (s == "&"){
-			var type = parent.type();
 			if (type != basicTypes.bool)
 				throw new Errors.Error("BOOLEAN expected as operand of '&', got '"
 									 + type.name() + "'");
-			parent.handleOperator(makeBinaryOperator(
-				  function(x, y){return x && y;}, " && "));
+			o = op.and;
 		}
+
+        if (o)
+            parent.handleOperator(o);
 	}
 });
 
@@ -915,7 +859,7 @@ exports.Expression = ChainedContext.extend({
         }
 
         if (this.__relation == "=")
-            code = Code.adjustPrecedence(leftExpression, precedence.equal) + " == " + rightCode;
+            code = op.equal(leftExpression, rightExpression).code();
         else if (this.__relation == "#")
             code = leftCode + " != " + rightCode;
         else if (this.__relation == "<=")

+ 46 - 1
src/operator.js

@@ -1,8 +1,53 @@
+var Code = require("code.js");
+
 var precedence = {
+    mulDivMod: 5,
+    addSub: 6,
     shift: 7,
     equal: 9,
+    bitAnd: 10,
+    bitXor: 11,
+    bitOr: 12,
+    and: 13,
+    or: 14,
     conditional: 15,
     assignment: 17
 };
 
-exports.precedence = precedence;
+function make(op, code, precedence, resultPrecedence){
+    return function(left, right){
+        var leftValue = left.constValue();
+        var rightValue = right.constValue();
+        var value = (leftValue !== undefined && rightValue !== undefined)
+            ? op(leftValue, rightValue) : undefined;
+
+        var leftCode = Code.adjustPrecedence(left.deref(), precedence);
+        var rightCode = Code.adjustPrecedence(right.deref(), precedence);
+        var expCode = (typeof code == "function")
+                    ? code(leftCode, rightCode)
+                    : leftCode + code + rightCode;
+        return new Code.Expression(expCode, left.type(), undefined, value, resultPrecedence ? resultPrecedence : precedence);
+    };
+}
+
+var operators = {
+    add: make(function(x, y){return x + y;}, " + ", precedence.addSub),
+    sub: make(function(x, y){return x - y;}, " - ", precedence.addSub),
+    mul: make(function(x, y){return x * y;}, " * ", precedence.mulDivMod),
+    div: make(function(x, y){return (x / y) >> 0;},
+              function(x, y){return x + " / " + y + " >> 0";},
+              precedence.mulDivMod, precedence.shift),
+    divFloat: make(function(x, y){return x / y;}, " / ", precedence.mulDivMod),
+    mod: make(function(x, y){return x % y;}, " % ", precedence.mulDivMod),
+    setUnion: make(function(x, y){return x | y;}, " | ", precedence.bitOr),
+    setDiff: make(function(x, y){return x & ~y;}, " & ~", precedence.bitAnd),
+    setIntersection: make(function(x, y){return x & y;}, " & ", precedence.bitAnd),
+    setSymmetricDiff: make(function(x, y){return x ^ y;}, " ^ ", precedence.bitXor),
+    or: make(function(x, y){return x || y;}, " || ", precedence.or),
+    and: make(function(x, y){return x && y;}, " && ", precedence.and),
+    equal: make(function(x, y){return x && y;}, " == ", precedence.equal)
+};
+
+for(var p in operators)
+    exports[p] = operators[p];
+exports.precedence = precedence;

+ 1 - 1
test/expected/arithmetic.js

@@ -6,7 +6,7 @@ i2 = 2;
 i1 = i1 + i2;
 i1 = i1 - i2;
 i1 = i1 * i2;
-i1 = (i1 / i2) >> 0;
+i1 = i1 / i2 >> 0;
 i1 = i1 % i2;
 r1 = 1;
 r2 = 2;

+ 1 - 1
test/expected/errors/syntax.txt

@@ -1 +1 @@
-line 4: END expected (MODULE)
+line 5: END expected (MODULE)

+ 60 - 0
test/expected/parentheses.js

@@ -0,0 +1,60 @@
+var RTL$ = {
+	makeArray: function (/*dimensions, initializer*/){
+        var forward = Array.prototype.slice.call(arguments);
+        var result = new Array(forward.shift());
+        var i;
+        if (forward.length == 1){
+            var init = forward[0];
+            if (typeof init == "function")
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init();
+            else
+                for(i = 0; i < result.length; ++i)
+                    result[i] = init;
+        }
+        else
+            for(i = 0; i < result.length; ++i)
+                result[i] = RTLMakeArray.apply(this, forward);
+        return result;
+    },
+	assert: function (condition, code){
+        if (!condition)
+            throw new Error("assertion failed"
+                          + ((code !== undefined) ? " with code " + code : ""));
+    }
+};
+var m = function (){
+var ch = 0;
+var i = 0;
+var b = false;
+var r = 0;
+var s = 0;
+var a = RTL$.makeArray(10, 0);
+i = 65;
+ch = i;
+i = (ch + i) / 2;
+RTL$.assert(i == 65);
+a[(i - 64) * 3] = i;
+i = i + i - 1;
+i = i - i + 1;
+i = i * i + 1;
+i = i * (i + 1);
+i = (i / 2 >> 0) + 1;
+i = i / (2 + 1) >> 0;
+r = r / 2 + 1;
+r = r / (2 + 1);
+i = i % 2 + 1;
+i = i % (2 + 1);
+b = b && b || b;
+b = b && (b || b);
+b = b && b || b;
+b = b || b && b;
+b = b == b || b;
+b = b == (b || b);
+s = (s | s) & ~s;
+s = s | s & ~s;
+s = s & s ^ s;
+s = s & (s ^ s);
+s = s & s | s;
+s = s & (s | s);
+}();

+ 2 - 1
test/input/errors/syntax.ob

@@ -1,5 +1,6 @@
 MODULE m1;
 VAR i: INTEGER;
 BEGIN
-	i := 1; (* extra semicolon *)
+	i := 1;
+	!!!
 END m1.

+ 44 - 0
test/input/parentheses.ob

@@ -0,0 +1,44 @@
+MODULE m;
+
+VAR ch: CHAR; i: INTEGER; b: BOOLEAN; r: REAL; s: SET; a: ARRAY 10 OF INTEGER;
+
+BEGIN
+    i := 65;
+    ch := CHR(i);
+	i := (ORD(ch) + i) / 2;
+    ASSERT(i = 65);
+
+	a[(i - 64) * 3] := i;
+
+    i := i + (i - 1);
+    i := (i - i) + 1;
+
+    i := (i * i) + 1;
+    i := i * (i + 1);
+
+    i := i DIV 2 + 1;
+    i := i DIV (2 + 1);
+
+    r := r / 2. + 1.;
+    r := r / (2. + 1.);
+
+    i := i MOD 2 + 1;
+    i := i MOD (2 + 1);
+
+    b := (b & b) OR b;
+    b := b & (b OR b);
+    b := b & b OR b;
+    b := b OR b & b;
+    
+    b := (b = b) OR b;
+    b := b = (b OR b);
+
+    s := (s + s) - s;
+    s := s + (s - s);
+
+    s := (s * s) / s;
+    s := s * (s / s);
+
+    s := s * s + s;
+    s := s * (s + s);
+END m.