Ho tradotto il codice in C++ che avevo postato nell'altra sezione. Ecco il parser a discesa ricorsiva in Java:
file CLexer.java:
codice:
import java.lang.String;
import java.lang.StringBuilder;
public class CLexer
{
static public enum TokenTypeEnum
{
T_EOL,
T_UNKNOWN,
T_NUMBER,
T_OPAREN,
T_CPAREN,
T_UMINUS,
T_MULT,
T_DIV,
T_PLUS,
T_MINUS
}
static public class Token
{
TokenTypeEnum Type;
String str;
double Value;
}
public CLexer()
{
m_nNextPos = 0;
m_PreviousTokenType = TokenTypeEnum.T_EOL;
m_currToken = new Token();
}
public void SetExpr(String str)
{
m_strExpr = new String(str);
}
public TokenTypeEnum GetNextToken(String strExpr)
{
StringBuilder strToken = new StringBuilder();
StringBuilder str = new StringBuilder();
str.append(strExpr);
if ( m_nNextPos >= str.length() )
{
m_currToken = new Token();
m_currToken.Type = TokenTypeEnum.T_EOL;
m_currToken.str = new String("EOL");
m_nNextPos = 0;
m_PreviousTokenType = TokenTypeEnum.T_EOL;
return TokenTypeEnum.T_EOL;
}
while ( true )
{
while ( m_nNextPos < str.length() && str.charAt(m_nNextPos++) == ' ' )
;
--m_nNextPos;
if ( m_nNextPos >= str.length() )
{
m_currToken = new Token();
m_currToken.Type = TokenTypeEnum.T_EOL;
m_currToken.str = new String("EOL");
m_nNextPos = 0;
m_PreviousTokenType = TokenTypeEnum.T_EOL;
return TokenTypeEnum.T_EOL;
}
else if ( isdigit(str.charAt(m_nNextPos)) )
{
while ( m_nNextPos < str.length() && isdigit(str.charAt(m_nNextPos)) )
{
strToken.append(str.charAt(m_nNextPos));
m_nNextPos++;
}
if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '.' )
{
str.setCharAt(m_nNextPos, '.');
m_nNextPos++;
while ( m_nNextPos < str.length() && isdigit(str.charAt(m_nNextPos)) )
{
strToken.append(str.charAt(m_nNextPos));
m_nNextPos++;
}
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_NUMBER;
m_currToken.str = new String(strToken.toString());
m_currToken.Value = Double.valueOf(m_currToken.str).doubleValue();
return TokenTypeEnum.T_NUMBER;
}
else
{
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_NUMBER;
m_currToken.str = new String(strToken.toString());
m_currToken.Value = Double.valueOf(m_currToken.str).doubleValue();
return TokenTypeEnum.T_NUMBER;
}
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '.' )
{
str.setCharAt(m_nNextPos, '.');
m_nNextPos++;
while ( m_nNextPos < str.length() && isdigit(str.charAt(m_nNextPos)) )
{
strToken.append(str.charAt(m_nNextPos));
m_nNextPos++;
}
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_NUMBER;
m_currToken.str = new String(strToken);
m_currToken.Value = Double.valueOf(m_currToken.str).doubleValue();
return TokenTypeEnum.T_NUMBER;
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '(' )
{
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_OPAREN;
m_currToken.str = new String("(");
++m_nNextPos;
return TokenTypeEnum.T_OPAREN;
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == ')' )
{
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_CPAREN;
m_currToken.str = new String(")");
++m_nNextPos;
return TokenTypeEnum.T_CPAREN;
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '+' )
{
m_PreviousTokenType = m_currToken.Type;
m_currToken.str = new String("+");
++m_nNextPos;
m_currToken.Type = TokenTypeEnum.T_PLUS;
return TokenTypeEnum.T_PLUS;
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '-' )
{
m_currToken.str = new String("-");
++m_nNextPos;
m_PreviousTokenType = m_currToken.Type;
if ( m_PreviousTokenType == TokenTypeEnum.T_CPAREN ||
m_PreviousTokenType == TokenTypeEnum.T_NUMBER )
{
m_currToken.Type = TokenTypeEnum.T_MINUS;
return TokenTypeEnum.T_MINUS;
}
else
{
m_currToken.Type = TokenTypeEnum.T_UMINUS;
return TokenTypeEnum.T_UMINUS;
}
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '*' )
{
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_MULT;
m_currToken.str = new String("*");
++m_nNextPos;
return TokenTypeEnum.T_MULT;
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '/' )
{
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_DIV;
m_currToken.str = new String("/");
++m_nNextPos;
return TokenTypeEnum.T_DIV;
}
else
{
m_PreviousTokenType = m_currToken.Type;
m_currToken.Type = TokenTypeEnum.T_UNKNOWN;
m_currToken.str = new String(str);
++m_nNextPos;
return TokenTypeEnum.T_UNKNOWN;
}
}
}
private boolean isdigit(char c)
{
return (c >= '0' && c <= '9');
}
public Token m_currToken;
private String m_strExpr;
private int m_nNextPos;
private TokenTypeEnum m_PreviousTokenType;
}
file CParser.java:
codice:
import java.lang.String;
import java.lang.StringBuilder;
/*
expr : expr1 {('+' | '-') expr1};
expr1 : expr2 {('*' | '/') expr2};
expr2 : ['-'] expr3;
expr3 : T_NUMBER | '(' expr ')'
*/
public class CParser
{
public CParser()
{
m_Lexer = new CLexer();
m_top = -1;
m_value = 0;
m_stack = new double[255];
}
public boolean Parse(String strExpr)
{
boolean ret = true;
m_strExpr = new String(strExpr);
m_top = -1;
m_value = 0;
m_Lexer.SetExpr(strExpr);
m_Lexer.GetNextToken(m_strExpr);
m_Token = m_Lexer.m_currToken;
while ( ret && m_Token.Type != CLexer.TokenTypeEnum.T_EOL )
{
ret = expr();
}
if ( m_top >= 0 )
m_value = m_stack[m_top--];
m_top = -1;
return ret;
}
public double GetValue()
{
return m_value;
}
//expr : expr1 {('+' | '-') expr1};
private boolean expr()
{
double right, left;
CLexer.TokenTypeEnum currToken;
if ( !expr1() )
return false;
while ( m_Token.Type == CLexer.TokenTypeEnum.T_PLUS || m_Token.Type == CLexer.TokenTypeEnum.T_MINUS )
{
currToken = m_Token.Type;
m_Lexer.GetNextToken(m_strExpr);
m_Token = m_Lexer.m_currToken;
if ( !expr1() )
return false;
right = m_stack[m_top--];
left = m_stack[m_top--];
if ( currToken == CLexer.TokenTypeEnum.T_PLUS )
m_stack[++m_top] = left + right;
else if ( currToken == CLexer.TokenTypeEnum.T_MINUS )
m_stack[++m_top] = left - right;
}
return true;
}
//expr1 : expr2 {('*' | '/') expr2};
private boolean expr1()
{
double right, left;
CLexer.TokenTypeEnum currToken;
if ( !expr2() )
return false;
while ( m_Token.Type == CLexer.TokenTypeEnum.T_MULT || m_Token.Type == CLexer.TokenTypeEnum.T_DIV )
{
currToken = m_Token.Type;
m_Lexer.GetNextToken(m_strExpr);
m_Token = m_Lexer.m_currToken;
if ( !expr2() )
return false;
right = m_stack[m_top--];
left = m_stack[m_top--];
if ( currToken == CLexer.TokenTypeEnum.T_MULT )
m_stack[++m_top] = left * right;
else if ( currToken == CLexer.TokenTypeEnum.T_DIV )
{
if ( right == 0 )
{
System.out.println("Errore: divisione per zero.");
return false;
}
m_stack[++m_top] = left / right;
}
}
return true;
}
//expr2 : ['-'] expr3;
private boolean expr2()
{
CLexer.TokenTypeEnum currToken;
double dblValue;
currToken = CLexer.TokenTypeEnum.T_EOL;
if ( m_Token.Type == CLexer.TokenTypeEnum.T_UMINUS )
{
currToken = m_Token.Type;
m_Lexer.GetNextToken(m_strExpr);
m_Token = m_Lexer.m_currToken;
}
if ( !expr3() )
return false;
if ( currToken == CLexer.TokenTypeEnum.T_UMINUS )
{
dblValue = m_stack[m_top--];
dblValue *= -1;
m_stack[++m_top] = dblValue;
}
return true;
}
//expr3 : T_NUMBER
// | '(' expr ')'
private boolean expr3()
{
switch( m_Token.Type )
{
case T_NUMBER:
m_stack[++m_top] = m_Token.Value;
m_Lexer.GetNextToken(m_strExpr);
m_Token = m_Lexer.m_currToken;
break;
case T_OPAREN:
m_Lexer.GetNextToken(m_strExpr);
m_Token = m_Lexer.m_currToken;
if ( !expr() )
return false;
if ( !match(CLexer.TokenTypeEnum.T_CPAREN) )
{
System.out.println("Errore: parentesi non bilanciate.");
return false;
}
break;
default:
System.out.println("Errore: atteso numero, meno unario o parentesi aperta.");
System.out.print("Trovato invece ");
System.out.println(m_Token.str);
return false;
}
return true;
}
private boolean match(CLexer.TokenTypeEnum ExpectedToken)
{
if ( m_Token.Type == ExpectedToken )
{
m_Lexer.GetNextToken(m_strExpr);
m_Token = m_Lexer.m_currToken;
return true;
}
return false;
}
private CLexer m_Lexer;
private CLexer.Token m_Token;
private String m_strExpr;
private int m_top;
private double[] m_stack;
private double m_value;
}
file ExprJava.java:
codice:
import java.io.Console;
//import java.util.Arrays;
//import java.io.IOException;
// C:\Programmi\Java\jdk1.6.0_14\bin\javac CLexer.java CParser.java ExprJava.java
// C:\Programmi\Java\jdk1.6.0_14\bin\java ExprJava
public class ExprJava
{
public static void main(String[] args) /* throws IOException */
{
String str;
CParser parser = new CParser();
Console c = System.console();
System.out.println();
while( true )
{
String strExpr = c.readLine("Inserisci un'espressione aritmetica: ");
System.out.println();
if ( strExpr.length() == 0 )
break;
System.out.println();
if ( parser.Parse(strExpr) )
{
System.out.print("Il risultato e': ");
System.out.println(parser.GetValue());
System.out.println();
}
}
/*
CLexer lex = new CLexer();
Console c = System.console();
while( true )
{
System.out.println();
String strExpr = c.readLine("Inserisci un'espressione aritmetica: ");
if ( strExpr.length() == 0 )
break;
System.out.println();
System.out.println("Lista Token:");
lex.GetNextToken(strExpr);
int x = 0;
while ( lex.m_currToken.Type != CLexer.TokenTypeEnum.T_EOL)
{
System.out.println();
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_PLUS )
System.out.println("PLUS");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_MINUS )
System.out.println("MINUS");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_MULT )
System.out.println("MULT");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_DIV )
System.out.println("DIV");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_UMINUS )
System.out.println("UMINUS");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_CPAREN )
System.out.println("CPAREN");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_OPAREN )
System.out.println("OPAREN");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_NUMBER )
System.out.println("NUMBER");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_UNKNOWN )
System.out.println("UNKNOWN");
System.out.print("Token: <");
System.out.print(lex.m_currToken.str);
System.out.print(">");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_NUMBER )
{
System.out.print(" Value: ");
System.out.print(lex.m_currToken.Value);
}
System.out.println();
lex.GetNextToken(strExpr);
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_EOL )
System.out.println("EOL");
System.out.println();
x++;
if ( x >= 21 )
break;
}
System.out.println();
}
*/
}
}