在Antlr4基础的解释器中,循环内的if语句中使用字符串名称而非值的ID。

huangapple go评论72阅读模式
英文:

If statement inside loop ID string name instead of value in Antlr4 based Interpreter

问题

好的,我理解了。以下是已翻译的内容:

Good day can really appreciate if some one would help. I am working on interpreter based on Antlr4 now i am having challenge after implementation of Visitor class. The implementation is working perfectly i.e the if statement unless inside loop it will return the ID name instead of value.
以下是代码部分,不需要翻译:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EasyBite
{
    public class Interpreter : EasyBiteBaseVisitor<object>
    {
        // ... 这里是类的具体实现,请查看上述代码 ...
    }
}
And the source code i tried with
以下是源代码部分,不需要翻译:

generate i from 1 to 50 
if i / 2 == 2 then 
show "Make sense"
else 
show "is not working"
end if     
stop

repeat while(2 > 3) 
show "test" 
showline()
show("")
end repeat
Now this i / 2 == 2 is not working which crashes the interpreter with message of invalid conversion after using debugger i realized it actually calling i name instead of i value.

Thank you.
现在,这个 `i / 2 == 2` 不起作用,导致解释器崩溃,并显示无效转换消息。通过使用调试器,我意识到它实际上调用了变量名 i 而不是 i 的值。

谢谢。
英文:

Good day can really appreciate if some one would help. I am working on interpreter based on Antlr4 now i am having challenge after implementation of Visitor class. The implementation is working perfectly i.e the if statement unless inside loop it will return the ID name instead of value.
Below is the implementation

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EasyBite
{
public class Interpreter : EasyBiteBaseVisitor<object>
{
private Dictionary<string, object> variables = new Dictionary<string, object>();
// Helper function to convert an object to a bool
private bool ToBool(object obj)
{
if (obj is bool)
return (bool)obj;
if (obj is int)
return (int)obj != 0;
if (obj is double)
return (double)obj != 0.0;
if (obj is string)
return !string.IsNullOrEmpty((string)obj);
return obj != null;
}
// Helper function to check if two objects are equal
private bool Equals(object a, object b)
{
if (a is double && b is double)
return Math.Abs((double)a - (double)b) < double.Epsilon;
return object.Equals(a, b);
}
// Declare the VisitProgram method
public override object VisitProgram(EasyBiteParser.ProgramContext context)
{
// Visit all the child statements
foreach (var statementContext in context.statement_list())
{
Visit(statementContext);
}
return null;
}
// Declare the VisitDeclareStatement method
public override object VisitDeclareStatement(EasyBiteParser.DeclareStatementContext context)
{
// Add the variable to the dictionary
if (!variables.ContainsKey(context.ID().GetText()))
{
variables.Add(context.ID().GetText(), null);
}
else
{
throw new Exception(String.Format("Variable {0} already declared", context.ID().GetText()));
}
return null;
}
// Declare the VisitSetStatement method
public override object VisitSetStatement(EasyBiteParser.SetStatementContext context)
{
// Update the value of the variable
var id = context.ID().GetText();
var value = Visit(context.expression());
variables[id] = value;
return null;
}
// Declare the VisitAssignStatement method
public override object VisitAssignStatement(EasyBiteParser.AssignStatementContext context)
{
// Update the value of the variable
var id = context.ID().GetText();
if (!variables.ContainsKey(id))
{
throw new Exception(String.Format("Variable {0} is not declared", context.ID().GetText()));
}
else
{
var value = Visit(context.expression());
variables[id] = value;
}
return null;
}
// Declare the VisitShowStatement method
public override object VisitShowStatement(EasyBiteParser.ShowStatementContext context)
{
// Print the value of the expression
var value = Visit(context.expression());
Console.WriteLine(value);
return null;
}
public override object VisitShowlnStatement(EasyBiteParser.ShowlnStatementContext context)
{
Console.WriteLine();
return null;
}
// Declare the VisitInputStatement method
public override object VisitInputStatement(EasyBiteParser.InputStatementContext context)
{
string variableName;
string inputPrompt;
if (context.ID() != null)
{
variableName = context.ID().GetText();
}
else
{
variableName = context.SET().GetText();
}
inputPrompt = (string)Visit(context.expression());
Console.Write(inputPrompt);
string userInput = Console.ReadLine();
// Convert the user input to the appropriate data type based on the variable type
variables[variableName] = userInput;
return null;
}
public override object VisitExpression(EasyBiteParser.ExpressionContext context)
{
if (context.LPAREN() != null && context.RPAREN() != null)
{
return Visit(context.expression(0));
}
else if (context.STRING() != null)
{
return context.GetText().Substring(1, context.GetText().Length - 2)
.Replace("\\\\", "\\").Replace("\\\"", "\"").Replace("\\'", "'");
}
else if (context.NUMBER() != null)
{
return double.Parse(context.NUMBER().GetText());
}
else if (context.ID() != null)
{
string id = context.ID().GetText();
if (variables.ContainsKey(id))
{
if (variables[id] is int)
{
return (int)variables[id];
}
else if (variables[id] is double || variables[id] is float)
{
return (double)variables[id];
}
else if (variables[id] is string)
{
return (string)variables[id];
}
else if (variables[id] is bool)
{
return (bool)variables[id];
}
}
else
{
Console.WriteLine("No variable named {0}", id);
}
}
else if (context.NOT() != null)
{
bool value = (bool)VisitExpression(context.expression(0));
return !value;
}
else if (context.AND() != null)
{
bool left = (bool)VisitExpression(context.expression(0));
bool right = (bool)VisitExpression(context.expression(1));
return left && right;
}
else if (context.OR() != null)
{
bool left = (bool)VisitExpression(context.expression(0));
bool right = (bool)VisitExpression(context.expression(1));
return left || right;
}
else if (context.LESS_THAN() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left < right;
}
else if (context.LESS_THAN_EQUAL() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left <= right;
}
else if (context.GREATER_THAN() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left > right;
}
else if (context.GREATER_THAN_EQUAL() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left >= right;
}
else if (context.EQUAL() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left == right;
}
else if (context.NOT_EQUAL() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left != right;
}
else if (context.PLUS() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left + right;
}
else if (context.MINUS() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left - right;
}
else if (context.MUL() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left * right;
}
else if (context.DIV() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return left/ right;
}
else if (context.MODULO() != null)
{
int left = (int)VisitExpression(context.expression(0));
int right = (int)VisitExpression(context.expression(1));
return left % right;
}
else if (context.POW() != null)
{
double left = (double)VisitExpression(context.expression(0));
double right = (double)VisitExpression(context.expression(1));
return Math.Pow(left, right);
}
return "Invalid expression";
}
public override object VisitForStatement(EasyBiteParser.ForStatementContext context)
{
string variableName = context.ID().GetText();
int start = (int)Visit(context.expression(0));
int end = (int)Visit(context.expression(1));
int step = context.expression(2) != null ? (int)Visit(context.expression(2)) : 1;
for (int i = start; i <= end; i += step)
{
variables[variableName] = i;
var statementListIndex = (i - start) / step; // compute the index of the statement list
var statementList = context.statement_list(statementListIndex);
foreach (var statement in context.statement_list())
{
Visit(statement);
}
}
return null;
}
public override object VisitGenerateStatement(EasyBiteParser.GenerateStatementContext context)
{
string variableName = context.ID().GetText();
int start = Convert.ToInt32(Visit(context.expression(0)));
int end = Convert.ToInt32(Visit(context.expression(1)));
int step = context.expression(2) != null ? Convert.ToInt32(Visit(context.expression(2))) : 1;
for (int i = start; i <= end; i += step)
{
variables[variableName] = i;
var statementListIndex = (i - start) / step; // compute the index of the statement list
var statementList = context.statement_list(statementListIndex);
foreach (var statement in context.statement_list())
{
Visit(statement);
}
}
return null;
}
public override object VisitIfStatement(EasyBiteParser.IfStatementContext context)
{
bool condition = (bool)Visit(context.expression());
if (condition == true)
{
foreach (var statementListContext in context.statement_list())
{
Visit(statementListContext);
}
}
else
{
if (context.elseifStatement() != null)
{
foreach (var elseIfStatementContext in context.elseifStatement())
{
bool elseIfCondition = (bool)Visit(elseIfStatementContext.expression());
if (elseIfCondition)
{
foreach (var statementListContext in elseIfStatementContext.statement_list())
{
Visit(statementListContext);
}
// Stop processing further else-if and else statements
return null;
}
}
}
var elseStatement = context.elseStatement();
if (elseStatement != null)
{
foreach (var statementListContext in elseStatement.statement_list())
{
Visit(statementListContext);
}
return null;
}
}
return null;
}
public object Divide(object left, object right)
{
if (left is int && right is int)
{
return (int)left / (int)right;
}
else if (left is double && right is double)
{
return (double)left / (double)right;
}
else if ((left is double && right is int) || (left is int && right is double))
{
return (double)left / (double)right;
}
else
{
return String.Format("Cant divide {0} by {1}", left, right);
}
}
}
}

