关键字:progress 4GL IO language 开发 语言
1.过程调用
上一篇文章里简单提到调用一个内部的子过程只需要 run procedure-name(parameters). 并且子过程是不要预先声明的。
一个progress文件可以保存为.p结尾,表示是一个procedure文件。
简单地,你可以在命令行模式下:
prowin32 -p my.p
如果你的子过程比较大,或者需要反复调用,这时候你不可能每次在你的主程序里定义它,怎么办呢,可以把一个子过程存储为一个单独的.p文件,
调用的时候采用:
run 相对路径/my_subproc.p(parameters)
如果my_subproc.p和你的主程序在同一目录下,并且主程序所在目录为当前工作目录,则可以直接run my_subproc.p. 如果它是在一个子目录下,比如MySubs.目录结构如下:
main.p
MySubs/
MySubs/my_subproc.p
那么你可以run MySubs/my_subproc.p(parameters). 这里的路径分隔符之所以使用/而不是/是为了让其也可以在unix环境中运行。
下面具个例子,这些例子都存储在和主程序同目录:
/* 文件名:proc1.p */
/*注释是使用 “/*你的注释*/" 来注明的,并且可以嵌套*/
define input parameter p1 as int no-undo.
define input parameter p2 as int no-undo.
define output parameter sum as int no-undo.
sum = p1 + p2.
/*main.p*/
define variable mi as int no-undo.
run pro1.p(1,2,output mi).
message mi. /*mi = 3*/
注意:
如果输入参数类型是input,则在调用是实参可以省略。但是如果是input-output或者output是不可以省略的。
那么如果是函数怎么办呢?不要紧,好友另外一种文件类型 .i文件。
.i文件是一个include文件。比如说有一个 init.i:
define variable l_i as int no-undo.
function msum return int (input p1 as int,input p2 as int):
return p1 + p2.
end function.
procedure showint:
define input parameter pi as int no-undo.
message pi.
end procedure.
则在你的主程序文件里可以这样引用它 {init.i}. 这样就相当于在这个地方定义了变量l_i和函数以及子过程。这一点有点像c语言里的宏定义。
比如main.p:
{init.i}
l_i = msum(1,2).
run showint(l_i).
这个完全等价与main2.p
define variable l_i as int no-undo.
function msum return int (input p1 as int,input p2 as int):
return p1 + p2.
end function.
procedure showint:
define input parameter pi as int no-undo.
message pi.
end procedure.
l_i = msum(1,2).
run showint(l_i).
2.高级过程调用
有的时候你所使用的外部过程要使用中间变量,比如说引用参数;或者一系列的过程具有要共同完成一个任务,怎么办呢?
不要紧,你可以把这一系列的变量,过程还有函数都写在一个.p文件里。不过呢,要先说明一下几个关键字。
run前面说过了是用来调用过程的,现在在介绍它更多的属性。
run { proc_name | value(proc_name) } persistent set proc-handle (parameter1,parameter2,...,parametern).
run { proc_name | value(proc_name) } in proc-handle.
proc_name可以直接是过程的名字,也可以是一个字符串表达式, 比如 run my.p. 就等价于 run value("my.p").这个好处接下来再讲。
persistent表明你所调用的外部过程(这个属性只对外部过程调用有效,内部子过程无效)会一直存在,你若想要再次引用它内部的其他子过程时,就可以使用句柄proc-handle并且采用第二种方法.
dynamic-function("func-name" in proc-handle, param1,param2,...)是用来调用持久过程的内部函数的。
现在我们有一个外部过程文件mysubs.p,它包含了一个子过程,一个子函数:
/*----------------------------------------------------*/
define input parameter pi as int no-undo.
define variable li as int no-undo.
li = pi.
MESSAGE li.
procedure add1:
li = li + 1.
end procedure.
function multi return int(input p1 as int):
return li * p1.
end function.
/*-----------------------------------------------------------*/
当你要调用的时候,可以用如下方法main3.p:
define variable h1 as handle no-undo.
run mysubs.p persistent set h1(2). /*注意,这个时候mysubs.p中的li已经被初始化为2了*/
define variable mi as int no-undo.
mi = dynamic-function("multi" in h1,3). /*调用*/
MESSAGE mi . /*mi = 6 = 2*3 */
run add1 in h1. /*li = 3*/
mi = dynamic-function("multi" in h1,3).
MESSAGE mi. /*mi = 6*/
delete procedure h1. /*使用完删除对象释放内存*/
3.高级过程调用(续)
上面讲到了调用的时候过程名可以是一个字符串表达式。我想因为没有函数指针之类的东西,这样子可以近似的代替函数指针吧。
define variable func-names as char extent 3. /*定义了一个维数为3的字符串数组*/
func-names[1] = "addd".
func-names[2] = "minus".
func-names[3] = "product".
function addd return int (input p1 as int, input p2 as int):
return p1 + p2.
end function.
function minus return int (input p1 as int, input p2 as int):
return p1 - p2.
end function.
function product return int (input p1 as int, input p2 as int):
return p1 * p2.
end function.
define variable i as int no-undo.
do i = 1 to 3:
message dynamic-function(func-names[i],1,2).
end.
func-names[1] = "proc1".
func-names[2] = "proc2".
func-names[3] = "proc3".
procedure proc1:
message 1.
end procedure.
procedure proc2:
message 2.
end procedure.
procedure proc3:
message 3.
end procedure.
do i = 1 to 3:
run value(func-names[i]).
end.
/*----------------------------------------------*/
另外一个大大的好处就是你可以直接把一个过程的名字作为参数传送进来,当然前提是这个文件存在。 c语言的解决方法是把过程或者函数写在一个dll文件里,通过loadlibrary和getProcAddress实现。比如你可以在数据库中存储被调用过程的名字,对不同的客户开发不同的程序,设置不同的名字即可。
当然你说也可以用select(vb用)或者switch(c/c++/java用),不过一旦编译之后就不能添加新的了吧。
4.全局变量
progress的全局变量的定义是这样的:
define [[new [global]] shared] variable g_my_Variable as dataType no-undo.
不带global参数的称谓局部共享变量。两者的区别是,局部共享变量可以被被调用程序访问,并且可以继承。
比如p1.p定义了define new shared variable mshare as char no-undo. 接着p1.p调用了p2.p,p2.p又调用了p3.p,那么在p2.p和p3.p里都是可以访问到mshare的。
全局共享变量的不同之处在于,如果定义一个全局共享变量在p2.p,p1.p在调用p2.p之后调用p4.p,那么p4.p是仍然可以访问全局共享变量的,即使创建它的程序p2.p已经结束了。为什么呢,是因为它存在于全局共享内存里。所以一旦创建,它就一直在那里,直到整个应用程序结束。
p1.p
/*----------------------------------------------*/
define new shared variable mshare as char.
mshare = "shared".
run p2.p.
run p4.p.
p2.p
/*---------------------------------------------*/
define new global shared gvar as char.
define shared variable mshare as char. /*你需要声明这个共享变量*/
gvar = "global".
message mshare + " in p2.p".
p3.p
/*----------------------------------------------*/
define shared variable mshare as char.
define shared variable gvar as char.
message mshare + " in p3.p" + gvar + " in p3.p".
p4.p
/*-----------------------------------------------*/
define shared variable gvar as char.
message gvar + " in p4.p".