IF and WHILE now take single operator
This commit is contained in:
parent
3d6f786949
commit
afc340d52d
3 changed files with 78 additions and 64 deletions
|
|
@ -176,7 +176,7 @@ func (cg *comparisonGenerator) cmpOperand(op *operandInfo, offset int) string {
|
|||
// tempLabel creates and returns a temporary label
|
||||
func (cg *comparisonGenerator) tempLabel() string {
|
||||
label := cg.generalStack.Push()
|
||||
cg.generalStack.Pop()
|
||||
_, _ = cg.generalStack.Pop()
|
||||
return label
|
||||
}
|
||||
|
||||
|
|
@ -633,3 +633,23 @@ func inferKindFromValue(val uint16) compiler.VarKind {
|
|||
}
|
||||
return compiler.KindWord
|
||||
}
|
||||
|
||||
// parseOperator converts string operator to comparisonOp
|
||||
func parseOperator(op string) (comparisonOp, error) {
|
||||
switch op {
|
||||
case "=", "==":
|
||||
return opEqual, nil
|
||||
case "<>", "!=":
|
||||
return opNotEqual, nil
|
||||
case ">":
|
||||
return opGreater, nil
|
||||
case "<":
|
||||
return opLess, nil
|
||||
case ">=":
|
||||
return opGreaterEqual, nil
|
||||
case "<=":
|
||||
return opLessEqual, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unsupported operator %q", op)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,12 @@ func (c *IfCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
return err
|
||||
}
|
||||
|
||||
if len(params) != 4 {
|
||||
return fmt.Errorf("IF: expected 4 parameters, got %d", len(params))
|
||||
// IF <param1> or IF <param1> <op> <param2> [THEN]
|
||||
if len(params) < 2 {
|
||||
return fmt.Errorf("IF: expected at least 2 parameters, got %d", len(params))
|
||||
}
|
||||
|
||||
c.operator = normalizeOperator(params[2])
|
||||
scope := ctx.CurrentScope()
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
|
|
@ -62,17 +61,31 @@ func (c *IfCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
isVar: isVar,
|
||||
}
|
||||
|
||||
// Parse param2
|
||||
varName, varKind, value, isVar, err = compiler.ParseOperandParam(
|
||||
params[3], ctx.SymbolTable, scope, constLookup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("IF: param2: %w", err)
|
||||
}
|
||||
c.param2 = &operandInfo{
|
||||
varName: varName,
|
||||
varKind: varKind,
|
||||
value: value,
|
||||
isVar: isVar,
|
||||
// Single param: IF <param1>
|
||||
if len(params) == 2 || (len(params) == 3 && strings.ToUpper(params[2]) == "THEN") {
|
||||
c.operator = "!="
|
||||
c.param2 = nil
|
||||
} else {
|
||||
// Full comparison: IF <param1> <op> <param2> [THEN]
|
||||
if len(params) == 5 && strings.ToUpper(params[4]) != "THEN" {
|
||||
return fmt.Errorf("IF: expected THEN when 5 parameters, got %s", params[4])
|
||||
} else if len(params) != 4 && len(params) != 5 {
|
||||
return fmt.Errorf("IF: expected 2, 3, 4, or 5 parameters, got %d", len(params))
|
||||
}
|
||||
|
||||
c.operator = params[2]
|
||||
// Parse param2
|
||||
varName, varKind, value, isVar, err = compiler.ParseOperandParam(
|
||||
params[3], ctx.SymbolTable, scope, constLookup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("IF: param2: %w", err)
|
||||
}
|
||||
c.param2 = &operandInfo{
|
||||
varName: varName,
|
||||
varKind: varKind,
|
||||
value: value,
|
||||
isVar: isVar,
|
||||
}
|
||||
}
|
||||
|
||||
// Check pragma
|
||||
|
|
@ -80,7 +93,7 @@ func (c *IfCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContext)
|
|||
longJumpPragma := ps.GetPragma("_P_USE_LONG_JUMP")
|
||||
c.useLongJump = longJumpPragma != "" && longJumpPragma != "0"
|
||||
|
||||
// Create skip label (jumps here on FALSE, or to ELSE if present)
|
||||
// Create skip label
|
||||
c.skipLabel = ctx.IfStack.Push()
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -35,13 +35,12 @@ func (c *WhileCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
|||
return err
|
||||
}
|
||||
|
||||
if len(params) != 4 {
|
||||
return fmt.Errorf("WHILE: expected 4 parameters, got %d", len(params))
|
||||
// WHILE <param1> or WHILE <param1> <op> <param2> [DO]
|
||||
if len(params) < 2 {
|
||||
return fmt.Errorf("WHILE: expected at least 2 parameters, got %d", len(params))
|
||||
}
|
||||
|
||||
c.operator = normalizeOperator(params[2])
|
||||
scope := ctx.CurrentScope()
|
||||
|
||||
constLookup := func(name string) (int64, bool) {
|
||||
sym := ctx.SymbolTable.Lookup(name, scope)
|
||||
if sym != nil && sym.IsConst() {
|
||||
|
|
@ -63,17 +62,31 @@ func (c *WhileCommand) Interpret(line preproc.Line, ctx *compiler.CompilerContex
|
|||
isVar: isVar,
|
||||
}
|
||||
|
||||
// Parse param2
|
||||
varName, varKind, value, isVar, err = compiler.ParseOperandParam(
|
||||
params[3], ctx.SymbolTable, scope, constLookup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("WHILE: param2: %w", err)
|
||||
}
|
||||
c.param2 = &operandInfo{
|
||||
varName: varName,
|
||||
varKind: varKind,
|
||||
value: value,
|
||||
isVar: isVar,
|
||||
// Single param: WHILE <param1>
|
||||
if len(params) == 2 || (len(params) == 3 && strings.ToUpper(params[2]) == "DO") {
|
||||
c.operator = "!="
|
||||
c.param2 = nil
|
||||
} else {
|
||||
// Full comparison: WHILE <param1> <op> <param2> [DO]
|
||||
if len(params) == 5 && strings.ToUpper(params[4]) != "DO" {
|
||||
return fmt.Errorf("WHILE: expected DO when 5 parameters, got %s", params[4])
|
||||
} else if len(params) != 4 && len(params) != 5 {
|
||||
return fmt.Errorf("WHILE: expected 2, 3, 4, or 5 parameters, got %d", len(params))
|
||||
}
|
||||
|
||||
c.operator = params[2]
|
||||
// Parse param2
|
||||
varName, varKind, value, isVar, err = compiler.ParseOperandParam(
|
||||
params[3], ctx.SymbolTable, scope, constLookup)
|
||||
if err != nil {
|
||||
return fmt.Errorf("WHILE: param2: %w", err)
|
||||
}
|
||||
c.param2 = &operandInfo{
|
||||
varName: varName,
|
||||
varKind: varKind,
|
||||
value: value,
|
||||
isVar: isVar,
|
||||
}
|
||||
}
|
||||
|
||||
// Check pragma
|
||||
|
|
@ -118,35 +131,3 @@ func (c *WhileCommand) Generate(ctx *compiler.CompilerContext) ([]string, error)
|
|||
asm = append(asm, cmpAsm...)
|
||||
return asm, nil
|
||||
}
|
||||
|
||||
// normalizeOperator converts operator variants to canonical form
|
||||
func normalizeOperator(op string) string {
|
||||
switch op {
|
||||
case "==":
|
||||
return "="
|
||||
case "!=":
|
||||
return "<>"
|
||||
default:
|
||||
return op
|
||||
}
|
||||
}
|
||||
|
||||
// parseOperator converts string operator to comparisonOp
|
||||
func parseOperator(op string) (comparisonOp, error) {
|
||||
switch op {
|
||||
case "=":
|
||||
return opEqual, nil
|
||||
case "<>":
|
||||
return opNotEqual, nil
|
||||
case ">":
|
||||
return opGreater, nil
|
||||
case "<":
|
||||
return opLess, nil
|
||||
case ">=":
|
||||
return opGreaterEqual, nil
|
||||
case "<=":
|
||||
return opLessEqual, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("unsupported operator %q", op)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue