Lexerを実装しよう(2)


前置き

バージョン 環境
jdk-10 IntelliJ IDEA

たぶん上の環境で動きます。

前の記事Lexerを実装しよう(1)

補足

このシリーズは私に共感してくれる人、new languageに興味を持っている人、チーム開発したいjavaプログラマさんとつながりたいと思って書いているものです。ほかの用途で利用・閲覧することはもちろんOKです。ですが、興味を持っていただけるととてもうれしいですし、コメントなどで何か教えてくださるととても助かります。


 Lexerを少しfunctionalにしたつもりです。Lexerのように入力と出力の個数が違いかつ出力数がわかっていないと扱いにくいと感じました。

実装

FLexer.java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;

public class FLexer {

    static Stack<String> stack = new Stack();

    //private static List<Character> brackets = Arrays.asList('(',')','{','}','[',']');
    private static List<Character> operators = Arrays.asList('=','+','-','*','/');

    public static FType getType(final Character c){
        if(Character.isLetter(c)) return FType.alphabet;
        else if(Character.isDigit(c)) return FType.digit;
        else if(Character.isWhitespace(c)) return FType.space;
        else if(operators.contains(c)) return FType.operator;
        //else if(brackets.contains(c)) return FType.brackets;
        return FType.other;
    }
    public static List<Character> toList(final char[] chars){
        List<Character> list = new ArrayList<>();
        for(Character aChar : chars){
            list.add(aChar);
        }
        return list;
    }
    public static void analyze(final Character aChar){
        if(stack.empty()){
            stack.push(Character.toString(aChar));
        }else{
            final String previous = stack.pop();
            if(getType(aChar) == getType(previous.charAt(0))){
                stack.push(previous + aChar);
            }else{
                stack.push(previous);
                stack.push(Character.toString(aChar));
            }
        }
    }
    public static void disp(){
        System.out.println(stack);
    }
}
FType.java
public enum FType{
    alphabet,
    digit,
    space,
    operator,
    //bracket,
    other
}

実装の説明

 「かっこ」はやはりめんどうなので実装していませんが、analyze()のif分岐を増やせば対応できると思います。

public static List<Character> toList(...)
ラムダ式を使いたかったので、リストに変換する関数を用意しました。
public static void analyze(...)
 前の要素を読むならスタックとか使えるんじゃないかと思ってスタックにしました。

実行

Main.java
import java.io.IOException;

public class Main{
    public static void main(String[] args) throws IOException{
        System.out.println("\n--EAM");
        char[] chars = EAM.use("lib\\test.txt", eam -> eam.read());
        for (char aChar : chars) {
            System.out.print(aChar);
        }
        System.out.println( "\n--FLexer");
        FLexer.toList(chars).stream()
                            .forEach(FLexer::analyze);
        FLexer.disp();
    }
}
--EAM
close()
a = 2 + 7 * 3
log a
--FLexer
[a,  , =,  , 2,  , +,  , 7,  , *,  , 3, 
, log,  , a]

こんな感じになれば成功です。分からないことがあれば質問してください。