布尔逻辑模拟器 - StackOverflowError

时间:2011-11-06 04:53:39

标签: java logic boolean stack-overflow simulator

我正在创建一个布尔逻辑模拟器。我发布了一个关于应用程序的组织和一般设置的问题,它位于此处:Organizing Simple Boolean Logic Simulator - Java。我认为这不直接适用于其他问题所以可以单独发布。请原谅我的代码,我是Java的新手。

代码的组织实际上非常简单,但是当我尝试在assign语句中为变量本身分配变量时,我遇到了一个问题。

例如,我们通常会使用这样的语句:

assign input1 * input2 + test3 * input2 to test3;

当input1和input2为高电平时,test3将变为高电平。此时,input1可能会退出,test3仍然会很高,因为它在语句中引用了它自己。 (注意:* => AND,+ => OR)如下所示,当变量在上面的assign语句中引用自身时,我遇到了问题。那是因为当我试图得到上述陈述的价值时,我得到了:

input1 * input2 +(input1 * input2 +(input1 * input2 + test3 * input2)* input2)* input2

等。它只是试图一遍又一遍地评估它的陈述。

public interface Argument {
    public boolean evaluate();
}

这是存储有关每个位的信息的“位”类。该位可以是“硬连线”的真或假,或者可以为其分配一个语句。

public class Bit implements Argument {

    private String name;
    private boolean value;
    private Argument assign;
    private boolean assigned;

    Bit( String name, boolean value ) {
        this.name = name;
        this.value = value;
    }

    @Override
    public boolean evaluate() {
        if ( assigned == true ) {
            return assign.evaluate();
        } else {
            return value;
        }
    }

    public void setValue( boolean value ) {
        this.value = value;
    }

    public void setAssign( Argument assign ) {
        this.assign = assign;
        this.assigned = true;
    }

}

这是Operation类的一个例子;其他人非常相似。

public class OrOperation implements Argument {

    private Argument argument1, argument2;

    public OrOperation( Argument arg1, Argument arg2 ) {
        this.argument1 = arg1;
        this.argument2 = arg2;
    }

    @Override
    public boolean evaluate() {
        return argument1.evaluate() || argument2.evaluate();
    }

}

Parser类:我只包含了部分内容,因为实际解析并不是那么相关。 请注意,当我为自己分配一个变量时会产生错误。在下面的第二个测试中,我将test3分配给test3。我可以推断这是因为test3试图确定自身的值,一遍又一遍地调用第二个语句。

public class Parser {

    public HashMap<String, Bit> bits = new HashMap<String, Bit>();

    Parser(String file) {

        bits.put( "test1", new Bit( "test1", true ) );
        bits.put( "test2", new Bit( "test2", true ) );
        bits.put( "test3", new Bit( "test3", false ) );
        bits.put( "test4", new Bit( "test4", true ) );

        // Works great
        bits.get("test3").setAssign( parseStatement("test1 * ~test2 + test4 * test2") );
        System.out.println( bits.get("test3").evaluate() );

        // Produces error
        bits.get("test3").setAssign( parseStatement("test1 * test2 + test3 * test2") );
        System.out.println( bits.get("test3").evaluate() );

    }
}

解析器基本上创建如下语句:(取自上一个问题)

Operand op = new AndOperand( register1, new OrOperand( register2, register3 );
boolean output = op.evaluate(); // this is register1 && (register2 || register3 )

希望这很清楚。如果问题是什么或我正在尝试做什么,请告诉我。提前谢谢。

2 个答案:

答案 0 :(得分:1)

假设这是一个模拟器/评估器(而不是方程求解器),那么您需要将系统建模为随时间变化的状态。因此,声明:

assign test1 * input1 to test1;

表示test1 t + 1 的状态为test1 t * input1 t

您的代码正在做的是区分test1 t 和test1 t + 1 ...并且因此导致无限递归。

一种解决方案是与方程式分开表示状态(变量的值),并使用不同的数据结构来表示时间t的状态和时间的状态t + 1

答案 1 :(得分:1)

您所描述的是电路中的反馈回路。它们确实存在于现实中,在较低的水平上它们被用于例如对于存储器元件(触发器和锁存器),在更高级别上,您可以将其用于需要确实需要反馈的电路(例如IIR滤波器)。

在这个更高级别的“应用程序”中,您可以在不同(逻辑)操作之间进行注册。 这就是你如何进入你的逻辑循环。然后,您必须根据时间计算结果。

从使用复位值(通常为0)循环的寄存器/输入的内容开始。然后开始计算。您可以在中间的寄存器中中断循环,并通过上一个循环的值中的assign语句计算循环的值。这也意味着即使输入没有改变,输出也可以从时间步长改变。您还可以为每个输出输出一个输出值,但输出顺序(随时间变化)。

另一个选项(我建议你有一个简单的模拟器)是禁止这样的循环并在你识别它时抛出错误信息。

如果这是用于制作,我只能建议:要再次发明轮子。这不是一个新问题。例如有那里有硬件描述语言(例如Verilog或VHDL),其中存在几个模拟器(例如,如果你想要一个免费模拟器,可以来自synopsys或verilator的vcs)。