我想编写一个文本语法规则,它可以包含另一个定义的规则或任何类型的标准数据类型(Int,Float,String等)。
这是一个简单的textx DSL,应该有可能包括写入(并在最后翻译)条件,这些条件可以包括其他语法规则(如预定义函数)或任何类型的标准预定义数据类型(String / Int / Float) /布尔/ ID)。
所以,我实际上希望能够编写类似的东西
condition insert input data 5 equal 10 BEGIN
...
END
这代表正常的IF。 insert input data 5
是一个规则,后来被翻译成正常的函数调用insertOutputData(5)
。我在那里使用的语法:
Model: commands*=Command;
Command: Function | Branch;
Function: Func_InsertInputData | Func_InsertOutputData;
Func_InsertInputData: 'insert input data' index=INT;
Func_InsertOutputData: 'insert output data' index=INT;
Branch: 'condition' condition=Condition 'BEGIN'
commands*=Command;
'END'
Condition: Cond_Equal | Cond_And | Cond_False;
Cond_Equal: op1=Operand 'equal' op2=Operand;
Cond_And: op1=Operand 'and' op2=Operand;
Cond_False: op1=Operand 'is false';
Operand: Function | OR_ANY_OTHER_KIND_OF_DATA;
在解释器中,我尝试通过执行以下操作来读取代码:
def translateCommands(cmds):
commands = []
for cmd in cmds:
commands.append(translateCommand(cmd))
return commands
def translateCommand(cmd):
print(cmd)
print(cmd.__class__)
if cmd.__class__.__name__ == 'int' or cmd.__class__.__name__ == 'float':
return str(cmd)
elif cmd.__class__.__name__ == 'str':
return '\'' + cmd + '\''
elif(cmd.__class__.__name__ == 'Branch'):
s = ''
if(cmd.condition.__class__.__name__ == 'Cond_Equal'):
s = 'if ' + translateCommand(cmd.condition.op1) + '==' + translateCommand(cmd.condition.op2) + ':'
if(cmd.condition.__class__.__name__ == 'Cond_And'):
s = 'if ' + translateCommand(cmd.condition.op1) + 'and' + translateCommand(cmd.condition.op2) + ':'
# ...
commandsInBlock = translateCommands(cmd.commands)
for command in commandsInBlock:
s += '\n '+command
return s
在OR ANY OTHER KIND OF DATA
,我尝试列出实际的数据类型,但这不起作用。如果我使用Function | FLOAT | INT | BOOL | ID | STRING
作为操作数规则处理上面显示的DSL代码的模型,则整数(示例中等于10后的整数)将转换为浮点数
if insertInputData(5)==10.0:
如果我使用像Function | INT | FLOAT | BOOL | ID | STRING
这样的操作数规则处理模型,我会收到错误
textx.exceptions.TextXSyntaxError: None:13:43: error: Expected 'BEGIN' at position (13, 43) => 't equal 10*.0 BEGIN '.
我希望看到的结果是
if insertInputData(5)==10:
要么
if insertInputData(5)==10.0:
同
condition insert input data 5 equal 10.0 BEGIN
...
END
但是textx似乎总是试图将它在该位置获得的值转换为操作数规则中的建议类型,这在这种情况下是不好的。我如何修改我的规则,以便它适当地检测每种数据类型而不修改任何内容?
IgorDejanović刚刚描述了这个问题,我按照他给出的方法。
语法(相关部分):
Command: Function | Branch | MyNumber;
#...
Oparand: Function | MyNumber | BOOL | ID | STRING;
MyNumber: STRICTFLOAT | INT;
STRICTFLOAT: /[+-]?(((\d+\.(\d*)?|\.\d+)([eE][+-]?\d+)?)|((\d+)([eE][+-]?\d+)))(?<=[\w\.])(?![\w\.])/;
码:
mm = metamodel_from_str(grammar)
mm.register_obj_processors({'STRICTFLOAT': lambda x: float(x)})
dsl_code = '''
10
10.5
'''
model = mm.model_from_str(dsl_code)
commands = iterateThroughCommands(model.commands)
这导致了
10
<class 'int'>
'10.5'
<class 'str'>
所以,有一些东西缺少使对象处理器工作......
问题是每个有效整数都可以解释为FLOAT
,所以如果你将你的规则命名为FLOAT | INT |...
,你会得到一个float
类型,因为FLOAT
规则会匹配,但是如果你将规则命令为INT | FLOAT|...
for float number,解析器将使用该数字的一部分直到.
和解析不会继续。
这在textX的开发版本(请参阅CHANGELOG.md)中通过引入STRICTFLOAT
规则来解决,该规则永远不会匹配整数,并且内置的NUMBER
规则被更改为首先尝试匹配STRICTFLOAT
然后INT
。
下一个版本将是2.0.0
,并且即将在未来几周发生,我希望如此。同时你可以直接从github安装或修改你的语法来得到这样的东西:
MyNumber: STRICTFLOAT | INT;
STRICTFLOAT: /[+-]?(((\d+\.(\d*)?|\.\d+)([eE][+-]?\d+)?)|((\d+)([eE][+-]?\d+)))(?<=[\w\.])(?![\w\.])/; // or the float format you prefer
并注册object processor为您的STRICTFLOAT
类型,将转换为Python float
。升级到textX 2.0.0后,您应该在语法中用MyNumber
替换对NUMBER
的引用。
更多信息可以在the reported issue找到
编辑1:
由于报告的here错误,建议的解决方案目前无法正常工作
编辑2:
该错误已在开发版本中修复。在2.0.0发布之前,你必须这样做
pip install https://github.com/textX/textX/archive/master.zip
然后,如果您不想更改默认类型,则根本不需要解决方法。