La tabella LL(1) viene utilizzata dal parser per scegliere l'azione da intraprendere(la produzione della grammatica da applicare) in base al token corrente nella stringa di input(il cosiddetto token di lookahead).
In sostanza si tratta di un array bidimensionale che contiene i simboli non terminali nelle righe e i simboli terminali nelle colonne. Gli elementi dell'array sono le regole grammaticali da applicare.
Il cuore dell'algoritmo suesposto è nella seguente riga:
codice:
action = LL1_Table[top, currentToken];
Se in cima allo stack(top) abbiamo un non terminale, applichiamo la regola grammaticale corrispondente al token di lookahead(currentToken). Se in corrispondenza a top, currentToken non c'è nessuna regola grammaticale, riportiamo un errore di sintassi.
La prima cosa da fare è, dunque, scrivere un analizzatore lessicale(lexer o tokenizer) che legga la stringa in input e la suddivida in token. Per esempio così:
CLexer.java:
codice:
import java.lang.String;
import java.lang.StringBuilder;
public class CLexer
{
static public enum TokenTypeEnum
{
T_TERMINAL(0),
T_NONTERMINAL(1),
T_SPACE(2),
T_NEWLINE(3),
T_ARROW(4),
T_EOL(5),
T_UNKNOWN(6);
private final int value;
private TokenTypeEnum(int value)
{
this.value = value;
}
public int getValue()
{
return value;
}
}
static public class Token
{
TokenTypeEnum Type;
String str;
int row;
}
public CLexer()
{
m_nNextPos = 0;
m_currToken = new Token();
m_currToken.row = 1;
}
public void setExpr(String str)
{
m_strExpr = new String(str);
}
public TokenTypeEnum getNextToken()
{
StringBuilder strToken = new StringBuilder();
StringBuilder str = new StringBuilder();
str.append(m_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;
return TokenTypeEnum.T_EOL;
}
while ( true )
{
if ( m_nNextPos >= str.length() )
{
m_currToken = new Token();
m_currToken.Type = TokenTypeEnum.T_EOL;
m_currToken.str = new String("EOL");
m_nNextPos = 0;
return TokenTypeEnum.T_EOL;
}
else if ( isAlpha(str.charAt(m_nNextPos)) )
{
while ( m_nNextPos < str.length() && isAlpha(str.charAt(m_nNextPos)) )
{
strToken.append(str.charAt(m_nNextPos));
m_nNextPos++;
}
if ( strToken.length() == 2 )
{
if ( isUpper(strToken.charAt(0)) && isUpper(strToken.charAt(1)) )
m_currToken.Type = TokenTypeEnum.T_NONTERMINAL;
else
m_currToken.Type = TokenTypeEnum.T_TERMINAL;
}
else
{
m_currToken.Type = TokenTypeEnum.T_TERMINAL;
}
m_currToken.str = new String(strToken.toString());
return m_currToken.Type;
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '-' )
{
strToken.append(str.charAt(m_nNextPos));
m_nNextPos++;
if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '>' )
{
strToken.append(str.charAt(m_nNextPos));
m_currToken.Type = TokenTypeEnum.T_ARROW;
m_currToken.str = new String(strToken);
++m_nNextPos;
return m_currToken.Type;
}
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == ' ' )
{
m_currToken.Type = TokenTypeEnum.T_SPACE;
m_currToken.str = new String("b");
++m_nNextPos;
return m_currToken.Type;
}
else if ( m_nNextPos < str.length() && str.charAt(m_nNextPos) == '\n' )
{
m_currToken.Type = TokenTypeEnum.T_NEWLINE;
m_currToken.str = new String("n");
++m_nNextPos;
m_currToken.row++;
return m_currToken.Type;
}
else
{
m_currToken.Type = TokenTypeEnum.T_UNKNOWN;
m_currToken.str = new String(str);
++m_nNextPos;
return m_currToken.Type;
}
}
}
private boolean isAlpha(char c)
{
return ( (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') );
}
private boolean isUpper(char c)
{
return ( c >= 'A' && c <= 'Z' );
}
public Token m_currToken;
private String m_strExpr;
private int m_nNextPos;
}
ProvaLexer.java:
codice:
import java.io.*;
import java.io.Console;
// javac ProvaLexer.java CLexer.java
// java ProvaLexer
public class ProvaLexer
{
public static String readFile(String strFileName)
{
StringBuffer buffer = new StringBuffer();
File name = new File(strFileName);
if ( name.isFile() )
{
try
{
BufferedReader input = new BufferedReader(new FileReader(name));
String text;
while ( (text = input.readLine()) != null )
buffer.append(text + "\n");
input.close();
}
catch (IOException ioException)
{
return null;
}
}
return buffer.toString();
}
public static void main(String[] args)
{
if ( args.length < 2 )
{
System.out.println("Uso: java ProvaLexer file1 file2");
return;
}
String strFileName1 = args[0];
String strFileName2 = args[1];
CParser parser = new CParser();
System.out.println();
String strFile1 = readFile(strFileName1);
if ( strFile1 == null )
{
System.out.print("Errore nella lettura del file ");
System.out.println(strFileName1);
return;
}
String strFile2 = readFile(strFileName2);
if ( strFile2 == null )
{
System.out.print("Errore nella lettura del file ");
System.out.println(strFileName1);
return;
}
CLexer lex = new CLexer();
System.out.println();
System.out.println();
System.out.println("Lista Token:");
lex.setExpr(strFile1);
lex.getNextToken();
while ( lex.m_currToken.Type != CLexer.TokenTypeEnum.T_EOL)
{
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_TERMINAL )
System.out.println("TERMINAL");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_NONTERMINAL )
System.out.println("NON-TERMINAL");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_SPACE )
System.out.println("SPACE");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_NEWLINE )
System.out.println("NEWLINE");
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_ARROW )
System.out.println("ARROW");
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("'");
System.out.println();
lex.getNextToken();
if ( lex.m_currToken.Type == CLexer.TokenTypeEnum.T_EOL )
System.out.println("EOL");
System.out.println();
}
}
}