语法分析器建议 (ANTLR)
Grammar parser suggestion (ANTLR)
好吧,我正在尝试在 Antlr4 上编写一个简单的 QBasic 语法。而 'Else-If' 循环将无法正常工作,它会在 THEN
之后自动转换为 assigncommand
。你能复习一下我的语法吗,有什么改进吗?
如何用正则表达式写 string
。(也用西里尔字母)
我应该写这些关键词吗('PRINT' 'IF'
)?或使用词法分析器(如 ..PRINTKEY; PRINTKEY : 'PRINT'
)
grammar Hello3;
// AssignCommand; MainCommand; FlowCommand
prog : (assigncommand | maincommand | flowcommand)+;
// AssignInt; AssignString
// MyAge = PreviousAge + 1
// MyName$ = FirstName$ + MiddleName$ + LastName$
assigncommand : assignint | assignstring;
assignint : IDINT '=' (IDINT | INT) (OPERATORMATH (IDINT | INT))* '\n'+;
assignstring : IDSTRING '=' (IDSTRING | STRING) ('+' (IDSTRING | STRING))* '\n'+;
//PrintCommand, InputCommand
//PRINT MyName$, MyAge, "Hello", 123
//INPUT "What is your name?", yourname$
//(or)INPUT yourname$
maincommand : printcommand | inputcommand;
printcommand : 'PRINT' (',' (IDINT | IDSTRING | STRING | INT))+ '\n'+;
inputcommand : 'INPUT' (IDINT | IDSTRING | STRING)? ',' (IDINT | IDSTRING) '\n'+;
//If-ElseFlow; WhileFlow
//If-Else-Add; Else-Add
//
//IF a > 3 THEN
//PRINT a
//a = a -1
//ELSE IF a = 1 THEN
//b = a
//END IF
//
//WHILE a > 3
//a = a - 1
//PRINT a
//WEND
flowcommand : ifelseflow | whileflow;
ifelseflow : 'IF' conditionflow 'THEN' '\n' ifelseadd* elseadd* 'END' 'IF' '\n'+;
whileflow : 'WHILE' conditionflow '\n' (assigncommand | maincommand | flowcommand)* 'WEND' '\n'+;
conditionflow : ((INT | IDINT) OPERATORBOOL (INT | IDINT)) | ((STRING | IDSTRING) '=' (STRING | IDSTRING));
ifelseadd : 'ELSEIF' conditionflow 'THEN' '\n' ((assigncommand | maincommand | flowcommand) '\n')+;
elseadd : 'ELSE' '\n' ((assigncommand | maincommand | flowcommand) '\n')+;
//Lexers
INT : [0-9]+;
STRING : '"' [a-zA-Z\u0400-\u04FF[=10=]-9' ''?'':']+ '"';
IDINT : [a-zA-Z]([a-zA-Z0-9]*); //MyAge
IDSTRING : [a-zA-Z]([a-zA-Z0-9]*)'$'; //MyName$
OPERATORMATH : '+'|'-'|'*'|'/';
OPERATORBOOL : '='|'>'|'<'|'>='|'<=';
WS : [ \t\r]+ -> skip;
像你一样,我发现用类似 BASIC 的语言实现 if..else
结构是一个真正的挑战。我在网上找到了一些很好的资源。请看看我的语法片段:
ifstmt
: IF condition_block (ELSE IF condition_block)* (ELSE stmt_block)?
;
condition_block
: expr stmt_block
;
stmt_block
: OBRACE statement+ CBRACE
| statement
;
我的实现(在 C# 访问者模式中):
public override MuValue VisitIfstmt(LISBASICParser.IfstmtContext context)
{
LISBASICParser.Condition_blockContext[] conditions = context.condition_block();
bool evaluatedBlock = false;
foreach (LISBASICParser.Condition_blockContext condition in conditions)
{
MuValue evaluated = Visit(condition.expr());
if (evaluated.AsBoolean())
{
evaluatedBlock = true;
Visit(condition.stmt_block());
break;
}
}
if (!evaluatedBlock && context.stmt_block() != null)
{
Visit(context.stmt_block());
}
return MuValue.Void;
}
我从 Bart Kiers 对他的 Mu
语言的出色实现中借鉴了 MuValue
的想法。他的那个项目中有很多很棒的想法。
好吧,我正在尝试在 Antlr4 上编写一个简单的 QBasic 语法。而 'Else-If' 循环将无法正常工作,它会在 THEN
之后自动转换为 assigncommand
。你能复习一下我的语法吗,有什么改进吗?
如何用正则表达式写 string
。(也用西里尔字母)
我应该写这些关键词吗('PRINT' 'IF'
)?或使用词法分析器(如 ..PRINTKEY; PRINTKEY : 'PRINT'
)
grammar Hello3;
// AssignCommand; MainCommand; FlowCommand
prog : (assigncommand | maincommand | flowcommand)+;
// AssignInt; AssignString
// MyAge = PreviousAge + 1
// MyName$ = FirstName$ + MiddleName$ + LastName$
assigncommand : assignint | assignstring;
assignint : IDINT '=' (IDINT | INT) (OPERATORMATH (IDINT | INT))* '\n'+;
assignstring : IDSTRING '=' (IDSTRING | STRING) ('+' (IDSTRING | STRING))* '\n'+;
//PrintCommand, InputCommand
//PRINT MyName$, MyAge, "Hello", 123
//INPUT "What is your name?", yourname$
//(or)INPUT yourname$
maincommand : printcommand | inputcommand;
printcommand : 'PRINT' (',' (IDINT | IDSTRING | STRING | INT))+ '\n'+;
inputcommand : 'INPUT' (IDINT | IDSTRING | STRING)? ',' (IDINT | IDSTRING) '\n'+;
//If-ElseFlow; WhileFlow
//If-Else-Add; Else-Add
//
//IF a > 3 THEN
//PRINT a
//a = a -1
//ELSE IF a = 1 THEN
//b = a
//END IF
//
//WHILE a > 3
//a = a - 1
//PRINT a
//WEND
flowcommand : ifelseflow | whileflow;
ifelseflow : 'IF' conditionflow 'THEN' '\n' ifelseadd* elseadd* 'END' 'IF' '\n'+;
whileflow : 'WHILE' conditionflow '\n' (assigncommand | maincommand | flowcommand)* 'WEND' '\n'+;
conditionflow : ((INT | IDINT) OPERATORBOOL (INT | IDINT)) | ((STRING | IDSTRING) '=' (STRING | IDSTRING));
ifelseadd : 'ELSEIF' conditionflow 'THEN' '\n' ((assigncommand | maincommand | flowcommand) '\n')+;
elseadd : 'ELSE' '\n' ((assigncommand | maincommand | flowcommand) '\n')+;
//Lexers
INT : [0-9]+;
STRING : '"' [a-zA-Z\u0400-\u04FF[=10=]-9' ''?'':']+ '"';
IDINT : [a-zA-Z]([a-zA-Z0-9]*); //MyAge
IDSTRING : [a-zA-Z]([a-zA-Z0-9]*)'$'; //MyName$
OPERATORMATH : '+'|'-'|'*'|'/';
OPERATORBOOL : '='|'>'|'<'|'>='|'<=';
WS : [ \t\r]+ -> skip;
像你一样,我发现用类似 BASIC 的语言实现 if..else
结构是一个真正的挑战。我在网上找到了一些很好的资源。请看看我的语法片段:
ifstmt
: IF condition_block (ELSE IF condition_block)* (ELSE stmt_block)?
;
condition_block
: expr stmt_block
;
stmt_block
: OBRACE statement+ CBRACE
| statement
;
我的实现(在 C# 访问者模式中):
public override MuValue VisitIfstmt(LISBASICParser.IfstmtContext context)
{
LISBASICParser.Condition_blockContext[] conditions = context.condition_block();
bool evaluatedBlock = false;
foreach (LISBASICParser.Condition_blockContext condition in conditions)
{
MuValue evaluated = Visit(condition.expr());
if (evaluated.AsBoolean())
{
evaluatedBlock = true;
Visit(condition.stmt_block());
break;
}
}
if (!evaluatedBlock && context.stmt_block() != null)
{
Visit(context.stmt_block());
}
return MuValue.Void;
}
我从 Bart Kiers 对他的 Mu
语言的出色实现中借鉴了 MuValue
的想法。他的那个项目中有很多很棒的想法。