我的编程语言的解析器不会在第一个块或第一个语句之后检查任何内容,而 while 循环只会接受一个语句

My programming language's parser wont check anything after the first block or first statement and while loops will only take in one statement

我在 Java 中制作了一种编程语言。但是,我的解析器存在一些问题。解析器只检查第一个块或语句,或者它只检查第一个语句,然后停止检查输入的其余内容。我不太确定为什么要这样做。它不应该那样发生。

我的编程语言中的 while 语句也会发生类似的事情。虽然语句只接受一个语句,然后不再接受,如果给出一个或多个,我的语言将打印出一个错误(不是 Java 错误,而只是一个打印语句,用作我的错误处理我制作的编程语言)。我试过使用 do { statement(); }while(accept("SEMICOLON")); 和 while 循环,但这似乎不起作用。我也尝试了与第一期类似的方法,但无济于事。

我的目标是让解析器检查不止一个块或语句,并使 while 循环接受不止一个语句,比如它应该如何根据我的语言语法工作。希望你们中的一位能帮助我解决这些问题。

分词器:

package dev.fransk.tundra;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Tokenizer {

    // Read file
    public static void readFile() {
        try {
            File myObj = new File("filename.txt");
            Scanner myReader = new Scanner(myObj);
            while (myReader.hasNextLine()) {
                String data = myReader.nextLine();
                System.out.println(data);
            }
            myReader.close();
        } catch (FileNotFoundException e) {
            System.out.println("An error occurred.");
            e.printStackTrace();
        }
    }

    // Tokens
    public static enum Token {
        STR("\"([^\"]*)\""), IGNORE("~([^~]*)~"), EXTERN("extern"), 
    FLOAT("float"), SCAN("scan"), STRING("string"),
        VOID("void"), WHILE("while"), WRITELN("writeln"), WORD("[a-zA-Z_]+"), 
    FLT("-?[0-9]+\.[0-9]+"), LTEQ("<="),
        GTEQ(">="), LT("<"), GT(">"), DEQ("=="), NTEQ("!="), MUL("\*"), 
    DIV("/"), PLUS("\+"), MINUS("\-"),
        MODULO("%"), EQ("="), SEMICOLON(";"), LCUR("\{"), RCUR("\}"), SKIP("[ 
    \t\f\r\n]+"), ERROR(".");

        public final String pattern;

        Token(String pattern) {
            this.pattern = pattern;
        }
    }

    public static class Word {
        public Token token;
        public String lexeme;

        public Word(Token token, String lexeme) {
            this.token = token;
            this.lexeme = lexeme;
        }

        @Override
        public String toString() {
            if (token.name() == "SKIP")
                return "";

            return String.format("%-10s: [%s]", token.name(), lexeme);
        }
    }

    public static ArrayList<Word> lex(String input) {
        ArrayList<Word> words = new ArrayList<Word>();

        StringBuffer tokenPatternsBuffer = new StringBuffer();
        for (Token token : Token.values())
            tokenPatternsBuffer.append(String.format("|(?<%s>%s)", token.name(), 
    token.pattern));
        Pattern tokenPatterns = Pattern.compile(new 
    String(tokenPatternsBuffer.substring(1)));

        Matcher matcher = tokenPatterns.matcher(input);
        while (matcher.find()) {
            for (Token token : Token.values())
                if (matcher.group(token.name()) != null) {
                    words.add(new Word(token, matcher.group(token.name())));
                    continue;
                }
        }
        return words;
    }

    public static ArrayList<String> tokenList = new ArrayList<String>();
    public static ArrayList<String> lexemeList = new ArrayList<String>();
}

这是解析器 class:

package dev.fransk.tundra;

public class Parser {
    
    public static int i;
    private static Tokenizer tokenizer;
    
    public static boolean accept(String s) {
        if(tokenizer.tokenList.get(i).equals(s)) {
            i++;
            return true;
        }else if(tokenizer.tokenList.get(i).equals("EOF")) {
            for(;;)
                break;
        }
        return false;
    }

    public static boolean expect(String s) {
        if(accept(s))
            return true;
        System.out.println("Parsing error. Expect: unexpected symbol");
        return false;
    }
    
    public static void factor() {
        if(accept("FLT"))
            ;
        else if(accept("STR"))
            ;
        else if(accept("WORD"))
            ;
        else
            System.out.println("Parsing error. Factor: syntax error");
    }
    
