MFP编程语言citingspace和using语句:
用户也许已经注意到,从1.7版开始,MFP编程语言和以前有些不同。比如,在以前版本的用户手册中,示例程序的函数名都是以mfpExample_开头,这样避免了mfp手册的示例程序和软件自带的程序或者用户自己定义的程序相互冲突。
从1.7版开始,用户手册的示例程序不再以mfpExample_开头。比如,在上一节中的例子函数的名字,就是简单的testHelp。那么,如果用户自己定义了一个testHelp函数,并且参数个数和例子函数testHelp相同,MFP语言如何区分它们呢?
一个比较好的办法是对名字相同的函数使用不同的引用空间。当且仅当函数的引用空间相同,函数名相同以及参数个数相等,MFP才认为它们是同一函数。比如,从本版开始,示例程序都在mfpexample的引用空间中。在示例源文件的头部均有citingspace ::mfpexample的语句,在示例源文件尾部均有endcs的语句。这就表明,所有的例子程序,都是定义在::mfpexample引用空间内,在其他的引用空间内,即使定义了同名函数,也不会发生冲突。
引用空间本身是一个层级的概念,最上层的引用空间,名字是一个空字符串,如果一个mfps文件中没有定义任何引用空间,MFP语言就会认为该文件中所有的函数均被定义在最上层的引用空间中。
在最上层的引用空间的内部(也就是下一层),用户可以定义另外的引用空间,比如一个名叫mfpexample的引用空间(引用空间名,和函数名一样,不分大小写,所以mfpExample和MFPexample以及mfpexample是等价的)。注意mfpexample虽然是该引用空间的名字,但是,如果用户想找到这个引用空间,必须使用该引用空间的绝对引用路径,绝对引用路径的表示方式是:
最上层引用空间名::下一层引用空间名::再下层引用空间名::...::目标引用空间名
。由于引用空间mfpexample位于最上层引用空间的下一层,所以,它的绝对路径是::mfpexample(注意最上层引用空间的名字是一个空字符串)
用户在执行MFP语言的例子函数时,则需要指出是哪个引用空间,比如以下函数定义在引用空间::mfpexample中:
Function testCS1(a)
print("\nThis is ::mfpexample::testCS1, a=" + a + "\n")
endf
那么,上述函数的调用就应该是::mfpexample::testCS1(a)。换句话说,就是函数的绝对引用路径加上::再加上函数名和函数参数。
用户可能会问,在可编程科学计算器1.6.7及其以前版本中,没有引用空间的概念,函数调用就是函数名加上参数(比如testCS1(a)),那么,可编程科学计算器1.7版如何保证和以前的版本兼容呢?
为了实现兼容的目的,MFP语言中加入了基本引用路径的概念,也就是说,如果一个函数的引用空间位于一条基本引用路径上,那么调用该函数时,不用写明绝对引用路径。
1.7版的MFP语言的基本引用路径为顶层引用空间和mfp引用空间和mfp所有的下级(或者更下级)引用空间。任何函数,如果定义在这些引用空间中,调用的时候不用写明绝对引用路径。
由于在旧版本的可编程科学计算器中,所有的mfps文件都没有定义引用空间,那么,这些mfps文件在新的1.7版中,将自动地被看成使用最顶级引用空间。那么在这些mfps文件中定义的函数,将被认为是最顶级引用空间中的函数,而这些函数的调用是不需要写明绝对引用路径的(当然如果写明,也是可以的)。
比如,用户在旧版的可编程科学计算器中,定义了函数Myf_abc(),并且在其他的函数中调用了Myf_abc。显然,调用的方式就是myf_abc()。在新版本中,由于函数Myf_abc()是定义在最上层引用空间的,所以调用是不需要写明绝对引用路径,所以myf_abc()还是正确的。当然,如果用户在调用时写明绝对引用路径也就是::myf_abc(),也是可以的。
还要注意的是,对于软件自带的函数,在旧版中没有引用空间的概念,在新版软件中,自带函数的引用空间都位于引用空间::mfp的一个子空间(下层或者更下层引用空间)中。比如,函数tan(x),在新版软件中位于引用路径为::mfp::math::trigon的引用空间中,而函数log(x)在新版软件中位于引用路径为::mfp::math::log_exp的引用空间中。无论系统自带的函数位于哪一个引用空间中,它们都是引用空间::mfp的某一个子空间,所以,都是被包括在基本引用路径中,在调用的时候不需要指定引用路径。这样确保了和旧版软件的兼容性。
从2.0版开始,MFP语言加入了对面向对象编程的支持。class语句被引入。class语句和citingspace保持兼容,每一个class就是一个citingspace。每一个class内定义的静态函数可以用上面所给出的使用citingspace引用路径的办法访问。但是,如果不是静态函数,由于需要初始化对象,所以无法通过citingspace引用路径的办法访问。注意,当前class还不支持静态变量,所以变量无法通过citingspace引用路径的办法访问。比如下面的例子:
class ABC
Function f0()
print("\nThis is ::ABC::f0()\n")
endf
Function f1(self)
print("\nThis is ::ABC::f1(self)\n")
Endf
endcs
通过::ABC::f0()调用静态函数f0是合法的,但无法通过::ABC::f1()调用非静态函数f1,原因是f1需要通过类ABC的对象来访问。
除了基本引用路径,用户也可以在基本引用路径之外自定义额外的引用路径。用户定义引用路径需要使用using citingspace语句,该语句指明哪条额外的引用路径还要被使用。比如语句using citingspace ::abcd就是告诉MFP语言除了最高层引用空间和::mfp以及其子引用空间之外还要使用引用路径::abcd。
需要注意的是,在citingspace和using citingspace语句也可以使用相对引用空间。比如在引用空间::mfpexample中,用户又定义了
citingspace Abcd
Function testCS1(a)
print("\nThis is ::mfpexample::abcd::testCS1, a=" + a + "\n")
endf
endcs
那么,引用空间Abcd就是使用的相对引用路径,由于引用空间Abcd定义在::mfpexample中(也就是说::mfpexample是其直接上层引用空间),它的绝对引用路径就是::mfpexample::abcd。
又比如,在引用空间::mfpexample中,用户声明了语句using citingspace abcd,那么由于abcd不是绝对引用路径,MFP语言将使用这条using citingspace语句所在的最内层的引用空间来构析abcd的绝对引用空间,所以,它的绝对引用空间就是::mfpexample::abcd。
还比如,用户在引用空间::mfpexample中的某一个函数中,调用了abcd::testCS(a)函数,假如没有任何using citingspace语句在调用之前被声明,那么这个使用相对引用路径的abcd::testCS(a)的绝对引用路径就应该是::mfpexample::abcd::testCS(a)。
如果用户自己定义了好几层引用空间,并且在引用空间中和一些函数的函数体内部声明了一些using citingspace语句,那么,如果在这些函数中调用其他的函数,MFP语言对引用空间的查访顺序为:
1.函数调用语句所在的直接引用空间(也就是最内层的引用空间);
2.函数调用语句所在的最内层的程序块中的using citingspace所指定的引用空间。注意这些using citingspace语句必须位于函数调用语句的上方,并且越靠近函数调用语句,在进行引用空间搜索时,就具有越高的优先级;
3.函数调用语句所在的外层的程序块中的using citingspace所指定的引用空间,越往外层,using citingspace语句所指定的引用空间的优先级就越低。和第2点类似,这些using citingspace语句必须位于函数调用语句的上方,并且越靠近函数调用语句,在进行引用空间搜索时,就具有越高的优先级;
4.函数调用语句所在的直接引用空间内但是在函数体外的using citingspace所指定的引用空间。请注意些using citingspace语句必须位于函数调用语句的上方,并且越靠近函数调用语句,在进行引用空间搜索时,就具有越高的优先级;
5.函数调用语句所在的非直接引用空间(也就是包含最内层引用空间的上层或者更上层引用空间,直到最顶层引用空间)和在非直接引用空间内的using citingspace语句所指定的引用空间。注意,在这里,这些引用空间的优先级是非直接引用空间 > 该非直接引用空间中的using citingspace语句所指定的引用空间 > 更上层的非直接引用空间 > 更上层的非直接引用空间中的using citingspace语句所指定的引用空间...。比如,假如用户在某个mfps文件中定义了如下引用结构:
Citingspace level1 //绝对引用路径为::level1
Using citingspace aaaa //绝对引用路径为::level1::aaaa
Using citingspace bbbb //绝对引用路径为::level1::bbbb
Citingspace level2 //绝对引用路径为::level1::level2
Using citingspace cccc //绝对引用路径为::level1::level2::cccc
Using citingspace dddd //绝对引用路径为::level1::level2::dddd
Citingspace level3 //绝对引用路径为::level1::level2::level3
Function asmallfunc()
endf
Endcs
Endcs
Endcs
,并且假设上述代码就是该mfps文件的全部,那么,在函数asmallfunc看来,引用空间的优先级顺序为:::level1::level2::level3 > ::level1::level2 > ::level1::level2::dddd > ::level1::level2::cccc > ::level1 > ::level1::bbbb > ::level2::aaaa > 最顶层引用空间。
6.系统基本引用路径所指向的引用空间。
在这里需要注意几点。第一点,如果用户在非常靠近调用函数调用的位置用using citingspace语句指定了一个已经具有较低优先级的引用空间,那么该引用空间的优先级将会被提升。比如,在引用空间::aaaa内,用户定义了某个函数,在该函数内,用户要调用另外一个函数,在调用另外那个函数之前,用户又用using citingspace声明了::bbbb引用路径,代码结构如下:
Citingspace ::aaaa
......
Function callsomething()
......
Using citingspace ::bbbb
Anotherfunc() // 这里调用函数Anotherfunc()
......
Endf
......
Endcs
。显然,在此例子中,当调用Anotherfunc()函数时,MFP语言搜索引用空间的顺序为(由高到低排列):
1.::aaaa
2.::bbbb
3.顶级引用空间
4.::mfp以及其下级引用空间
。如果这时用户在Using citingspace ::bbbb下面增加一条using citingspace语句(增加后的代码结构见下):
Citingspace ::aaaa
......
Function callsomething()
......
Using citingspace ::bbbb
Using citingspace // 这条语句的意思是使用顶级引用空间
Anotherfunc() // 这里调用函数Anotherfunc()
......
Endf
......
Endcs
,由于Using citingspace比Using citingspace ::bbbb更靠近函数调用语句Anotherfunc(),所以顶级引用空间的搜索优先级这时比::bbbb还要高。换句话说,顶级引用空间的搜索优先级被提升了。新的搜索引用空间的顺序为(由高到低排列):
1.::aaaa
2.顶级引用空间
3.::bbbb
4.::mfp以及其下级引用空间
。注意虽然顶级引用空间的搜索优先级被提升了,但是它仍然比::aaaa的搜索优先级低。原因是::aaaa是调用语句所在的直接(最内层)引用空间,直接引用空间总是具有最高的搜索优先次序。
第二点是程序块的概念。程序块是指一个有开始有结束完整的程序部分。比如function和endf之间的部分就构成一个程序块,if和endif (也包括if和elseif,if和else,elseif和elseif,elseif和else,elseif和endif,以及else和endif),for和next,while和loop,do和until,try和catch,catch和endtry,select和ends,这些语句对之间的部分都构成程序块。显然,程序块可以相互嵌套,比如:
If a == b
For idx = 0 to 10 step 1
Next
Endif
,就是一个for程序块嵌在一个if程序块内。注意在MFP语言中,外层程序块声明的using citingspace语句,只要在内层程序块的上方,内层程序块的函数调用都可以看到。当然,外层程序块中声明的using citingspace语句在引用地址中的搜索优先级总是比在内层程序块中声明的using citingspace语句的搜索优先级低。但是在内层程序块中声明的using citingspace语句,外层程序块中是看不到的。在上述例子中,如果在if程序块中声明using citingspace ::aaaa,在for程序块中声明using citingspace ::bbbb,那么for程序块中的引用地址搜索顺序是先::bbbb,再是::aaaa,但在if程序快中引用地址搜索顺序只包括::aaaa。
If a == b
Using citingspace ::aaaa // for程序块看得见,但优先级低。
For idx = 0 to 10 step 1
Using citingspace ::bbbb // if程序块看不见。
Next
Endif
第三点,引用空间在一个mfps文件中的优先级不影响另外一个mfps文件中的优先级。比如有两个mfps文件,一个文件的内容为:
Citingspace ::aaaa
Using citingspace ::bbbb
Citingspace ::cccc
Function funcA()
Endf
Endcs
Endcs
另外一个文件的内容为:
Citingspace ::aaaa
Citingspace ::cccc
Using citingspace ::bbbb
Function funcB()
Endf
Endcs
Endcs
那么在函数funcA看来,引用空间的优先顺序为::cccc > ::aaaa > ::bbbb,而在函数funcB看来,引用空间的优先顺序为::cccc > ::bbbb > ::aaaa。
第四点,虽然不同文件中的引用空间的优先级排序不会相互影响,但要注意定义在同一个引用空间中的各个函数,哪怕定义在不同文件中,只要该空间被引用,则它们都是可见的。比如,在上一个例子中,函数funcB定义在引用空间::bbbb中,虽然函数funcA位于另外一个文件中,但由于在funcA之前已经声明使用引用空间::bbbb,所以funcB对于funcA是可见的,funcA可以直接调用funcB(只要没有同名并且同参数数目的函数)。
第五点,citingspace除了在mfps代码文件中声明,不能在其他任何地方使用。而using citingspace语句可以在命令提示符和基于JAVA的可编程科学计算器中使用,但不能在智慧计算器中使用,在这些交互式的工具中,用户可以使用
Shellman list_cs
命令查看所有使用的引用空间,也可以使用
Shellman add_cs citingspace_path
把citingspace_path指向的引用空间添加到引用空间搜索列表中。这条指令和using citingspace具有一样的效果。用户还可以使用
Shellman delete_cs citingspace_path
命令把citingspace_path指向的引用空间从引用空间搜索列表中删除。
Using citingspace语句(或者shellman add_cs命令)在命令提示符和基于JAVA的可编程科学计算器中使用时,将会添加新的引用空间搜索路径。但是这些新的引用空间搜索路径的优先级总是低于顶级引用空间(原因是顶级引用空间就是人机交互模式下命令提示符或者基于JAVA的可编程科学计算器的直接引用空间)。正是因为顶级引用空间在人机交互模式下在命令提示符或者基于JAVA的可编程科学计算器中具有最高的搜索优先级,所以,用户在命令提示符或者基于JAVA的可编程科学计算器中输入函数命令时,可以用省略掉起始::的相对引用空间路径。比如一个函数包括完整引用空间路径的名字为::abcdef::ghijk::lmn(a,b),在命令提示符或者基于JAVA的可编程科学计算器中,如果用户想调用这个函数,可以输入并运行,比如abcdef::ghijk::lmn(1,2),这和输入::abcdef::ghijk::lmn(1,2)的效果完全一样。
最后需要指出的是citingspace和using citingspace语句不能在solve程序块中出现。
以下代码示例(可以在本手册自带的示例代码所在目录中的MFP fundamental子目录中的examples.mfps文件中找到)可以帮助用户理解引用空间运作机制和搜索优先次序:
Citingspace ::mfpexample
// 别的函数,和本章节不相干,不在此列出
// ......
Function testCS1(a)
print("This is ::mfpexample::testCS1, a=" + a + "\n")
endf
citingspace Abcd
Function testCS1(a)
print("This is ::mfpexample::abcd::testCS1, a=" + a + "\n")
endf
Function testCS2(a, b)
print("This is ::mfpexample::abcd::testCS2, a="+a+", b="+ b+"\n")
endf
endcs
citingspace ::Abcd
Function testCS1(a)
print("This is ::abcd::testCS1, a=" + a + "\n")
endf
using citingspace abcd
Function testCSRef()
// get error here because testCS2(a,b) is only defined in citingspace
// ::mfpexample::abcd. Indeed using citingspace abcd has been declared
// before the function. This function is defined in citingspace ::Abcd
// . Because using citingspace abcd means use relative citingspace
// abcd, so the absolute citingspace should be ::Abcd + abcd =
// ::Abcd::abcd. This citingspace does not exist, so the function will
// fail.
//注意这里调用testCS2(a,b)时会出错,原因是testCS2(a,b)定义在引用空
// 间::mfpexample::abcd中。虽然using citingspace abcd已经被声明,但
//由于abcd是相对引用路径而不是绝对引用路径,而本函数(testCSRef)
// 定义在引用空间::Abcd中,这样一来,using citingspace abcd语句
// 所指向的引用空间的绝对引用路径就是::Abcd::abcd。但这个引用空间并
// 不存在,而里面就更不会有testCS2(a,b)函数了,所以会出错。
testCS2(2,3)
endf
using citingspace ::mfpexample::abcd
Function testCSRef1()
// here testCS2(a,b) is called after citingspace ::mfpexample::abcd is
// declared to use. So MFP will be able to find the right function
// which is ::mfpexample::abcd::testCS2
//这里,testCS2(a,b)在using citingspace ::mfpexample::abcd语句之后调
// 用,函数testCS2(a,b)是定义在引用空间::mfpexample::abcd中,所以
// 可以正确执行。
testCS2(2,3)
endf
endcs
citingspace ::__efgh__
Function testCSRef1()
// here the first testCS2(a,b) (testCS2 inside if block) is called
// after citingspace ::mfpexample::abcd is declared to use in the if
// block. So MFP will be able to find the right function which is
// ::mfpexample::abcd::testCS2. The second testCS2(a,b) is in the
// nested for block. Because the if block above the for block has
// declared to use ::mfpexample::abcd so the second testCS2(a,b) can
// still be found. However, the last testCS2(a,b) is out of if block
// so that it cannot see the using citingspace ::mfpexample::abcd
// statement so user will get error at the last testCS2 function.
//这里,第一个testCS2(a,b)函数(在if程序块内的testCS2)在
// using citingspace ::mfpexample::abcd语句之后调用,所以能够正确执行。
// 第二个testCS2(a,b)函数在for程序块内,它能够看到上层程序块,也就是
// if程序块的using citingspace ::mfpexample::abcd的语句,所以也能够正
// 常执行。但是最后一个testCS2(a,b)函数在if程序块之外,它无法看到在
// if程序块内的using citingspace ::mfpexample::abcd语句,所以无法正确
// 执行,会出错。
variable a = 3
if a == 3
using citingspace ::mfpexample::abcd
print("::mfpexample::abcd is declared to use in this if block\n")
testCS2(2,3)
for variable idx = 0 to 1 step 1
print("::mfpexample::abcd is declared to use in the above if block\n")
testCS2(2,3)
next
endif
print("::mfpexample::abcd is not declared to use out of if block\n")
testCS2(2,3)
endf
Function testCSRef2()
variable a = 3
// call ::mfpexample::testCS1 because testCSRef2() is inside (both
// ::__efgh__ and) ::mfpexample. Citingspace ::__efgh__ has a higher
// priority than ::mfpexample. If there is function named testCS1
// with one parameter is defined in ::__efgh__ it will be called.
// However, there is not. So MFP looks for testCS1 with one parameter
// in citingspace ::mfpexample. And there is. So ::mfpexample::testCS1
// is called.
// 调用::mfpexample::testCS1函数。这是因为testCSRef2()函数既位于
// 引用空间::__efgh__中,也位于引用空间::mfpexample中。但是
// ,由于::__efgh__位于引用空间::mfpexample的内部,而testCSRef2()
// 又位于::__efgh__内部,所以,引用空间::__efgh__具有更高的优先级,
// 如果在引用空间::__efgh__内有定义一个名叫函数testCS1并且只有
// 一个参数的函数,则这个函数将会被调用,但是由于::__efgh__中没有
// 这个函数,所以MFP会在更外层的引用空间中寻找,最后MFP在
// 引用空间::mfpexample中找到了这个函数,所以该函数被调用。
testCS1(a)
if a == 3
using citingspace ::abcd
// Because citingspace ::abcd has been explicitly declared to use
// in the innermost block, it has higher priority than
// ::mfpexample(but sill lower priority than the innermost
// citingspace declaration, in this case it is ::__efgh__). Thus
// ::abcd::testCS1 is called.
// 由于using citingspace ::abcd在最内层的程序块中被声明,它
// 具有比::mfpexample引用空间更高的优先级(但是它的优先级仍然
// 比::__efgh__要低,原因是::__efgh__是testCSRef2()函数最直接
// 的引用空间)。所以,最后的结果是函数::abcd::testCS1被调用。
testCS1(a)
endif
using citingspace ::mfpexample::abcd
// citingspace ::mfpexample::abcd has been explicitly declared to use
// and it is the closest using citingspace statement to the below
// testCS1 function. As such ::mfpexample::abcd has higher priority
// than any other citingspaces except ::__efgh__. Since ::__efgh__
// doesn't include a testCS1 function with a single parameter,
// ::mfpexample::abcd::testCS1 is called.
// using citingspace ::mfpexample::abcd语句位于下面testCS1函数调用
// 的正上方,所以引用空间::mfpexample::abcd具有比除了::__efgh__之外
// 所有其他引用空间都要高的优先级。由于引用空间::__efgh__中不包括
// 一个叫testCS1并且只有一个参数的函数,::mfpexample::abcd::testCS1
// 函数将被调用。
testCS1(a)
endf
endcs
using citingspace ::mfpexample::abcd
citingspace ::__efgh__
Function testCSRef3()
// function testCS2(a,b) is defined in the citingspace
// ::mfpexample::abcd and statement using citingspace ::mfpexample::abcd
// is called in the above citingspace, i.e. ::abcd (not the innermost
// citingspace, i.e. ::__efgh__, but ::abcd as a citingspace includes
// citingspace ::__efgh__) before this function call. Therefore, function
//testCS2(2,3) can be found.
// 函数testCS2(a,b)被定义在引用空间::mfpexample::abcd中,并且,在
// 外层引用空间::abcd中(也就是并非最内层的直接引用空间::__efgh__,
// 但引用空间::abcd包含了::__efgh__)声明了
// using citingspace ::mfpexample::abcd,而且这个声明是在本函数调
// 用之前。所以,这里调用函数testCS2(2,3)能够成功。
testCS2(2,3)
endf
Endcs
// 别的函数,和本章节不相干,不在此列出
// ......
endcs
用户在命令提示符或者基于JAVA的可编程科学计算器中输入并运行“::mfpexample::testCS1(3)”,将会得到:
This is ::mfpexample::testCS1, a=3
,然后用户输入“using citingspace :: mfpexample”并运行,将会看到以下提示:
Citingspace has been added. Now it has higher priority than any other citingspace except the top one.
上述提示的意思是说,::mfpexample已经被加入引用空间搜索路径了,它现在具有比除了顶级应用空间之外的其他所有引用空间都要高的搜索优先级。
用户再输入“testCS1(3)”并运行,将会得到:
This is ::mfpexample::testCS1, a=3
,然后用户输入“abcd:: testcs1(3)”并运行,将会得到:
This is ::abcd::testCS1, a=3
,然后再输入“::mfpexample :: abcd :: testCS1(3)”,将会看到:
This is ::mfpexample::abcd::testCS1, a=3
,然后用户运行“abcd::testcsref()”,将会看到如下错误信息:
Function cannot be properly be evaluated!
In function abcd::testcsref :
D:\Development\NetBeansProjs\JCmdLine\build\scripts\manual_scripts\MFP fundamental\examples.mfps Line 275 : Invalid expression
Undefined function!
,如果用户运行“abcd::testcsref1()”,则不会出错,运行结果是:
This is ::mfpexample::abcd::testCS2, a=2, b=3
,用户运行“__efgh__::testCSRef1()”,将会看到结果为:
::mfpexample::abcd is declared to use in this if block
This is ::mfpexample::abcd::testCS2, a=2, b=3
::mfpexample::abcd is declared to use in the above if block
This is ::mfpexample::abcd::testCS2, a=2, b=3
::mfpexample::abcd is declared to use in the above if block
This is ::mfpexample::abcd::testCS2, a=2, b=3
::mfpexample::abcd is not declared to use out of if block
Function cannot be properly be evaluated!
In function __efgh__::testcsref1 :
D:\Development\NetBeansProjs\JCmdLine\build\scripts\manual_scripts\MFP fundamental\examples.mfps Line 318 : Invalid expression
Undefined function!
,运行“__efgh__::testCSRef2()”,结果为:
This is ::mfpexample::testCS1, a=3
This is ::abcd::testCS1, a=3
This is ::mfpexample::abcd::testCS1, a=3
,运行“__efgh__::testCSRef3()”,得到的结果为:
This is ::mfpexample::abcd::testCS2, a=2, b=3