[ragel-users] -G2 -Z generating an incorrect FSM
Karl Stenerud
kstenerud at gmail.com
Fri Nov 8 00:04:03 EST 2019
I have a ragel machine that generates passing Go code when built with -G1,
but failing code when built with -G2 (using ragel 6.10 on ubuntu).
Given the following machine definition:
-------------------------------------------------------------------------
package safe16l
import (
"fmt"
)
%%{
machine safe16;
access this.;
numeric_hi = [0-9] @{
accumulator = (fc - '0') << 4
};
af_hi = [a-f] @{
accumulator = (fc - 'a' + 10) << 4
};
AF_hi = [A-F] @{
accumulator = (fc - 'A' + 10) << 4
};
numeric_lo = [0-9] @{
accumulator |= fc - '0'
};
af_lo = [a-f] @{
accumulator |= fc - 'a' + 10
};
AF_lo = [A-F] @{
accumulator |= fc - 'A' + 10
};
sequence = space* (numeric_hi | af_hi | AF_hi) space* (numeric_lo |
af_lo | AF_lo) %{
dst[dstIndex] = accumulator
dstIndex++
};
length_nocontinue = [0-7] @{
this.length = this.length << 3 + int(fc - '0')
};
length_numeric = [8-9] @{
this.length = this.length << 3 + int(fc - '0')
};
length_af = [a-f] @{
this.length = this.length << 3 + int(fc - 'a' + 10 - 8)
};
length_AF = [A-F] @{
this.length = this.length << 3 + int(fc - 'A' + 10 - 8)
};
length = (length_numeric | length_af | length_AF)* length_nocontinue;
sequence_counted = sequence %{
fmt.Printf("### End of sequence\n")
this.length--
if this.length == 0 {
this.isComplete = true
fbreak;
}
};
main := length sequence_counted* @/{
err = fmt.Errorf("Incomplete document")
};
}%%
%% write data;
type Parser struct {
cs int // Current Ragel state
data []byte
length int
isComplete bool
}
func (this *Parser) Init() {
}
func NewParser() *Parser {
this := new(Parser)
return this
}
func (this *Parser) Parse(src []byte, dst []byte) (bytesWritten int,
isComplete bool, err error) {
this.data = src
p := 0 // Position: current
pe := len(this.data) // Position: end of buffer
// TODO: Change to -1 and check for end of file
eof := pe // Position: end of file
accumulator := byte(0)
dstIndex := 0
_ = eof
%%{
write init;
write exec;
}%%
if this.cs == safe16_error {
err = fmt.Errorf("Parse error at %v", p)
}
return dstIndex, this.isComplete, err
}
-------------------------------------------------------------------------
And the following test code:
-------------------------------------------------------------------------
package safe16l
import (
"bytes"
"testing"
)
func testSafe16L(t *testing.T, src string, expected []byte) {
dst := make([]byte, len(src))
parser := NewParser()
bytesWritten, isComplete, err := parser.Parse([]byte(src), dst)
if err != nil {
t.Error(err)
}
if !isComplete {
t.Errorf("Sequence [%v]: Incomplete parse", src)
}
actual := dst[:bytesWritten]
if !bytes.Equal(actual, expected) {
t.Errorf("Sequence [%v]: Expected %v but got %v", src, expected,
actual)
}
}
func TestSafe16L(t *testing.T) {
testSafe16L(t, "100", []byte{0x00})
}
-------------------------------------------------------------------------
With G1:
$ ragel -Z -G1 safe16l.rl && go test
### End of sequence
PASS
ok github.com/kstenerud/go-safe16 0.001s
With G2:
$ ragel -Z -G2 safe16l.rl && go test
### End of sequence
--- FAIL: TestSafe16L (0.00s)
parser_test.go:14: Parse error at 4
FAIL
exit status 1
FAIL github.com/kstenerud/go-safe16 0.001s
-------------------------------------------------------------------------
Looking at the generated code, I see this in the -G2 version:
//line safe16l.rl:51
fmt.Printf("### End of sequence\n")
this.length--
if this.length == 0 {
this.isComplete = true
{p++; this.cs = 0; goto _out }
}
I'm not sure why cs would be set to 0 here. This isn't an error state as
far as I can tell...
Cheers,
Karl
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.colm.net/pipermail/ragel-users/attachments/20191108/53e2c0c6/attachment.html>
More information about the ragel-users
mailing list