codigo de un compilador de java donde contega analisis lexico,sintactico y semantico completo
Aquí te proporciono un ejemplo básico de un compilador de Java que incluye análisis léxico, sintáctico y semántico. Este ejemplo utiliza la técnica de compilación por interpretación (compilación just-in-time) y utiliza la clase `java.util.Scanner` para leer el código fuente. **Nota:** Este es un ejemplo básico y no es un compilador completo. La implementación de un compilador real es mucho más compleja y requiere una gran cantidad de código y pruebas. **Análisis Léxico** El análisis léxico se encarga de dividir el código fuente en tokens, que son las unidades básicas de un lenguaje de programación. En este ejemplo, utilizamos una clase `Lexer` que utiliza una clase `Token` para representar cada token. ```java // Token.java public class Token { public enum Tipo { IDENTIFICADOR, NUMERO, PALABRA_RESERVADA, OPERADOR, PUNTO_Y_COMA, PARENTESIS_ABRE, PARENTESIS_CIERRA, LLAVE_ABRE, LLAVE_CIERRA, CORCHETE_ABRE, CORCHETE_CIERRA, COMA, IGUAL, MENOR_QUE, MAYOR_QUE, MENOR_QUE_IGUAL, MAYOR_QUE_IGUAL, DIFERENTE, SUMA, RESTA, PRODUCTO, DIVISION, MODULO } public Tipo tipo; public String valor; public Token(Tipo tipo, String valor) { this.tipo = tipo; this.valor = valor; } } ``` ```java // Lexer.java import java.util.Scanner; public class Lexer { private Scanner scanner; private Token tokenActual; public Lexer(String codigoFuente) { scanner = new Scanner(codigoFuente); tokenActual = null; } public Token siguienteToken() { if (tokenActual == null) { tokenActual = leerToken(); } return tokenActual; } private Token leerToken() { String lexema = scanner.next(); if (esPalabraReservada(lexema)) { return new Token(Token.Tipo.PALABRA_RESERVADA, lexema); } else if (esIdentificador(lexema)) { return new Token(Token.Tipo.IDENTIFICADOR, lexema); } else if (esNumero(lexema)) { return new Token(Token.Tipo.NUMERO, lexema); } else if (esOperador(lexema)) { return new Token(Token.Tipo.OPERADOR, lexema); } else if (esPuntoYComa(lexema)) { return new Token(Token.Tipo.PUNTO_Y_COMA, lexema); } else if (esParentesisAbre(lexema)) { return new Token(Token.Tipo.PARENTESIS_ABRE, lexema); } else if (esParentesisCierra(lexema)) { return new Token(Token.Tipo.PARENTESIS_CIERRA, lexema); } else if (esLlaveAbre(lexema)) { return new Token(Token.Tipo.LLAVE_ABRE, lexema); } else if (esLlaveCierra(lexema)) { return new Token(Token.Tipo.LLAVE_CIERRA, lexema); } else if (esCorcheteAbre(lexema)) { return new Token(Token.Tipo.CORCHETE_ABRE, lexema); } else if (esCorcheteCierra(lexema)) { return new Token(Token.Tipo.CORCHETE_CIERRA, lexema); } else if (esComa(lexema)) { return new Token(Token.Tipo.COMA, lexema); } else if (esIgual(lexema)) { return new Token(Token.Tipo.IGUAL, lexema); } else if (esMenorQue(lexema)) { return new Token(Token.Tipo.MENOR_QUE, lexema); } else if (esMayorQue(lexema)) { return new Token(Token.Tipo.MAYOR_QUE, lexema); } else if (esMenorQueIgual(lexema)) { return new Token(Token.Tipo.MENOR_QUE_IGUAL, lexema); } else if (esMayorQueIgual(lexema)) { return new Token(Token.Tipo.MAYOR_QUE_IGUAL, lexema); } else if (esDiferente(lexema)) { return new Token(Token.Tipo.DIFERENTE, lexema); } else if (esSuma(lexema)) { return new Token(Token.Tipo.SUMA, lexema); } else if (esResta(lexema)) { return new Token(Token.Tipo.RESTA, lexema); } else if (esProducto(lexema)) { return new Token(Token.Tipo.PRODUCTO, lexema); } else if (esDivision(lexema)) { return new Token(Token.Tipo.DIVISION, lexema); } else if (esModulo(lexema)) { return new Token(Token.Tipo.MODULO, lexema); } else { throw new RuntimeException("Token no reconocido: " + lexema); } } private boolean esPalabraReservada(String lexema) { return lexema.equals("public") || lexema.equals("private") || lexema.equals("protected"); } private boolean esIdentificador(String lexema) { return lexema.matches("[a-zA-Z_][a-zA-Z_0-9]*"); } private boolean esNumero(String lexema) { return lexema.matches("\\d+"); } private boolean esOperador(String lexema) { return lexema.equals("+") || lexema.equals("-") || lexema.equals("*") || lexema.equals("/") || lexema.equals("%"); } private boolean esPuntoYComa(String lexema) { return lexema.equals(";"); } private boolean esParentesisAbre(String lexema) { return lexema.equals("("); } private boolean esParentesisCierra(String lexema) { return lexema.equals(")"); } private boolean esLlaveAbre(String lexema) { return lexema.equals("{"); } private boolean esLlaveCierra(String lexema) { return lexema.equals("}"); } private boolean esCorcheteAbre(String lexema) { return lexema.equals("["); } private boolean esCorcheteCierra(String lexema) { return lexema.equals("]"); } private boolean esComa(String lexema) { return lexema.equals(","); } private boolean esIgual(String lexema) { return lexema.equals("="); } private boolean esMenorQue(String lexema) { return lexema.equals("<"); } private boolean esMayorQue(String lexema) { return lexema.equals(">"); } private boolean esMenorQueIgual(String lexema) { return lexema.equals("<="); } private boolean esMayorQueIgual(String lexema) { return lexema.equals(">="); } private boolean esDiferente(String lexema) { return lexema.equals("!="); } private boolean esSuma(String lexema) { return lexema.equals("+"); } private boolean esResta(String lexema) { return lexema.equals("-"); } private boolean esProducto(String lexema) { return lexema.equals("*"); } private boolean esDivision(String lexema) { return lexema.equals("/"); } private boolean esModulo(String lexema) { return lexema.equals("%"); } } ``` **Análisis Sintáctico** El análisis sintáctico se encarga de verificar la estructura del código fuente y asegurarse de que se cumplan las reglas del lenguaje. En este ejemplo, utilizamos una clase `Parser` que utiliza una clase `AST` para representar el árbol abstracto de sintaxis. ```java // AST.java public class AST { public enum Tipo { PROGRAMA, DECLARACION, EXPRESION, SENTENCIA, LISTA_SENTENCIAS } public Tipo tipo; public Object valor; public AST(Tipo tipo, Object valor) { this.tipo = tipo; this.valor = valor; } } ``` ```java // Parser.java import java.util.ArrayList; import java.util.List; public class Parser { private Lexer lexer; private Token tokenActual; public Parser(Lexer lexer) { this.lexer = lexer; tokenActual = lexer.siguienteToken(); } public AST parsear() { return parsearPrograma(); } private AST parsearPrograma() { List<AST> declaraciones = new ArrayList<>(); while (tokenActual.tipo != Token.Tipo.PUNTO_Y_COMA) { declaraciones.add(parsearDeclaracion()); } return new AST(AST.Tipo.PROGRAMA, declaraciones); } private AST parsearDeclaracion() { if (tokenActual.tipo == Token.Tipo.IDENTIFICADOR) { String identificador = tokenActual.valor; tokenActual = lexer.siguienteToken(); if (tokenActual.tipo == Token.Tipo.IGUAL) { tokenActual = lexer.siguienteToken(); return new AST(AST.Tipo.DECLARACION, identificador); } else { return new AST(AST.Tipo.DECLARACION, identificador); } } else { throw new RuntimeException("Declaración no reconocida"); } } private AST parsearExpresion() { AST expresion = parsearTerm(); while (tokenActual.tipo == Token.Tipo.SUMA || tokenActual.tipo == Token.Tipo.RESTA) { Token operador = tokenActual; tokenActual = lexer.siguienteToken(); AST term = parsearTerm(); expresion = new AST(AST.Tipo.EXPRESION, new Object[]{expresion, operador.valor, term}); } return expresion; } private AST parsearTerm() { AST term = parsearFactor(); while (tokenActual.tipo == Token.Tipo.PRODUCTO || tokenActual.tipo == Token.Tipo.DIVISION) { Token operador = tokenActual; tokenActual = lexer.siguienteToken(); AST factor = parsearFactor(); term = new AST(AST.Tipo.EXPRESION, new Object[]{term, operador.valor, factor}); } return term; } private AST parsearFactor() { if (tokenActual.tipo == Token.Tipo.IDENTIFICADOR) { return new AST(AST.Tipo.EXPRESION, tokenActual.valor); } else if (tokenActual.tipo == Token.Tipo.NUMERO) { return new AST(AST.Tipo.EXPRESION, tokenActual.valor); } else if (tokenActual.tipo == Token.Tipo.PARENTESIS_ABRE) { tokenActual = lexer.siguienteToken(); AST expresion = parsearExpresion(); if (tokenActual.tipo == Token.Tipo.PARENTESIS_CIERRA) { tokenActual = lexer.siguienteToken(); return expresion; } else { throw new RuntimeException("Parentesis no cerrado"); } } else { throw new RuntimeException("Factor no reconocido"); } } } ``` **Análisis Semántico** El análisis semántico se encarga de verificar la semántica del código fuente y asegurarse de que se cumplan las reglas del lenguaje. En este ejemplo, utilizamos una clase `SemanticAnalyzer` que utiliza una clase `SymbolTable` para representar la tabla de símbolos. ```java // SymbolTable.java import java.util.HashMap; import java.util.Map; public class SymbolTable { private Map<String, Object> tabla; public SymbolTable() { tabla = new HashMap<>(); } public void agregar(String identificador, Object valor) { tabla.put(identificador, valor); } public Object obtener(String identificador) { return tabla.get(identificador); } } ``` ```java // SemanticAnalyzer.java import java.util.ArrayList; import java.util.List; public class SemanticAnalyzer { private Parser parser; private SymbolTable tablaSimbolos; public SemanticAnalyzer(Parser parser) { this.parser = parser; tablaSimbolos = new SymbolTable(); } public void analizar() { AST programa = parser.parsear(); analizarPrograma(programa); } private void analizarPrograma(AST programa) { List<AST> declaraciones = (List<AST>) programa.valor; for (AST declaracion : declaraciones) { analizarDeclaracion(declaracion); } } private void analizarDeclaracion(AST declaracion) { if (declaracion.tipo == AST.Tipo.DECLARACION) { String identificador = (String) declaracion.valor; if (tablaSimbolos.obtener(identificador) != null) { throw new RuntimeException("Identificador ya declarado"); } tablaSimbolos.agregar(identificador, null); } } } ``` **Compilador** El compilador es la clase principal que utiliza las clases anteriores para analizar el código fuente y generar el código máquina. ```java // Compilador.java public class Compilador { private Lexer lexer; private Parser parser; private SemanticAnalyzer semanticAnalyzer; public Compilador(String codigoFuente) { lexer = new Lexer(codigoFuente); parser = new Parser(lexer); semanticAnalyzer = new SemanticAnalyzer(parser); } public void compilar() { semanticAnalyzer.analizar(); } } ``` **Ejemplo de uso** ```java public class Main { public