aboutsummaryrefslogtreecommitdiff
path: root/calculator-java/src/main/java/ch/bfh/CalculatorLexer.java
diff options
context:
space:
mode:
authorMaël Gassmann <mael.gassmann@students.bfh.ch>2021-06-11 01:39:49 +0200
committerMaël Gassmann <mael.gassmann@students.bfh.ch>2021-06-11 01:39:49 +0200
commit126a6c85b60ad07fa29ab48315f0f195fb45d854 (patch)
tree1c0245fc232c701da8577a5451d703a0d5808822 /calculator-java/src/main/java/ch/bfh/CalculatorLexer.java
parentee369b50b14ffe662e05355459f57c076680cd58 (diff)
[+] First version of the java calculator
Diffstat (limited to 'calculator-java/src/main/java/ch/bfh/CalculatorLexer.java')
-rw-r--r--calculator-java/src/main/java/ch/bfh/CalculatorLexer.java106
1 files changed, 106 insertions, 0 deletions
diff --git a/calculator-java/src/main/java/ch/bfh/CalculatorLexer.java b/calculator-java/src/main/java/ch/bfh/CalculatorLexer.java
new file mode 100644
index 0000000..ba10944
--- /dev/null
+++ b/calculator-java/src/main/java/ch/bfh/CalculatorLexer.java
@@ -0,0 +1,106 @@
+package ch.bfh;
+import ch.bfh.exceptions.LexerException;
+
+// Lexer for classical arithmetic expressions with identifiers and assignments.
+// Scans a source string char by char.
+
+public class CalculatorLexer {
+
+ private String src; // source string for lexical analysis
+ private int idx; // current index in source
+ private int len; // length of source
+
+ public CalculatorLexer() { }
+
+ public void initLexer(String source) {
+ this.src = source;
+ idx = 0;
+ len = src.length();
+ }
+
+ // Consumes letters only and builds an identifier
+ private String identifier() {
+ StringBuffer s = new StringBuffer();
+
+ do {
+ s.append(src.charAt(idx));
+ idx++;
+ } while (idx < len && Character.isLetter(src.charAt(idx)));
+ return s.toString();
+ }
+
+ // Consumes digits and convert integer part and decimal part
+ // Convert characters using the formula
+ // "3456.253" = [(((3+0)*10+4)*10+5)*10+6]+[0.1*2+0.01*5+0.001*3]
+ private double number() throws LexerException {
+ double v = 0; // accumulates the result
+ double factor = 0.1; // factor for decimal part
+
+ do { // integer part
+ v = v * 10 + Character.digit(src.charAt(idx),30);
+ idx++;
+ } while (idx < len && Character.isDigit(src.charAt(idx)));
+ if (idx < len && src.charAt(idx) == '.') { // decimal point
+ idx++;
+ if (idx < len && Character.isDigit(src.charAt(idx))) { // decimal part
+ while (idx < len && Character.isDigit(src.charAt(idx))) {
+ v = v + (factor * Character.digit(src.charAt(idx),30));
+ factor = factor * 0.1;
+ idx++;
+ }
+ }
+ else throw new LexerException("Illegal number: decimal part missing");
+ }
+ return v;
+ }
+
+ // Skips blanks, tabs, newlines
+ private void skip() {
+ char c;
+ while (idx < len) {
+ c = src.charAt(idx);
+ if (c==' ' || c=='\t' || c=='\n') idx++;
+ else break;
+ }
+ }
+
+ // returns next token
+ public Token nextToken() throws LexerException {
+ Token tok = new Token();
+
+ skip();
+ if (idx>=len) {
+ tok.str="EOL";
+ tok.type=Token.EOL;
+ }
+ else
+ // is it a positive number?
+ if (Character.isDigit(src.charAt(idx))) {
+ tok.value = number();
+ tok.type = Token.NUM;
+ tok.str = Double.toString(tok.value);
+ }
+ else
+ if (Character.isLetter(src.charAt(idx))) {
+ tok.value = 0;
+ tok.type = Token.ID;
+ tok.str = identifier();
+ if (tok.str.compareTo("let")==0) tok.type = Token.LET;
+ if (tok.str.compareTo("exit")==0) tok.type = Token.END;
+ }
+ else {
+ switch (src.charAt(idx)) {
+ case '+': tok.type = Token.ADD; tok.str = "+"; break;
+ case '-': tok.type = Token.SUB; tok.str = "-"; break;
+ case '*': tok.type = Token.MUL; tok.str = "*"; break;
+ case '/': tok.type = Token.DIV; tok.str = "/"; break;
+ case '(': tok.type = Token.PAL; tok.str = "("; break;
+ case ')': tok.type = Token.PAR; tok.str = ")"; break;
+ case '=': tok.type = Token.EQU; tok.str = "="; break;
+ default : throw new LexerException("Illegal Token: '" + src.charAt(idx) + "'");
+ }
+ idx++;
+ }
+ return tok;
+ }
+} \ No newline at end of file