Парсер ANTLR входит в "неправильное" правило - PullRequest
0 голосов
/ 03 декабря 2018

Я пытаюсь создать интерпретатор для простого языка программирования с использованием ANTLR.Пока что он состоит из печатных и числовых выражений.Я создал правило синтаксического анализатора simpleExpr для обработки отрицательных чисел.Я пробовал и другие способы, но это единственный способ, который мне подходит.Однако по какой-то причине мой посетитель переходит на это правило, даже если я ожидаю, что оно посетит мое правило «числа».Я действительно думаю, что это не ошибка посетителя, потому что даже дерево, нарисованное ANTLR, показывает это поведение.Это странно, но все будет в порядке, но моя проблема в том, что когда я пытаюсь распечатать результат простого сложения, например, print (1 + 2);тогда он этого не делает, но входит в правило «числа» вместо правила «Плюс».

Моя грамматика:

grammar BatshG;
/*
 * Parser Rules
 */
compileUnit: (expression | ( println ';') | ( print ';' ))+;
expression:     
                left=expression '/' right=simpleExpr #Divi
            |   left=expression '*' right=simpleExpr #Mult
            |   left=expression '-' right=simpleExpr #Minus
            |   left=expression '+' right=simpleExpr #Plus
            |   number=simpleExpr                    #Number
;
println: 'println' '(' argument=expression ')'; 
print: 'print' '(' argument=expression ')';
simpleExpr
      :   (MINUS)?
          (FLOAT | INTEGER)
      ;
MINUS: '-';
INTEGER: [0-9] [0-9]*;
DIGIT : [0-9]                       ;
FRAC : '.' DIGIT+                   ;
EXP : [eE] [-+]? DIGIT+  ;
FLOAT : DIGIT* FRAC EXP?             ;
WS: [ \n\t\r]+ -> channel(HIDDEN);

Если это поможет, вот мое визуализированное дерево, сгенерированноепо ANTLR для

print(1+2);

enter image description here

Обновление: Класс посетителя, если он имеет значение:

public class BatshGVisitor : BatshGBaseVisitor<ResultValue>
{
    public ResultValue Result { get; set; }
    public StringBuilder OutputForPrint { get; set; }

    public override ResultValue VisitCompileUnit([NotNull] BatshGParser.CompileUnitContext context)
    {
        OutputForPrint = new StringBuilder("");
        var resultvalue = VisitChildren(context);
        Result = new ResultValue() { ExpType = "string", ExpValue = resultvalue.ExpValue };
        return Result;
    }

    public override ResultValue VisitPlus([NotNull] BatshGParser.PlusContext context)
    {
        var leftExp = VisitChildren(context.left);
        var rigthExp = VisitChildren(context.right);

        return new ResultValue()
        {
            ExpType = "number",
            ExpValue = (double)leftExp.ExpValue + (double)rigthExp.ExpValue
        };
    }

    //public override ResultValue VisitNumber([NotNull] BatshGParser.NumberContext context)
    //{
    //    return new ResultValue()
    //    {
    //        ExpType = "number",
    //        ExpValue = Double.Parse(context.GetChild(0).GetText() 
    //        + context.GetChild(1).GetText()
    //        + context.GetChild(2).GetText()
    //        , CultureInfo.InvariantCulture)
    //    };
    //}

    public override ResultValue VisitPrint([NotNull] BatshGParser.PrintContext context)
    {
        var viCh = VisitChildren(context.argument);
        var viChVa = viCh.ExpValue;
        string printInner = viChVa.ToString();
        var toPrint = new ResultValue()
        {
            ExpType = viCh.ExpType,
            ExpValue = printInner
        };
        OutputForPrint.Append(toPrint.ExpValue);
        return toPrint;
    }

    public override ResultValue VisitSimpleExpr([NotNull] BatshGParser.SimpleExprContext context)
    {
        string numberToConvert = "";
        if (context.ChildCount == 1)
        {
            numberToConvert = context.GetChild(0).GetText();
        }
        else if (context.GetChild(0).ToString() == "-")
        {
            if (context.ChildCount == 2)
            {
                numberToConvert = "-" + context.GetChild(1);
            }
            if (context.ChildCount == 4)
            {
                numberToConvert = context.GetChild(0).ToString() + context.GetChild(1).ToString() +
                    context.GetChild(2).ToString() + context.GetChild(3).ToString();
            }
        }

        return new ResultValue()
        {
            ExpType = "number",
            ExpValue = Double.Parse(numberToConvert, CultureInfo.InvariantCulture)
        };
    }

    protected override ResultValue AggregateResult(ResultValue aggregate, ResultValue nextResult)
    {
        if (aggregate == null)
            return new ResultValue()
            {
                ExpType = nextResult.ExpType,
                ExpValue = nextResult.ExpValue
            };
        if (nextResult == null)
        {
            return aggregate;
        }
        return null;
    }
}

В чем проблема с моей грамматикой?Спасибо!

1 Ответ

0 голосов
/ 03 декабря 2018

Внутри метода посещения для операторов печати у вас есть это:

var viCh = VisitChildren(context.argument);

Итак, допустим, ваш ввод был print(1+2);.Тогда context.argument будет PlusContext для 1+2, а потомки context.argument будут NumberContext для 1, Token объект для + и SimpleExpression объект для 2. Так чтопозвонив по номеру VisitChildren, вы собираетесь посетить этих детей, поэтому он никогда не запускает VisitPlus и не переходит непосредственно к номерам.

Как правило, вы редко хотите посещать дочерние элементы какого-либо другого узла.Вы обычно хотите навестить своих собственных детей, не пропускать детей и непосредственно посещать внуков.Так что вместо этого вы должны позвонить Visit(context.argument);.

...