使用ANTLR构建PowerScript语法分析器(4)
什么是表达式
简单的来说,表达式就是操作数和操作符根据语法规则结合后的结果,它通常被用来执行在变量或值上的操作处理。
主表达式(Primary Expression)
到现在PowerScript的词法分析已经写的差不多了,接下来就要开始写语法分析。语法分析的主要组成部分是表达式(expression),而表达式的主要组成部分则是主表达式。主表达式包含了大部分简单的表达式,如文字量(Literals),字段存取,方法调用和数组存取等。带圆括号的表达式通常也被认为是主表达式。其常见形式如下:
(x) x.y f(x) a[x] x++ x-- new
super,parent,this分析
什么时候使用super
当直接子类中存在有和父类相同签名的事件或函数时
使用super有哪些限制
1. 不能调用父类中控件的脚本 (猜测super后只能跟随"::"符号)
2. 只能在直接子类的函数或事件中调用父类的事件或函数
在哪些脚本中可以使用parent
1. 窗口中的控件,此时parent指代包含该控件的窗口
2. 定制的用户对象中的控件,这时parent指代定制的用户对象
3. 菜单,这时候parent指代该菜单的上一级菜单
收集的一些script语句
this.ls_array[1] this.event pfc_addrow() this.event rowfocuschanged(ll_row) this.uo_1.function hallo() post function column_order_update_from_grid() event ue_process() close(parent) parent.enabled parent.hide() parent.event ue_postconstructor() parent.function static trigger wf_process( ) super::create super::clicked; super::event clicked() super::event clicked(xpos, ypos, row, dwo) super::of_remove_tail(anv_tailnode) super::event trigger selectionchanging(oldindex, newindex) iu_tab_postings.post of_enable_sort(dw_main, dw_detail, false) w_main.event doubleclicked(flags, xpos, ypos) dw_main.event pfc_retrieve() cb_ok.event trigger clicked() cb_ok.triggerevent(clicked!)
主表达式语法,还需要再继续完善
primary_expression
: '(' expression ')'
| IDENTIFIER '!'? // build-in constant
| literal
| '::' IDENTIFIER // global variables
| call_type IDENTIFIER arguments // example: post function to_string()
| 'create' 'using'? (STRING_LITERAL|IDENTIFIER)
| 'destroy' IDENTIFIER
| 'super' '::' call_type? IDENTIFIER arguments?
| objectname ('.' IDENTIFIER)* identifier_suffix?
;
objectname
: 'this'
| 'parent'
| IDENTIFIER
;
call_type
: ( 'function'
| 'event'
| 'static'
| 'dynamic'
| 'trigger'
| 'post'
)+
;
identifier_suffix
: arguments ('.' IDENTIFIER arguments)* // cascaded calling
| '[' expression_list? ']'
| call_type IDENTIFIER arguments
;
arguments
: '(' expression_list? ')'
;
literal
: STRING_LITERAL
| INTEGER_LITERAL
| FLOAT_LITERAL
| BOOLEAN_LITERAL
;
Related Posts
People who read this, also read...
Cannot launch the remote parser because port 49153 is already in use
在Windows Server 2008使用AntlrWorks调试语法文件时,总是提示说什么端口49153已被占用。使用netstat -an发现这个端口正在被别的进程监听着,虽然知道问题原因,但是不知道如何去解决。后来从《如果AntlrWorks的Debug报错"当前端口已被占用",可能是防火墙的原因》得到了启示:AntlrWorks是可以修改远程调试端口的。不过我没有像该文作者介绍的那样将调试端口改成49253,因为那样可能需要设置防火墙。而是直接将之设置到了一个不在使用的端口49151上。
设置调试端口的路径如下:
File -> Preferences -> Debugger -> Default local port
Related Posts
People who read this, also read...
使用ANTLR构建PowerScript语法分析器(3)
转义字符(Special ASCII Characters)
PowerScript中转义字符是以波浪号(~)开头。下图是PowerScript支持的完整的转义字符,#字符表示数字。Decimal由三个十进制数组成,范围是000-255;Hexadecimal由两个十六进制数组成,范围是00-FF;Octal由三个八进制数组成,范围是000-377。

注意:#表示数字是必须的。比如,必须用~007这种样式来表示转义字符,而不能是~7这种样式。
这里是转义字符的词法代码
ESCAPE
: '~' ('n'|'t'|'v'|'r'|'f'|'b'|'\"'|'\''|'~')
| DecimalEscape
| HexEscape
| OctalEscape
;
fragment
DecimalEscape
: '~' ('0'..'1') ('0'..'9') ('0'..'9') // 000 - 199
| '~' '2' ('0'..'5') ('0'..'5') // 200 - 255
;
fragment
HexEscape
: '~h' ('0'..'9'|'a'..'f'|'A'..'F') ('0'..'9'|'a'..'f'|'A'..'F') // 00 - FF
;
fragment
OctalEscape
: '~o' ('0'..'3') ('0'..'7') ('0'..'7') // 000 - 377
;
续行(Statement Continuation)
通常情况下,PowerScript的一条语句书写在一行上,语句书写完毕后,按Enter键转到下一行,开始下一条语句。有时候,为了阅读方便等原因,需要把一条语句书写在几行上,这时就需要使用续行符了。PowerScript的续行符是&字符,它放在一行的末尾指示下一行是当前行的继续,并且续行符必须是一行的最后一个字符。
CONTINUEDLINE
: '&' NEWLINE
;
字符和字符串常量(Character and String Literal)
PowerScript程序中字符和字符串文字常量没有明显的区别。字符文字常量是指由单引号(')或双引号(")括起来的一个ASCII字符,例如:
char c
c = 'T'
c = "T"
字符串文字常量则是指由单引号(')或双引号(")括起来的不多于1024个的ASCII字符,例如:
string s
s = 'This is a string'
s = "This is a string"
由于两者没有明显区别,因此在词法分析阶段只能将两者都作为字符串文字常量来处理。至于到底是字符还是字符串文字常量,只有到了语意分析阶段才能作出判断(字符串文字常量支持续行符)。
STRING_LITERAL
: ( '\'' (ESCAPE|CONTINUEDLINE|~('~'|'r'|'n'|'\''))* '\''
| '\"' (ESCAPE|CONTINUEDLINE|~('~'|'r'|'n'|'\"'))* '\"'
)
{
System.out.println("string>" + getText());
}
;
数字和布尔常量(Numeric and Boolean Literal)
INTEGER_LITERAL
: ('0'|'1'..'9' ('0'..'9')*)
;
FLOAT_LITERAL
: ('0'..'9')+ '.' ('0'..'9')* Exponent?
| '.' ('0'..'9')+ Exponent?
| ('0'..'9')+ Exponent?
;
BOOLEAN_LITERAL
: ('true'|'false')
;
fragment
Exponent
: ('e'|'E') ('+'|'-')? ('0'..'9')+
;
标识符(Identifier)
标识符规则可以参看《PowerBuilder标识符versus Java标识符》一文,以下是标识符的词法代码。
DENTIFIER
: Letter (Letter|'0'..'9'|'$'|'#'|'%')* // 暂时不支持短横线(-)
{
System.out.println("identifier>" + getText());
}
;
fragment
Letter
: ('A'..'Z'|'a'..'z'|'_')
;
问题:PowerScript是否支持变量名的续行?
PowerBuilder V9.0 Build 5507 不支持
PowerBuilder V9.0.1 Build 7171 不支持
PowerBuilder V8.0.3 Build 9704 不支持
Do not split a line by inserting the continuation character within a variable name. This causes an error and the statement fails.
结论:PowerScript不支持变量名的续行。
Related Posts
People who read this, also read...
使用ANTLR构建PowerScript语法分析器(2)
在前篇文中写的词法分析文件存在有两个小问题:
1. 处理换行符和回车符的词法定义有重复,在WS和EndOfLine中都有出现
2. 像/* comments /* nested comments */ */这种嵌套注释会被输出成

第一个问题比较容易解决,只要将EndOfLine前的fragment去掉,再将WS改成下面这样就可以了。
WS
: (' '|'\t'|'\u000C') {$channel=HIDDEN;}
;
第二个问题则可以通过计数器来处理。先初始化一个计数器变量depthOfComments来标记块注释的深度,当遇到'/*'时就加一,遇到'*/'时则减一。输出时只要判断depthOfComments是否等于0就行了。
BLOCK_COMMENT
@init {
int depthOfComments = 0;
}
: '/*' {depthOfComments++;}
( options {greedy=false;}
: ('/' '*')=> BLOCK_COMMENT {depthOfComments++;}
| '/' ~('*')
| ~('/')
)*
'*/' {depthOfComments--;}
{
if (depthOfComments == 0) {
System.out.println("bc>" + getText());
}
}
;
Related Posts
People who read this, also read...
使用ANTLR构建PowerScript语法分析器(1)
首先,让我们从最简单的做起,先实现一个能正确分析PowerScript注释的词法文件。PowerScript支持两种注释形式:单行注释(//)和多行注释(/*...*/)。
单行注释以双斜杠(//)起头,直到遇到行结束符为止,所以在这里要先明确一下行结束符用什么表示。在DOS系统中行结束符用'\r\n'表示,在Unix系统中行结束符用'\n'表示,现在的Mac系统也是以'\n'表示行结束符,但早期的Mac系统中行结束符则是以'\r'表示。所以兼容这几种操作系统的行结束符定义为:
fragment
EndOfLine
: '\r' '\n' // DOS
| '\r' // Mac
| '\n' // Unix
;
现在,有了行结束符定义,就可以定义单行注释的词法规则了:
LINE_COMMENT
: '//' ~('\n'|'\r')* EndOfLine
;
通常的多行注释词法规则是这样的
BLOCK_COMMENT
: '/*' ( options {greedy=false;} : . )* '*/'
;
但由于PowerScript支持嵌套注释,所以上面的规则无效,必须重新定义。当词法分析器遇到'/*'后就进入了多行注释。这时假如遇到了'/'符号,词法分析器必须预取一个字符,看这个字符是否是'*'。如果是的话,就进入了嵌套的多行注释,否则,则还是处在多行注释中。
BLOCK_COMMENT
: '/*'
( options {greedy=false;}
: ('/' '*')=> BLOCK_COMMENT // 在多行注释中遇到'/*',用语法断言确定是嵌套多行注释
| '/' ~('*') // 在多行注释中只遇到'/',而没有紧跟着的'*'
| ~('/') // 在多行注释中没有遇到'/'
)*
'*/'
;
当然,我们还希望忽略空格、制表符、回车符、换行符等无意义字符。
WS
: (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
;
测试样例
/* This is a single-line comment. */ /* /This is a single-line comment. */ /* *This is a single-line comment. */ /* This comment /* */*/ /* This comment /* The nested comment */ */ /* This comment starts here. /* This is the start of a nested comment. The nested comment ends here. */ The first comment ends here. */ /* This comment starts here, continues to this line,& and finally ends here. */ // This entire line is a comment. // This entire line is a comment. // // /This entire line is a comment. // /This entire line is a comment. // This entire line is a comment. */ // This entire line is a comment. /*
语法文件PowerScript.g的内容如下:
grammar PowerScript;
program
: LINE_COMMENT+
| BLOCK_COMMENT+
;
LINE_COMMENT
: '//' ~('\n'|'\r')* EndOfLine
{
System.out.println("lc>" + getText());
}
;
BLOCK_COMMENT
: '/*'
( options {greedy=false;}
: ('/' '*')=>; BLOCK_COMMENT
| '/' ~('*')
| ~('/')
)*
'*/'
{
System.out.println("bc>" + getText());
}
;
WS
: (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
;
fragment
EndOfLine
: '\r' '\n' // DOS
| '\r' // Mac
| '\n' // Unix
;

