Advertisement
AleksandarH

LexerImpl.java

Dec 1st, 2023
720
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 7.68 KB | None | 0 0
  1. package lexer;
  2.  
  3. import bg.tu_varna.kst_sit.ci_ep.exceptions.LexicalException;
  4. import bg.tu_varna.kst_sit.ci_ep.lexer.Lexer;
  5. import bg.tu_varna.kst_sit.ci_ep.lexer.token.Token;
  6. import bg.tu_varna.kst_sit.ci_ep.source.Source;
  7. import bg.tu_varna.kst_sit.ci_ep.source.SourceImpl;
  8. import bg.tu_varna.kst_sit.ci_ep.utils.CompilerTestHelper;
  9. import token.TokenImpl;
  10. import token.TokenType;
  11.  
  12. import java.io.IOException;
  13.  
  14. public class LexerImpl extends Lexer<TokenType> {
  15.  
  16.     private int line;
  17.     private int position;
  18.  
  19.     public LexerImpl(Source source) {
  20.         super(source);
  21.     }
  22.  
  23.     @Override
  24.     public Token<TokenType> nextToken() {
  25.         currentChar = source.getCurrentChar();
  26.         line = source.getLineNumber();
  27.         position = source.getPosition() + 1;
  28.         while (currentChar != Source.EOF) {
  29.             switch (currentChar) {
  30.                 case ' ' : case '\t' : handleSpaceAndTabs(); continue;
  31.  
  32.                 case '-' : return handleTwoCharOp('>', TokenType.MINUS, TokenType.ARROW);
  33.                 case '=' : return handleTwoCharOp('=', TokenType.BECOMES, TokenType.EQUALS);                        
  34.                 case '>' : return handleTwoCharOp('=', TokenType.GREATER, TokenType.GREATER_EQ);
  35.                 case '<' : return handleTwoCharOp('=', TokenType.LESS, TokenType.LESS_EQ);
  36.                 case '!' : return handleTwoCharOp('=', TokenType.NOT, TokenType.NOTEQUALS);
  37.                 case '&' : return handleTwoCharOp('&', TokenType.AND, TokenType.OTHER);
  38.                 case '|' : return handleTwoCharOp('|', TokenType.OR, TokenType.OTHER);
  39.                 case '/' : return handleSlash();
  40.                 case '\'': return handleCharLiteral();
  41.                 case '"' : return handleStringLiteral();
  42.  
  43.                 case '+' : return retTokenAndAdvance(TokenType.PLUS);
  44.                 case '[' : return retTokenAndAdvance(TokenType.LSQUARE);
  45.                 case ']' : return retTokenAndAdvance(TokenType.RSQUARE);                  
  46.                 case '{' : return retTokenAndAdvance(TokenType.LBRACKET);                    
  47.                 case '}' : return retTokenAndAdvance(TokenType.RBRACKET);      
  48.                 case '(' : return retTokenAndAdvance(TokenType.LPAREN);                      
  49.                 case ')' : return retTokenAndAdvance(TokenType.RPAREN);                      
  50.                 case ';' : return retTokenAndAdvance(TokenType.SEMICOLON);                      
  51.                 case '*' : return retTokenAndAdvance(TokenType.MUL);                      
  52.                 case '%' : return retTokenAndAdvance(TokenType.MOD);                    
  53.                 case ',' : return retTokenAndAdvance(TokenType.COMMA);                      
  54.                 case '@' : return retTokenAndAdvance(TokenType.AT);              
  55.  
  56.                 default  :
  57.                     if (isLetter(currentChar)) { return handleIdentifier(); }
  58.                     if (isDigit(currentChar)) { return handleDigit(); }
  59.                     return retTokenAndAdvance(TokenType.OTHER, currentChar + "");
  60.             }
  61.         }
  62.         return null;
  63.     }
  64.  
  65.     private Token<TokenType> retTokenAndAdvance(TokenType token) {
  66.         source.next();
  67.         return new TokenImpl(token, position, line);
  68.     }
  69.  
  70.     private Token<TokenType> retTokenAndAdvance(TokenType token, String text) {
  71.         source.next();
  72.         return new TokenImpl(token, text, position, line);
  73.     }
  74.  
  75.     private Token<TokenType> retToken(TokenType token) {
  76.         return new TokenImpl(token, position, line);
  77.     }
  78.  
  79.     private Token<TokenType> retToken(TokenType token, String text) {
  80.         return new TokenImpl(token, text, position, line);
  81.     }
  82.  
  83.     private void handleSpaceAndTabs() {
  84.         while (currentChar == ' ' || currentChar == '\t') {
  85.             currentChar = source.next();
  86.         }
  87.         line = source.getLineNumber();
  88.         position = source.getPosition() + 1;
  89.     }
  90.  
  91.     private Token<TokenType> handleTwoCharOp(char followingChar, TokenType firstMatchedToken, TokenType secondMatchedToken) {
  92.         if (source.next() == followingChar) {
  93.             return retTokenAndAdvance(secondMatchedToken);
  94.         }
  95.         return retToken(firstMatchedToken);
  96.     }
  97.  
  98.     private Token<TokenType> handleSlash() {
  99.         if (source.next() == '/') {
  100.             int currentLineNum = source.getLineNumber();
  101.             while (currentLineNum == source.getLineNumber()) {
  102.                 source.next();
  103.             }
  104.             return nextToken();
  105.         }
  106.         return retToken(TokenType.DIV);
  107.     }
  108.  
  109.     private Token<TokenType> handleCharLiteral() {
  110.         char ch = source.next();
  111.         if (ch == '\'') { return retTokenAndAdvance(TokenType.OTHER); }
  112.         if (ch == '\\') ch = handleSpecialChars();
  113.         currentChar = source.next();
  114.         if (currentChar == '\'') {
  115.             return retTokenAndAdvance(TokenType.CHAR_LITERAL, "" + ch);
  116.         }
  117.         return retTokenAndAdvance(TokenType.OTHER);
  118.     }
  119.  
  120.     private char handleSpecialChars() {
  121.         switch (source.next()) {
  122.             case 'n'    : return '\n';
  123.             case 't'    : return '\t';
  124.             case 'b'    : return '\b';
  125.             case 'r'    : return '\r';
  126.             case 'f'    : return '\f';
  127.             case '\''   : return '\'';
  128.             case '"'    : return '"';
  129.             case '\\'   : return '\\';
  130.             default     : throw new LexicalException("Incorrect char escape: " + currentChar, line, position);
  131.         }
  132.     }
  133.  
  134.     private Token<TokenType> handleStringLiteral() {
  135.         StringBuilder sb = new StringBuilder();
  136.         while((currentChar = source.next()) != Source.EOF && currentChar != '"') {
  137.             if (currentChar == '\\') currentChar = handleSpecialChars();
  138.             sb.append(currentChar);
  139.         }
  140.         if (currentChar == Source.EOF) {
  141.             throw new LexicalException("String quote not closed!", line, position);
  142.         }
  143.         return retTokenAndAdvance(TokenType.STRING_LITERAL, sb.toString());
  144.     }
  145.  
  146.     private Token<TokenType> handleIdentifier() {
  147.         StringBuilder sb = new StringBuilder();
  148.         sb.append(currentChar);
  149.         currentChar = source.next();
  150.         while(isLetter(currentChar) || isDigit(currentChar)) {
  151.             sb.append(currentChar);
  152.             currentChar = source.next();
  153.         }
  154.         String res = sb.toString();
  155.         if (TokenType.isKeyword(res)) {
  156.             return retToken(TokenType.valueOf(res.toUpperCase()));
  157.         }
  158.         return retToken(TokenType.IDENTIFIER, res);
  159.     }
  160.  
  161.     private Token<TokenType> handleDigit() {
  162.         StringBuilder sb = new StringBuilder();
  163.         while (isDigit(currentChar)) {
  164.             sb.append(currentChar);
  165.             currentChar = source.next();
  166.         }
  167.         String digit = sb.toString();
  168.         try {
  169.             Integer.parseInt(digit);
  170.         } catch (NumberFormatException e) {
  171.             throw new LexicalException("Not a valid integer " + digit + "." , line, position, e);
  172.         }
  173.         return retToken(TokenType.NUMBER, digit);
  174.     }
  175.  
  176.     private boolean isLetter(char ch) {
  177.         boolean bool = false;
  178.         if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z')
  179.         {
  180.             bool = true;
  181.         }
  182.         return bool;
  183.     }
  184.  
  185.     private boolean isDigit(char ch) {
  186.         boolean bool = false;
  187.         if (ch >= '0' && ch <= '9')
  188.         {
  189.             bool = true;
  190.         }
  191.         return bool;        
  192.     }
  193.  
  194.     public static void main(String[] args) throws IOException {
  195.         Lexer<TokenType> lexer = new LexerImpl(new SourceImpl("resources/Fib.txt"));
  196.         System.out.println(CompilerTestHelper.getTokensAsString(lexer));
  197.     }
  198.  
  199. }
  200.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement