如何修改仅支持单数字的递归Java计算器以适配多数字输入?
Hey there! Let's get your calculator handling multi-digit numbers like 12+34 or (100-25)*4—this is a straightforward adjustment to your existing recursive descent parser. Here's the breakdown of what's needed and the updated code:
The Root Problem
Your current factor() method only reads one single digit before returning. To support numbers with multiple digits, we need to keep reading consecutive digit characters and build the full numeric value instead of stopping at the first one.
The Fix: Update the factor() Method
Replace your existing factor() with this version, which loops through consecutive digits to construct multi-digit numbers:
private int factor() throws ParseError, IOException { if (lookAheadToken == '(') { consume(lookAheadToken); int result = expr(); if (lookAheadToken == ')') { consume(lookAheadToken); return result; } else throw new ParseError(); } if (lookAheadToken < '0' || lookAheadToken > '9') throw new ParseError(); // Build multi-digit number here int result = 0; while (lookAheadToken >= '0' && lookAheadToken <= '9') { result = result * 10 + evalDigit(lookAheadToken); consume(lookAheadToken); } return result; }
How This Works
- We start with
result = 0for the number we're building. - For each digit we encounter:
- Multiply the current result by 10 (shifting it left, e.g., 1 becomes 10 when we're about to add 2 to make 12).
- Add the value of the new digit (using your existing
evalDigit()method). - Consume the digit and check if the next token is also a digit—if yes, repeat the loop.
- Once we hit a non-digit token (operator, parenthesis, newline, etc.), we return the full multi-digit number.
Full Updated Code
Here's the complete calculator class with multi-digit support added (note: I also added a simple ParseError class since it wasn't included in your original code):
import java.io.IOException; import java.io.InputStream; public class Calculator { private int lookAheadToken; private InputStream inputStream; public Calculator(InputStream inputStream) throws IOException, ParseError { this.inputStream = inputStream; lookAheadToken = inputStream.read(); } private void consume(int symbol) throws IOException, ParseError { if (lookAheadToken != symbol) throw new ParseError(); lookAheadToken = inputStream.read(); } private int evalDigit(int digit) { return digit - '0'; } private void goal() throws ParseError, IOException { int result = expr(); if (lookAheadToken == '\n') { System.out.println("result = " + result); } consume(lookAheadToken); if (lookAheadToken == -1) return; goal(); } private int expr() throws ParseError, IOException { int result = term(); return rest_expr(result); } private int rest_expr(int factor) throws ParseError, IOException { if (lookAheadToken == '\n' || lookAheadToken == ')' || lookAheadToken == -1) return factor; if (lookAheadToken != '+' && lookAheadToken != '-') throw new ParseError(); char operator = (char) lookAheadToken; consume(lookAheadToken); int result = term(); if (operator == '+') { return rest_expr(factor + result); } else if (operator == '-') { return rest_expr(factor - result); } else return factor; } private int term() throws ParseError, IOException { int result = factor(); return rest_term(result); } private int rest_term(int factor) throws ParseError, IOException { if (lookAheadToken == '\n' || lookAheadToken == ')' || lookAheadToken == -1) return factor; if (lookAheadToken == '+' || lookAheadToken == '-') return factor; if (lookAheadToken != '*' && lookAheadToken != '/') throw new ParseError(); char operator = (char) lookAheadToken; consume(lookAheadToken); int result = factor(); if (operator == '*') { return rest_term(factor * result); } else if (operator == '/') { return rest_term(factor / result); } return factor; } private int factor() throws ParseError, IOException { if (lookAheadToken == '(') { consume(lookAheadToken); int result = expr(); if (lookAheadToken == ')') { consume(lookAheadToken); return result; } else throw new ParseError(); } if (lookAheadToken < '0' || lookAheadToken > '9') throw new ParseError(); // Updated to build multi-digit numbers int result = 0; while (lookAheadToken >= '0' && lookAheadToken <= '9') { result = result * 10 + evalDigit(lookAheadToken); consume(lookAheadToken); } return result; } public static void main(String[] args) throws IOException, ParseError { InputStream inputStream = System.in; Calculator calculator = new Calculator(inputStream); calculator.goal(); } // Custom exception for parsing errors static class ParseError extends Exception {} }
Testing It Out
Try inputs like:
12+34→ Should outputresult = 46(100-25)*4→ Should outputresult = 300789/3→ Should outputresult = 263
This change maintains all your existing recursive logic for operator precedence and parentheses—we just extended the number-parsing part to handle multiple digits.
内容的提问来源于stack exchange,提问作者vasilis_dim

