Fixed mysterious 'unknown conflict' error

This commit is contained in:
David Beazley 2019-04-09 17:10:00 -05:00
parent a728a23adf
commit 5bf4d9707d
3 changed files with 47 additions and 29 deletions

View File

@ -1,5 +1,10 @@
Version 0.4
-----------
04/09/2019 Minor refinement to the reporting of reduce/reduce conflicts.
If a top grammar rule wasn't specified, SLY could fail with
a mysterious "unknown conflict" exception. This should be
fixed.
11/18/2018 Various usability fixes observed from last compilers course.
- Errors encountered during grammar construction are now

View File

@ -11,52 +11,65 @@ import enum
from collections import defaultdict
import json
# ------------------------------------------------------------
# Low level encoding of values
def encode_unsigned(value):
'''
Produce an LEB128 encoded unsigned integer.
'''
bits = bin(value)[2:]
if len(bits) % 7:
bits = '0'*(7 - len(bits) % 7) + bits
parts = [ bits[i:i+7] for i in range(0,len(bits), 7) ]
parts = [ parts[0], *['1'+p for p in parts[1:]] ]
parts = [ int(p, 2) for p in parts ]
return bytes(parts[::-1])
assert encode_unsigned(624485) == bytes([0xe5, 0x8e, 0x26])
parts = []
while value:
parts.append((value & 0x7f) | 0x80)
value >>= 7
if not parts:
parts.append(0)
parts[-1] &= 0x7f
return bytes(parts)
def encode_signed(value):
'''
Produce a LEB128 encoded signed integer.
'''
if value > 0:
return encode_unsigned(value)
bits = bin(~(~0 << value.bit_length()) & value)[2:]
bits = '1'+ '0'*(value.bit_length() - len(bits)) + bits
if len(bits) % 7:
bits = '1'*(7 - len(bits) % 7) + bits
return encode_unsigned(int(bits,2))
parts = [ ]
if value < 0:
# Sign extend the value up to a multiple of 7 bits
value = (1 << (value.bit_length() + (7 - value.bit_length() % 7))) + value
negative = True
else:
negative = False
while value:
parts.append((value & 0x7f) | 0x80)
value >>= 7
if not parts or (not negative and parts[-1] & 0x40):
parts.append(0)
parts[-1] &= 0x7f
return bytes(parts)
assert encode_unsigned(624485) == bytes([0xe5, 0x8e, 0x26])
assert encode_unsigned(127) == bytes([0x7f])
assert encode_signed(-624485) == bytes([0x9b, 0xf1, 0x59])
assert encode_signed(127) == bytes([0xff, 0x00])
def encode_float64(value):
def encode_f64(value):
'''
Encode a 64-bit floating point as little endian
'''
return struct.pack('<d', value)
def encode_float32(value):
def encode_f32(value):
'''
Encode a 32-bit floating point as little endian.
'''
return struct.pack('<f', value)
def encode_name(value):
'''
Encode a name as UTF-8
'''
data = value.encode('utf-8')
return encode_vector(list(data[i:i+1] for i in range(len(data))))
return encode_vector(data)
def encode_vector(items):
'''
Items is a list of encoded values
Items is a list of encoded value or bytess
'''
if isinstance(items, bytes):
return encode_unsigned(len(items)) + items
@ -409,13 +422,13 @@ class F32OpBuilder(OpBuilder):
_optable = f32
def const(self, value):
self._append([self._optable.const, *encode_float32(value)])
self._append([self._optable.const, *encode_f32(value)])
class F64OpBuilder(OpBuilder):
_optable = f64
def const(self, value):
self._append([self._optable.const, *encode_float64(value)])
self._append([self._optable.const, *encode_f64(value)])
def _flatten(instr):
for x in instr:

View File

@ -1414,7 +1414,7 @@ class LRTable(object):
if not rlevel:
descrip.append(f' ! shift/reduce conflict for {a} resolved as shift')
self.sr_conflicts.append((st, a, 'shift'))
elif r < 0:
elif r <= 0:
# Reduce/reduce conflict. In this case, we favor the rule
# that was defined first in the grammar file
oldp = Productions[-r]
@ -1451,7 +1451,7 @@ class LRTable(object):
if r > 0:
if r != j:
raise LALRError(f'Shift/shift conflict in state {st}')
elif r < 0:
elif r <= 0:
# Do a precedence check.
# - if precedence of reduce rule is higher, we reduce.
# - if precedence of reduce is same and left assoc, we reduce.