我正在创建一个布尔逻辑模拟器。我发布了一个关于应用程序的组织和一般设置的问题,它位于此处: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 )
希望这很清楚。如果问题是什么或我正在尝试做什么,请告诉我。提前谢谢。
答案 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)。