mirror of
https://github.com/hneemann/Digital.git
synced 2025-09-16 00:15:01 -04:00
improved hgs double support
This commit is contained in:
parent
c4abf9a395
commit
5af455adbb
@ -12,6 +12,7 @@ import de.neemann.digital.lang.Lang;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The evaluation context
|
||||
@ -254,7 +255,7 @@ public class Context {
|
||||
for (int i = 1; i < args.size(); i++)
|
||||
eval.add(args.get(i).value(c));
|
||||
|
||||
return String.format(Value.toString(args.get(0).value(c)), eval.toArray());
|
||||
return String.format(Locale.US, Value.toString(args.get(0).value(c)), eval.toArray());
|
||||
}
|
||||
|
||||
private static final class FunctionIsPresent extends InnerFunction {
|
||||
|
@ -70,7 +70,7 @@ public class Parser {
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
* @param reader the reader to parse
|
||||
* @param reader the reader to parse
|
||||
* @param srcFile the source file name if any
|
||||
*/
|
||||
public Parser(Reader reader, String srcFile) {
|
||||
@ -323,6 +323,14 @@ public class Parser {
|
||||
}
|
||||
}
|
||||
|
||||
private double convToDouble(String num) throws ParserException {
|
||||
try {
|
||||
return Double.parseDouble(num);
|
||||
} catch (NumberFormatException e) {
|
||||
throw newParserException("not a number: " + tok.getIdent());
|
||||
}
|
||||
}
|
||||
|
||||
private ParserException newUnexpectedToken(Tokenizer.Token token) {
|
||||
String name = token == IDENT ? tok.getIdent() : token.name();
|
||||
return newParserException("unexpected Token: " + name);
|
||||
@ -356,13 +364,13 @@ public class Parser {
|
||||
case NOTEQUAL:
|
||||
return c -> !Value.equals(a.value(c), b.value(c));
|
||||
case LESS:
|
||||
return c -> Value.toLong(a.value(c)) < Value.toLong(b.value(c));
|
||||
return c -> Value.less(a.value(c), b.value(c));
|
||||
case LESSEQUAL:
|
||||
return c -> Value.toLong(a.value(c)) <= Value.toLong(b.value(c));
|
||||
return c -> Value.lessEqual(a.value(c), b.value(c));
|
||||
case GREATER:
|
||||
return c -> Value.toLong(a.value(c)) > Value.toLong(b.value(c));
|
||||
return c -> Value.less(b.value(c), a.value(c));
|
||||
case GREATEREQUAL:
|
||||
return c -> Value.toLong(a.value(c)) >= Value.toLong(b.value(c));
|
||||
return c -> Value.lessEqual(b.value(c), a.value(c));
|
||||
default:
|
||||
throw newUnexpectedToken(t);
|
||||
}
|
||||
@ -435,7 +443,7 @@ public class Parser {
|
||||
while (nextIs(SUB)) {
|
||||
Expression a = ac;
|
||||
Expression b = parseMul();
|
||||
ac = c -> Value.toLong(a.value(c)) - Value.toLong(b.value(c));
|
||||
ac = c -> Value.sub(a.value(c), b.value(c));
|
||||
}
|
||||
return ac;
|
||||
}
|
||||
@ -445,7 +453,7 @@ public class Parser {
|
||||
while (nextIs(MUL)) {
|
||||
Expression a = ac;
|
||||
Expression b = parseDiv();
|
||||
ac = c -> Value.toLong(a.value(c)) * Value.toLong(b.value(c));
|
||||
ac = c -> Value.mul(a.value(c), b.value(c));
|
||||
}
|
||||
return ac;
|
||||
}
|
||||
@ -455,7 +463,7 @@ public class Parser {
|
||||
while (nextIs(DIV)) {
|
||||
Expression a = ac;
|
||||
Expression b = parseMod();
|
||||
ac = c -> Value.toLong(a.value(c)) / Value.toLong(b.value(c));
|
||||
ac = c -> Value.div(a.value(c), b.value(c));
|
||||
}
|
||||
return ac;
|
||||
}
|
||||
@ -480,6 +488,9 @@ public class Parser {
|
||||
case NUMBER:
|
||||
long num = convToLong(tok.getIdent());
|
||||
return c -> num;
|
||||
case DOUBLE:
|
||||
double d = convToDouble(tok.getIdent());
|
||||
return c -> d;
|
||||
case STRING:
|
||||
String s = tok.getIdent();
|
||||
return c -> s;
|
||||
|
@ -18,7 +18,7 @@ class Tokenizer {
|
||||
UNKNOWN, IDENT, AND, OR, XOR, NOT, OPEN, CLOSE, NUMBER, EOL, EOF, SHIFTLEFT, SHIFTRIGHT, COMMA, EQUAL,
|
||||
ADD, SUB, MUL, GREATER, LESS, DIV, MOD, END, IF, ELSE, FOR, WHILE, SEMICOLON, NOTEQUAL, STRING,
|
||||
OPENBRACE, CLOSEDBRACE, CODEEND, OPENSQUARE, CLOSEDSQUARE, DOT, STATIC, FUNC, GREATEREQUAL, LESSEQUAL,
|
||||
REPEAT, RETURN, COLON, UNTIL
|
||||
REPEAT, RETURN, COLON, UNTIL, DOUBLE
|
||||
}
|
||||
|
||||
private static HashMap<String, Token> statementMap = new HashMap<>();
|
||||
@ -275,6 +275,9 @@ class Tokenizer {
|
||||
c = readChar();
|
||||
if (isNumberChar(c) || isHexChar(c) || c == 'x' || c == 'X') {
|
||||
builder.append((char) c);
|
||||
} else if (c == '.') {
|
||||
builder.append((char) c);
|
||||
token = Token.DOUBLE;
|
||||
} else {
|
||||
unreadChar(c);
|
||||
wasChar = false;
|
||||
|
@ -123,7 +123,9 @@ public final class Value {
|
||||
* @return true if both values are equal
|
||||
*/
|
||||
public static boolean equals(Object a, Object b) {
|
||||
if (a instanceof Number && b instanceof Number)
|
||||
if (a instanceof Double || b instanceof Double)
|
||||
return a.equals(b);
|
||||
else if (a instanceof Number && b instanceof Number)
|
||||
return ((Number) a).longValue() == ((Number) b).longValue();
|
||||
else if (a instanceof String || b instanceof String)
|
||||
return a.toString().equals(b.toString());
|
||||
@ -140,6 +142,8 @@ public final class Value {
|
||||
* @throws HGSEvalException HGSEvalException
|
||||
*/
|
||||
public static Object add(Object a, Object b) throws HGSEvalException {
|
||||
if (a instanceof Double || b instanceof Double)
|
||||
return toDouble(a) + toDouble(b);
|
||||
if (a instanceof Number && b instanceof Number)
|
||||
return ((Number) a).longValue() + ((Number) b).longValue();
|
||||
if (a instanceof String || b instanceof String)
|
||||
@ -147,6 +151,54 @@ public final class Value {
|
||||
throw new HGSEvalException("arguments must be int or string, not " + a.getClass().getSimpleName() + "+" + b.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts two values
|
||||
*
|
||||
* @param a a value
|
||||
* @param b a value
|
||||
* @return the sum
|
||||
* @throws HGSEvalException HGSEvalException
|
||||
*/
|
||||
public static Object sub(Object a, Object b) throws HGSEvalException {
|
||||
if (a instanceof Double || b instanceof Double)
|
||||
return toDouble(a) - toDouble(b);
|
||||
if (a instanceof Number && b instanceof Number)
|
||||
return ((Number) a).longValue() - ((Number) b).longValue();
|
||||
throw new HGSEvalException("arguments must be int or double, not " + a.getClass().getSimpleName() + "+" + b.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies two values
|
||||
*
|
||||
* @param a a value
|
||||
* @param b a value
|
||||
* @return the product
|
||||
* @throws HGSEvalException HGSEvalException
|
||||
*/
|
||||
public static Object mul(Object a, Object b) throws HGSEvalException {
|
||||
if (a instanceof Double || b instanceof Double)
|
||||
return toDouble(a) * toDouble(b);
|
||||
if (a instanceof Number && b instanceof Number)
|
||||
return ((Number) a).longValue() * ((Number) b).longValue();
|
||||
throw new HGSEvalException("arguments must be int or double, not " + a.getClass().getSimpleName() + "+" + b.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides two numbers
|
||||
*
|
||||
* @param a a value
|
||||
* @param b a value
|
||||
* @return the quotient
|
||||
* @throws HGSEvalException HGSEvalException
|
||||
*/
|
||||
public static Object div(Object a, Object b) throws HGSEvalException {
|
||||
if (a instanceof Double || b instanceof Double)
|
||||
return toDouble(a) / toDouble(b);
|
||||
if (a instanceof Number && b instanceof Number)
|
||||
return ((Number) a).longValue() / ((Number) b).longValue();
|
||||
throw new HGSEvalException("arguments must be int or double, not " + a.getClass().getSimpleName() + "+" + b.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an or operation
|
||||
*
|
||||
@ -202,6 +254,42 @@ public final class Value {
|
||||
return !toBool(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper compare two values
|
||||
*
|
||||
* @param a a value
|
||||
* @param b a value
|
||||
* @return true if a<b
|
||||
* @throws HGSEvalException HGSEvalException
|
||||
*/
|
||||
public static boolean less(Object a, Object b) throws HGSEvalException {
|
||||
if (a instanceof Double || b instanceof Double)
|
||||
return toDouble(a) < toDouble(b);
|
||||
if (a instanceof Number && b instanceof Number)
|
||||
return toLong(a) < toLong(b);
|
||||
if (a instanceof String && b instanceof String)
|
||||
return a.toString().compareTo(b.toString()) < 0;
|
||||
throw new HGSEvalException("arguments must be int, double or string, not " + a.getClass().getSimpleName() + "+" + b.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper compare two values
|
||||
*
|
||||
* @param a a value
|
||||
* @param b a value
|
||||
* @return true if a<=b
|
||||
* @throws HGSEvalException HGSEvalException
|
||||
*/
|
||||
public static boolean lessEqual(Object a, Object b) throws HGSEvalException {
|
||||
if (a instanceof Double || b instanceof Double)
|
||||
return toDouble(a) <= toDouble(b);
|
||||
if (a instanceof Number && b instanceof Number)
|
||||
return toLong(a) <= toLong(b);
|
||||
if (a instanceof String && b instanceof String)
|
||||
return a.toString().compareTo(b.toString()) <= 0;
|
||||
throw new HGSEvalException("arguments must be int, double or string, not " + a.getClass().getSimpleName() + "+" + b.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims spaces at the right side of the string.
|
||||
*
|
||||
|
@ -78,6 +78,21 @@ public class ParserTest extends TestCase {
|
||||
assertEquals("Hallo_true", new Parser("\"Hallo_\" + (1<2)").parseExp().value(new Context()));
|
||||
}
|
||||
|
||||
public void testParseExpArithDouble() throws IOException, ParserException, HGSEvalException {
|
||||
assertEquals(4.0, new Parser("1.5+2.5").parseExp().value(new Context()));
|
||||
assertEquals(0.5, new Parser("1.5-1").parseExp().value(new Context()));
|
||||
assertEquals(3.0, new Parser("1.5*2").parseExp().value(new Context()));
|
||||
assertEquals(3.0, new Parser("2*1.5").parseExp().value(new Context()));
|
||||
assertEquals(1L, new Parser("3/2").parseExp().value(new Context()));
|
||||
assertEquals(1.5, new Parser("3.0/2").parseExp().value(new Context()));
|
||||
assertEquals(1.5, new Parser("3/2.0").parseExp().value(new Context()));
|
||||
assertEquals(1.5, new Parser("3.0/2.0").parseExp().value(new Context()));
|
||||
assertEquals(true, new Parser("1.0001>1").parseExp().value(new Context()));
|
||||
assertEquals(false, new Parser("1>1.0001").parseExp().value(new Context()));
|
||||
assertEquals(false, new Parser("1.0001<1").parseExp().value(new Context()));
|
||||
assertEquals(true, new Parser("1<1.0001").parseExp().value(new Context()));
|
||||
}
|
||||
|
||||
public void testParseExpCompare() throws IOException, ParserException, HGSEvalException {
|
||||
assertEquals(true, new Parser("5=5").parseExp().value(new Context()));
|
||||
assertEquals(true, new Parser("\"Hello\"=\"Hello\"").parseExp().value(new Context()));
|
||||
@ -85,6 +100,10 @@ public class ParserTest extends TestCase {
|
||||
assertEquals(false, new Parser("5!=5").parseExp().value(new Context()));
|
||||
assertEquals(false, new Parser("\"Hello\"!=\"Hello\"").parseExp().value(new Context()));
|
||||
assertEquals(true, new Parser("\"Hello\"!=\"World\"").parseExp().value(new Context()));
|
||||
assertEquals(true, new Parser("\"a\"<\"b\"").parseExp().value(new Context()));
|
||||
assertEquals(false, new Parser("\"b\"<\"a\"").parseExp().value(new Context()));
|
||||
assertEquals(false, new Parser("\"a\">\"b\"").parseExp().value(new Context()));
|
||||
assertEquals(true, new Parser("\"b\">\"a\"").parseExp().value(new Context()));
|
||||
|
||||
assertEquals(false, new Parser("5<5").parseExp().value(new Context()));
|
||||
assertEquals(true, new Parser("4<5").parseExp().value(new Context()));
|
||||
@ -265,6 +284,10 @@ public class ParserTest extends TestCase {
|
||||
Context c = new Context().declareVar("Bits", 17);
|
||||
exec("<? a:=format(\"hex=%x;\",Bits); print(a);?>", c);
|
||||
assertEquals("hex=11;", c.toString());
|
||||
|
||||
c = new Context().declareVar("freq", Math.PI*100);
|
||||
exec("<? a:=format(\"f=%.2f;\",freq); print(a);?>", c);
|
||||
assertEquals("f=314.16;", c.toString());
|
||||
}
|
||||
|
||||
public void testComment() throws IOException, ParserException, HGSEvalException {
|
||||
|
Loading…
x
Reference in New Issue
Block a user