Как создать и разобрать if заявления в Antlr 4 - PullRequest
0 голосов
/ 25 апреля 2018

Итак, я только начал изучать antlr4 и создал исключительно простой язык программирования. Язык может создавать переменные (int, booleans и strings), изменять их значения и выводить их значения. Тем не менее, я пытаюсь сделать заявление if, но после многих попыток это не сработало. Поиск в Google тоже не помог, так как большинство других кодов слишком разные, чтобы понимать и применять их самостоятельно. Большая часть моего кода следует этому руководству:

https://progur.com/2016/09/how-to-create-language-using-antlr4.html

Вот мой файл грамматики

grammar valhallap;

program : 'begin' statement+ 'end';

ifState : ifDec 'STARTIF' statement+ 'ENDIF';



statement :  createINT|assign|addINT|printVar|createString|print|createBool|;




ifDec: 'if' (NUMBER|ID) EXPRESION (NUMBER|ID) 'then';
createINT : 'new' 'int' ID;
createBool: 'new' 'bool' ID;
createString : 'new' 'string' ID;
addINT : 'addINT' ID NUMBER;
assign : 'set' ID (STRING|BOOL|NUMBER);
print : 'output' 'say' STRING;
printVar : 'output' 'var' ID;





ID : [A-z]+;
NUMBER : [0-9]+ ;
STRING : ["] ( ~["\r\n\\] | '\\' ~[\r\n] )* ["] | ['] ( ~['\r\n\\] | '\\' ~[\r\n] )* ['];
BOOL : 'true' | 'false';
WS : [ \n\t]+ -> skip;
Comment: '**' ~( '\r' | '\n' )* -> skip;
STATEMENT : .;
EXPRESION:
     'MORETHAN'
     |'LESSTHAN'
     |'EQUALS'
     |'LESSEQUALS'
     |'MOREEQUALS';

Наконец, вот класс слушателя

import com.power.valhallap.grammar.*;
import java.io.FileInputStream;
import java.io.IOException;

import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;

/**
 *
 * @author admin
 */

public class ValhallaListener extends valhallapBaseListener{

/**
 * @param args the command line arguments
 */
private Map<String, Object> variables;
public static boolean ifState = false;

public ValhallaListener()
{
    //init all the variables
    variables = new HashMap<>();
}


//if statements



@Override
public void exitAssign(valhallapParser.AssignContext ctx)
{
    String variable = ctx.ID().getText();


    if(variables.get(variable) instanceof String)
    {
        if(ctx.NUMBER() != null || ctx.BOOL() != null)
        {`enter code here`
            System.out.println("error expecting string");
        }
    }
    if(variables.get(variable) instanceof Boolean)
    {
        if(ctx.NUMBER() != null || ctx.STRING() != null)
        {
            System.out.println("error expecting boolean");
        }
    }
    if(variables.get(variable) instanceof Integer)
    {
        if(ctx.STRING() != null || ctx.BOOL() != null)
        {
            System.out.println("error expecting integer");
        }
    }

    if(ctx.STRING() != null)
    {
        if(variables.get(variable) instanceof String)
        {
           String finalString = ctx.STRING().getText();
           finalString = finalString.replace("\"", "");
           variables.put(variable, finalString);
        }

    }

    if(ctx.NUMBER() != null)
    {
        if(variables.get(variable) instanceof Integer)
        {
           variables.put(variable, Integer.parseInt(ctx.NUMBER().getText()));
        }

    }

    if(ctx.BOOL() != null)
    {
        if(variables.get(variable) instanceof Boolean)
        {
           boolean answer = Boolean.parseBoolean(ctx.BOOL().getText());

           variables.put(variable, answer);
        }

    }


}

@Override
public void exitCreateINT(valhallapParser.CreateINTContext ctx)
{
    //get's the variable name of int
    String variableName = ctx.ID().getText();

     if(!variables.containsKey(variableName))
    {
        //add the name to the hashmap with the init value of 0
        variables.put(variableName, 0);
    }
}



@Override
public void exitAddINT(valhallapParser.AddINTContext ctx)
{
    //get the var name
    String varName = ctx.ID().getText();

    //get the value
    int first = Integer.parseInt(variables.get(varName).toString());

    int addValue = Integer.parseInt(ctx.NUMBER().getText());

    int finalValue = first + addValue;

    //assign the new value

    variables.put(varName, finalValue);
}


 @Override
public void exitPrintVar(valhallapParser.PrintVarContext ctx)
{
    String varName = ctx.ID().getText();



    System.out.println(variables.get(varName));
}

@Override
public void exitPrint(valhallapParser.PrintContext ctx)
{
    String output = ctx.STRING().getText();
    output = output.replace("\"", "");
    System.out.println(output);
}

@Override
public void exitCreateString(valhallapParser.CreateStringContext ctx)
{
    String variableName = ctx.ID().getText();


    if(!variables.containsKey(variableName))
    {
        //add the name to the hashmap with the init value of null
        variables.put(variableName, "");
    }
}



@Override
public void exitCreateBool(valhallapParser.CreateBoolContext ctx)
{
    //get's the variable name of int
    String variableName = ctx.ID().getText();

     if(!variables.containsKey(variableName))
    {
        //add the name to the hashmap with the init value of false
        variables.put(variableName, false);
    }
}





public static void main(String[] args) {
   try {
    ANTLRInputStream input = new ANTLRInputStream(
        new FileInputStream(args[0]));    

    valhallapLexer lexer = new  valhallapLexer(input);
    valhallapParser parser = new valhallapParser(new CommonTokenStream(lexer));
    parser.addParseListener(new ValhallaListener());

    // Start parsing
    parser.program();


    if(ifState)
    {
        parser.ifState();
    }



    } catch (IOException e) {
        e.printStackTrace();
    }
}

}

Синтаксис оператора if, которого я хочу достичь:

begin
if 5 MORETHAN 4 then
   .....
ENDIF
end

Я новичок в antlr4, и некоторые концепции для меня новы, было бы здорово, если бы кто-нибудь мог мне помочь, спасибо!

1 Ответ

0 голосов
/ 26 апреля 2018

ifState не упоминается в вашем правиле statement.

Также имейте в виду, что вы определили, что после THEN должен быть 'STARTIF' - его нет в вашем примере ввода.

И еще одно наблюдение, ваше правило statement заканчивается на |; - это означает, что оно допускает пустое утверждение.Это не имеет смысла в языке без разделителя операторов.

Редактировать

Как указала @CoronA, проблема в том, что вы сначала вызываете правило program в главном, а затем вызываетеifState.Это означает, что вы ожидаете сначала выполнить синтаксический анализ программы (начиная с begin и заканчивая end), а только затем вы даете команду синтаксическому анализатору выполнить синтаксический анализ оператора if.Таким образом, входные данные, которые будут проанализированы вашим текущим кодом, должны выглядеть примерно так:

begin
    ...
end
if 5 MORETHAN 4 then
STARTIF
   ...
ENDIF

Что вы, вероятно, хотите сделать, это сделать ifState просто другим возможным типом оператора, т.е. добавить его к statement Править и звонить только program от основного.

...