And the source code i tried with

generate i from 1 to 50 
if i / 2 == 2 then 
show "Make sense"
else 
show "is not working"
end if     
stop
repeat while(2 > 3) 
show "test" 
showline()
show("")
end repeat

Now this i / 2 == 2 is not working which crashes the interpreter with message of invalid convertion after using debugger i realized it actually calling i name instead of i value.

Thank you.

答案1

得分: 0

明显地,你的 i 是一个 int,当你执行以下操作时:

else if (context.DIV() != null)
{
    double left = (double)VisitExpression(context.expression(0));
    ...
}

将一个 int 强制转换为 double 会导致问题。

如果你尝试:

else if (context.DIV() != null)
{
    int left = (int)VisitExpression(context.expression(0));
    ...
}

也许它会工作。当然,当 i 不是一个 int 时,这会导致问题,但至少你知道问题出在哪里。

编辑

我假设你的 i 是一个 int,因为有以下这段代码:

public override object VisitGenerateStatement(EasyBiteParser.GenerateStatementContext context)
{
    string variableName = context.ID().GetText();
    ...
    for (int i = start; i <= end; i += step)
    {
        variables[variableName] = i; // <-- 作为 `int` 存储
        ...
    }

    return null;
}

然后你像这样检索它:

else if (context.ID() != null)
{
    string id = context.ID().GetText();

    if (variables.ContainsKey(id))
    {
        if (variables[id] is int)
        {
            return (int)variables[id]; // <-- 这必须是情况
        }
        ...
    }
    else
    {
        Console.WriteLine("No variable named {0}", id);
    }
}

如果情况不是这样,你需要用一个完整的可工作示例更新你的问题。这意味着发布一个与你问题中的访问者兼容的完整语法。

英文:

Apparently your i is an int, and when you do:

else if (context.DIV() != null)
{
    double left = (double)VisitExpression(context.expression(0));
    ...
}

the cast of an int to a double breaks things.

If you'd try:

else if (context.DIV() != null)
{
    int left = (int)VisitExpression(context.expression(0));
    ...
}

maybe it'd work. Of course, that will break when i is not an int, but at least you know where to problem lies.

EDIT

I assumed your i is an int because of this:

public override object VisitGenerateStatement(EasyBiteParser.GenerateStatementContext context)
{
    string variableName = context.ID().GetText();
    ...
    for (int i = start; i <= end; i += step)
    {
        variables[variableName] = i; // <-- stored as an `int`
        ...
    }

    return null;
}

and then you retrieve it like this:

else if (context.ID() != null)
{
    string id = context.ID().GetText();

    if (variables.ContainsKey(id))
    {
        if (variables[id] is int)
        {
            return (int)variables[id]; // <-- this must be the case
        }
        ...
    }
    else
    {
        Console.WriteLine("No variable named {0}", id);
    }
}

If that is not the case, you'll need to update your question with a full working example. That means posting a complete grammar that works with the visitor from your question.

huangapple
  • 本文由 发表于 2023年3月10日 01:29:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/75688091.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定