    public static void term() {
        factor();
        while(tokenizer.tokenList.get(i).equals("PLUS") || 
    tokenizer.tokenList.get(i).equals("MINUS")
                || tokenizer.tokenList.get(i).equals("MUL") || 
    tokenizer.tokenList.get(i).equals("DIV")
                || tokenizer.tokenList.get(i).equals("MODULO")) {
            i++;
            factor();
        }
    }
    
    public static void condition() {
        term();
        if(tokenizer.tokenList.get(i).equals("LT") || 
    tokenizer.tokenList.get(i).equals("GT") || 
                tokenizer.tokenList.get(i).equals("LTEQ") || 
    tokenizer.tokenList.get(i).equals("GTEQ") || 
                tokenizer.tokenList.get(i).equals("DEQ") || 
    tokenizer.tokenList.get(i).equals("NTEQ")) {
            i++;
            term();
        }else
            System.out.println("Parsing error. Condition: invalid operator");
    }
    
    public static void statement() {
        if(accept("WORD")) {
            expect("EQ");
            term();
            expect("SEMICOLON");
        }else if(accept("EXTERN")) {
            expect("IGNORE");
            expect("SEMICOLON");
        }else if(accept("WRITELN")) {
            term();
            expect("SEMICOLON");
        }else if(accept("WHILE")) { // Second issue around here
            condition();
            expect("LCUR");
            do {
                statement();
            }while(accept("SEMICOLON"));
            expect("RCUR");
        }else
            System.out.println("Parsing error. Statement: syntax error");
    }
    
    public static void block() {
        if(accept("FLOAT")) {
            expect("WORD");
            expect("SEMICOLON");
        }
        if(accept("STRING")) {
            expect("WORD");
            expect("SEMICOLON");
        }
        statement();
    }
    
    public static void program() {
        block(); // First issue around here
    }
}

Class 包括主要功能:

package dev.fransk.tundra;

import java.util.ArrayList;

import dev.fransk.tundra.Tokenizer.Word;

public class Tundra {
    
    private static Tokenizer tokenizer;
    private static Parser parser;
    //private static Translator translator;

    public static void main(String[] args) {
        String input = "float a; a = 3.0; string b; b = \"a\"; extern 
     ~System.out.println(\"e\");~;";
        
        ArrayList<Word> words = tokenizer.lex(input);
        
        for (Word word : words) {
            if(word.token.name() == "ERROR")
                throw new java.lang.Error("Lexing Error: The token \'" + 
    word.lexeme + "\' is invalid");
            
            if(word.token.name() != "SKIP") {
                tokenizer.tokenList.add(String.valueOf(word.token));
                tokenizer.lexemeList.add(String.valueOf(word.lexeme));
            }
        }
        tokenizer.tokenList.add("EOF");
        tokenizer.lexemeList.add("EOF");
        
        System.out.println(tokenizer.tokenList + "\n" + tokenizer.lexemeList);
        parser.program();
    }
}

如果您需要更多代码,可以在此处找到:https://github.com/Fransk7/tundra

我查看了您的代码并注意到了一些奇怪的结构。

你为什么这样做(这会生成低效的代码)并且 imo 很难阅读。您只想在 accept 的 none 调用 return 为真时打印错误。注意:编译器实际上生成了我称之为 leap-frog 的代码,它围绕 goto 字节码进行分支。

public static void factor() {
     if(accept("FLT"))
         ;
     else if(accept("STR"))
         ;
     else if(accept("WORD"))
         ;
     else
         System.out.println("Parsing error. Factor: syntax error");
 }
    

而不是这个。如果任何 accept 调用 returns true,结果将是 true 所以 !truefalse 并且打印永远不会发生,除非它们都是 false.

public static void factor1() {
        if (!(accept("FLT") || accept("STR") || accept("WORD"))) {
            System.out.println("Parsing error. Factor: syntax error");
        }
}

并且在下文中,无论 else if 子句如何,您都将 return false 所以您甚至不需要第二个条件。即使你这样做了,在我能看到的任何情况下,带中断的紧密循环都是没有必要的。

并且无需声明静态 tokenizer,因为您调用了静态方法。只需使用 class 名称 Tokenizer

所以替换以下内容:


private static Tokenizer tokenizer;
    
public static boolean accept(String s) {
    if(tokenizer.tokenList.get(i).equals(s)) {
        i++;
        return true;
    }else if(tokenizer.tokenList.get(i).equals("EOF")) {
        for(;;)
            break;
    }
    return false;
}

public static boolean accept(String s) {
    if(Tokenizer.tokenList.get(i).equals(s)) {
        i++;
        return true;
    }
    return false;
}

并使用 equals 而不是 == 来比较字符串(您在其他地方这样做)

 @Override
 public String toString() {
     if (token.name() == "SKIP")
         return "";

     return String.format("%-10s: [%s]", token.name(), lexeme);
 }

这里是 Tundra class

    public static void main(String[] args) {
        String input = "float a; a = 3.0; string b; b = \"a\"; extern 
     ~System.out.println(\"e\");~;";
        
        ArrayList<Word> words = tokenizer.lex(input);
        
        for (Word word : words) {
            if(word.token.name() == "ERROR")
                throw new java.lang.Error("Lexing Error: The token \'" + 
    word.lexeme + "\' is invalid");
            
            if(word.token.name() != "SKIP") {
                tokenizer.tokenList.add(String.valueOf(word.token));
                tokenizer.lexemeList.add(String.valueOf(word.lexeme));
            }
        }
        tokenizer.tokenList.add("EOF");
        tokenizer.lexemeList.add("EOF");
        
        System.out.println(tokenizer.tokenList + "\n" + tokenizer.lexemeList);
        parser.program();
    }

我通过稍微更改语法来回答我自己的问题。句点现在分开 statements/blocks,在 while 循环中也一样。

package dev.fransk.tundra;

public class Parser {
    
    public static int i;
    
    // Functions
    public static boolean accept(String s) {
        if(Tokenizer.tokenList.get(i).equals(s)) {
            i++;
            return true;
        }else if(Tokenizer.tokenList.get(i).equals("EOF")) {
            for(;;)
                break;
        }
        return false;
    }

    public static boolean expect(String s) {
        if(accept(s))
            return true;
        System.out.println("Parsing error. Expect: unexpected symbol at " + i);
        return false;
    }
    
    public static void factor() {
        if(accept("FLT"))
            ;
        else if(accept("STR"))
            ;
        else if(accept("WORD"))
            ;
        else
            System.out.println("Parsing error. Factor: syntax error at " + i);
    }
    
    public static void term() {
        factor();
        while(Tokenizer.tokenList.get(i).equals("PLUS") || Tokenizer.tokenList.get(i).equals("MINUS")
                || Tokenizer.tokenList.get(i).equals("MUL") || Tokenizer.tokenList.get(i).equals("DIV")
                || Tokenizer.tokenList.get(i).equals("MODULO")) {
            i++;
            factor();
        }
    }
    
    public static void condition() {
        term();
        if(Tokenizer.tokenList.get(i).equals("LT") || Tokenizer.tokenList.get(i).equals("GT") || 
                Tokenizer.tokenList.get(i).equals("LTEQ") || Tokenizer.tokenList.get(i).equals("GTEQ") || 
                Tokenizer.tokenList.get(i).equals("DEQ") || Tokenizer.tokenList.get(i).equals("NTEQ")) {
            i++;
            term();
        }else
            System.out.println("Parsing error. Condition: invalid operator at " + i);
    }
    
    public static void statement() {
        if(accept("WORD")) {
            expect("EQ");
            term();
            expect("SEMICOLON");
        }else if(accept("EXTERN")) {
            expect("IGNORE");
            expect("SEMICOLON");
        }else if(accept("WRITELN")) {
            term();
            expect("SEMICOLON");
        }else if(accept("WHILE")) {
            condition();
            expect("LCUR");
            statement();
            while(Tokenizer.tokenList.get(i).equals("PERIOD")) {
                i++;
                statement();
            }
            expect("RCUR");
        }else
            System.out.println("Parsing error. Statement: syntax error at " + i);
    }
    
    public static void block() {
        if(accept("FLOAT")) {
            expect("WORD");
            expect("SEMICOLON");
        }
        if(accept("STRING")) {
            expect("WORD");
            expect("SEMICOLON");
        }
        statement();
    }
    
    public static void program() {
        block(); 
        while(Tokenizer.tokenList.get(i).equals("PERIOD")) {
            i++;
            block();
        }
    }
}