Benutzer-Werkzeuge

Webseiten-Werkzeuge


compilerbau:lexer:test:start

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
compilerbau:lexer:test:start [2021/10/28 20:35] Martin Pabstcompilerbau:lexer:test:start [2022/05/19 08:11] (aktuell) Martin Pabst
Zeile 4: Zeile 4:
 Die [[..:start|Beschreibung des Lexers findest Du hier.]] Die [[..:start|Beschreibung des Lexers findest Du hier.]]
 </WRAP> </WRAP>
 +
 +
 +<HTML>
 +<div class="java-online" style="height: 60vh; width: 100%" data-java-online="{'withBottomPanel': true, 'id': 'Lexertest', 'speed': 'max'}">
 +
 +<script type="text/plain" title="Testprogramm.java">
 +Lexer lexer = new Lexer("1 + 2 * (4 * a - 3 * b)");
 +
 +lexer.lex();
 +
 +println(lexer);
 +</script>
 +
 +<script type="text/plain" title="Lexer.java">
 +public class Lexer {
 + 
 + /**
 + * Die Zeichenkette wird von links nach rechts abgearbeitet. Hier ist
 + * gespeichert, das wievielte Zeichen gerade angesehen wird:
 + */
 +  private int position;
 + 
 + /**
 + * Liste zur Speicherung der ermittelten Tokens
 + */
 +  private ArrayList<Token> tokenListe;
 + 
 + /**
 + * Wir speichern den Programmtext in einem Attribut der Klasse, damit er
 + * nachher nicht von Methode zu Methode weitergereicht werden muss.
 + */
 +  private String text;
 + 
 + /**
 +
 + * @param text
 + *            Programmtext, der in Tokens zerlegt werden soll
 + */
 +  public Lexer(String text) {
 + 
 +    this.text = text;
 + 
 +    position = 0; // Wir beginnen mit dem Zeichen ganz links
 + 
 +    tokenListe = new ArrayList<Token>(); // Liste zur Aufnahme der gelesenen Tokens instanzieren
 + 
 +  }
 +
 + /**
 + * Zerlegt den Programmtext, der dem Konstruktor übergeben wurde
 +
 + * @return Liste mit Tokens
 + * @throws Exception
 + *             Eine Exception wird ausgelöst, wenn der Programmtext Passagen
 + *             enthält, aus denen keine Token gebildet werden können.
 + */
 +  public ArrayList<Token> lex() {
 + 
 + /**
 + * Wiederholung, die den Programmtext von links nach rechts abarbeitet:
 + */
 +    while(position < text.length()) {
 + 
 + /**
 + * peek() liest das nächste Zeichen im Programmtext, erhöht die
 + * Variable position aber nicht. Ruft man peek() mehrmals
 + * hintereinander auf, liefert es also immer dasselbe Zeichen.
 + */
 +      char c = peek();
 + 
 +      if(istZiffer(c)) {
 +        lexZahl();
 +      } else if(istBuchstabe(c)) {
 +        lexText();
 +      } else {
 +        switch(c) {
 +            case '+'
 +              addToken(TokenType.plus);
 +              break;
 +            case '-'
 +              addToken(TokenType.minus);
 +              break;
 +            case '*'
 +              addToken(TokenType.mal);
 +              break;
 +            case '/'
 +              addToken(TokenType.geteilt);
 +              break;
 +            case '('
 +              addToken(TokenType.klammerAuf);
 +              break;
 +            case ')'
 +              addToken(TokenType.klammerZu);
 +              break;
 +            case ' ' : 
 +            case '\n'
 +            case '\r'
 + // Leerzeichen werden einfach überlesen
 +              break;
 +            default : 
 +              println("Fehler: Der Lexer kann mit dem Zeichen '" + c
 +                  + "' an Position " + position + " nichts anfangen.");
 +                  System.exit(0);
 +        }
 + 
 +        position++; // Das von peek() oben gelesene Zeichen ist
 + // verarbeitet, also jetzt das nächste holen.
 + 
 +      }
 + 
 +    }
 + 
 +    return tokenListe;
 + 
 +  }
 +
 +      /**
 +
 + * @param c
 + *            beliebiges zeichen
 + * @return true, falls c eine Ziffer ist
 + */
 +  private boolean istZiffer(char c) {
 +    return c >= '0' && c <= '9';
 +  }
 +
 + /**
 +
 + * @param c
 + *            beliebiges Zeichen
 + * @return true, falls c ein Buchstabe ist
 + */
 +  private boolean istBuchstabe(char c) {
 +    return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z';
 +  }
 +
 +
 +   /**
 + * Die Methode lexText geht davon aus, dass das nächste zu verarbeitende
 + * Zeichen ein Buchstabe ist. Solange weitere Buchstaben oder Ziffern
 + * kommen, liest sie sie und setzt sie zu einem Variablennamen zusammen.
 + */
 +  private void lexText() {
 + 
 +    String variablenBezeichner = "";
 + 
 +    do {
 +      char c = peek();
 +      variablenBezeichner += c;
 +      position++;
 +    } while(Character.isLetter(peek()) || Character.isDigit(peek()) || peek() == '_');
 + 
 +    tokenListe.add(new Token(variablenBezeichner));
 + 
 +  }
 + 
 + /**
 + * Die Methode lexZahl liest eine Zahl
 + */
 +  private void lexZahl() {
 + 
 +    String zahlAlsString = "";
 + 
 +    do {
 +      char c = peek();
 +      zahlAlsString += c;
 +      position++;
 +    } while(Character.isDigit(peek()) || peek() == '.');
 + 
 + /**
 + * Hier machen wir es uns leicht und lassen Java den String in eine Zahl
 + * konvertieren. Die Methode parseDouble ist für sich genommen natürlich
 + * auch ein Lexer.
 + */
 +    double zahl = Double.parseDouble(zahlAlsString);
 + 
 +    tokenListe.add(new Token(zahl));
 + 
 +  }
 +
 +   /**
 + * Fügt der tokenListe das übergebene Token hinzu
 +
 + * @param tokenType
 + */
 +  private void addToken(TokenType tokenType) {
 +    tokenListe.add(new Token(tokenType));
 + 
 +  }
 +   
 +   /**
 + * peek() liest das nächste Zeichen im Programmtext, erhöht die Variable
 + * position aber nicht. Ruft man peek() mehrmals hintereinander auf, liefert
 + * es also immer dasselbe Zeichen.
 +
 + * @return nächstes Zeichen im Programmtext
 + */
 +  private char peek() {
 +    if(position < text.length()) {
 +      return text.charAt(position);
 +    } else {
 +      return 0x;
 +    }
 +  }
 +   
 + /**
 + * Vorsicht: Die übergebene Liste ist nur dann gefüllt, wenn zuvor die
 + * Methode lex aufgerufen wurde.
 +
 + * @return Liste mit den Tokens, in die der Lexer den Programmtext zerlegt
 + *         hat.
 + */
 +  public ArrayList<Token> getTokenListe() {
 +    return tokenListe;
 +  }
 + 
 + /**
 + * Nur zu Debuggingzwecken
 + */
 +  public String toString() {
 + 
 +    String s = "";
 + 
 +    for(Token token : tokenListe) {
 +      s += token.toString() + " ";
 +    }
 + 
 +    if(!s.isEmpty()) {
 +      s = s.substring(0, s.length() - 1);
 +    }
 + 
 +    return s;
 + 
 +  }
 +
 +
 +}
 +</script>
 +<script type="text/plain" title="TokenType.java">
 +public enum TokenType {
 +  zahl, text, plus, minus, mal, geteilt, klammerAuf, klammerZu,
 + 
 + /**
 + * Nur als Knotentyp für Knoten des Syntaxbaums:
 + */
 +  negation
 +}
 +</script>
 +<script type="text/plain" title="Token.java">
 +public class Token {
 + 
 +  private TokenType tokenType; // Art des Tokens (z.B. zahl, klammerAuf usw.)
 +  private double zahl; // Wird nur belegt, wenn tokenType == zahl
 +  private String text; // Wird nur belegt, falls tokenType == bezeichner
 + 
 +  public Token(double zahl) {
 +    this.zahl = zahl;
 +    tokenType = TokenType.zahl;
 +  }
 + 
 +  public Token(String text) {
 +    this.text = text;
 +    tokenType = TokenType.text;
 +  }
 + 
 +  public Token(TokenType tokenType) {
 +    this.tokenType = tokenType;
 +  }
 + 
 +  public TokenType getTokenType() {
 +    return tokenType;
 +  }
 + 
 +  public double getZahl() {
 +    return zahl;
 +  }
 + 
 +  public String getText() {
 +    return text;
 +  }
 + 
 + /**
 + * Die toString()-Methode dient nur Debuggingzwecken
 + */
 +  @Override
 +  public String toString() {
 + 
 +    String s = "" + tokenType;
 + 
 +    switch(tokenType) {
 +        case zahl : 
 +          s += "[" + zahl + "]";
 +          break;
 +        case text : 
 +          s += "[" + text + "]";
 +          break;
 +        default : 
 +          break;
 +    }
 + 
 +    return s;
 + 
 +  }
 + 
 +}
 +</script>
 +
 +
 +</div>
 +
 +</HTML>
  
compilerbau/lexer/test/start.1635446152.txt.gz · Zuletzt geändert: 2021/12/29 11:29 (Externe Bearbeitung)

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki