使用ANTLR构建PowerScript语法分析器(4)

Posted by dohkoos on April 27th, 2008 (831 views)

什么是表达式
简单的来说,表达式就是操作数和操作符根据语法规则结合后的结果,它通常被用来执行在变量或值上的操作处理。

主表达式(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

Posted by dohkoos on April 26th, 2008 (630 views)

在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)

Posted by dohkoos on September 7th, 2007 (575 views)

转义字符(Special ASCII Characters)
PowerScript中转义字符是以波浪号(~)开头。下图是PowerScript支持的完整的转义字符,#字符表示数字。Decimal由三个十进制数组成,范围是000-255;Hexadecimal由两个十六进制数组成,范围是00-FF;Octal由三个八进制数组成,范围是000-377。

Special ASCII Characters

注意:#表示数字是必须的。比如,必须用~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)

Posted by dohkoos on September 3rd, 2007 (529 views)

在前篇文中写的词法分析文件存在有两个小问题:
1. 处理换行符和回车符的词法定义有重复,在WS和EndOfLine中都有出现
2. 像/* comments /* nested comments */ */这种嵌套注释会被输出成

antlr 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)

Posted by dohkoos on August 23rd, 2007 (776 views)

首先,让我们从最简单的做起,先实现一个能正确分析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
    ;

Related Posts

People who read this, also read...