BNF范式是一种描述编程语言的数学方法,可读性接近自然语言。
BNF规则
::= 左边是非终结符或元变量,右边是终结符——一些事先规定好的符号,这些符号可能是简单的单词或者在其他BNF式子中作为非终结符。有些BNF式子中是用冒号代替 ::=
双引号中的内容表示符号本身的意思,之所以用双引号包上是因为部分符号在BNF中表达特定的意思。看BNF需要把双引号拿掉再看。有些BNF式子中是用的引号代替双引号
双引号外的内容表示语法部分
括号中的内容是必选项。有些BNF式子是用的尖括号
方括号中的内容是可选项
花括号中的内容可以是零次或者许多次
竖线表示左右任选一项
有的单词加引号表示原本的意思,有的不用引号也表示原本的意思(好不严谨的样子)
变量var
这里指变量的命名,即标识符!
变量开头不能是数字,可以是字母和下划线。变量其他字符可以是数字、字母、下划线。
(letter、digit、underline这类简单的单词表达的意思就不用解释了!)
var ::= prechar[otherchar]
prechar ::= letter|underline
otherchar ::= (letter|digit|underline)[otherchar]
1
2
3
表达式
表达式可以指数据,变量存放的数据!
二元表达式和一元表达式,判断式,四则运算式。
无效值nil和用两个点连接字符串都是LUA语法,在进行设计的时候尽量考虑的简单点,所以使用一些LUA、python、C等语言的语法。
exp ::= nil|false|true|unop exp|exp binop exp|NUMBER|STRING|var
unop ::= "+"|"-"|"~"|not
binop ::= "+"|"-"|"*"|"/"|"//"|"%"|"^"|"&"|and|"|"|or|
">"|"<"|"=="|"<="|">="|".."
NUMBER ::= digit { digit } [ "." digit { digit } ]
STRING ::= """ everyletter """ { ".." STRING }
1
2
3
4
5
6
语句
每个语句块用花括号包起来。每句话可以以分号或者换行结束, } 左边的第一条语句可以不用分号和换行结束。
语句块内可以嵌套语句块。
赋值语句左边可以是一个变量,或者用逗号分隔的几个变量。
当型循环用while关键字,满足条件就进入循环。
直到型循环用until关键字,满足条件就跳出循环。
区分局部变量和全局变量,如果是类或者函数内的,就是默认局部变量。
凡是可以用赋值式的地方,等于号都能用is关键字代替。
block ::= "{" { stat endstat } [ stat ] "}" | "{" block "}"
varlist ::= var { "," var }
explist ::= exp { "," exp }
stat ::= [ local ] varlist ( "=" | is ) explist |
if exp block { elif block } [ else block ] |
for var ( "=" is ) exp "," exp [ "," exp ] block |
while exp block |
do block until exp |
break |
continue
endstat ::= ";"|newline
1
2
3
4
5
6
7
8
9
10
11
函数
在增加功能的时候,把新增的BNF式子并到之前的有过的非终结符式子里面。下面的式子都是对已有的补充(高级数组代替类有修改的内容)
三个连续的点表示任意数量、任意类型的参数。
参数内可传递变量、函数名、表达式。
因为没有设计运行这么自定义语言可以嵌套定义函数,所以函数体不涵盖在block里了。
返回参数可以为零,可以是一串参数。
funcname ::= var
args ::= ( var | funcname | exp ) [ "," args ]
arglist ::= args [ "," "..." ] | "..."
paramlist ::= "(" [ arglist ] ")"
functiondef ::= def funcname paramlist block
stat ::= return [explist] | functioncall
functioncall ::= funcname "(" [ args ] ")"
1
2
3
4
5
6
7
对象
这里点操作符只能用在实例对象或者包(package/module)的相关使用上。现在暂时就不管包了。
语句stat增加了创建实例对象这一句!直接用类名赋值就是创建了,简单易懂。
增加this关键字,指向本身。
classname ::= var
classdef ::= class classname [ extends classname ] classbody
classbody ::= "{" {
(functiondef |
varlist ( "=" | is ) explist)
} "}"
exp ::= classname
var ::= var { "." ( var | functioncall ) }
this ::= classname
1
2
3
4
5
6
7
8
9
数组
数组内部可以嵌套数组!元素间用逗号分开。元素可以是表达式不能是赋值式子。
增加了in关键字。
数组的使用可以递归?就是不止一维数组,可以有许多维度。
括号后面可以跟方括号,但是方括号后面不能跟括号,因为这里没有设计数组中可以存放变量——现在数组中只能放置常量。
arrayname ::= var
elements ::= NUMBER | STRING
arraydef ::= "[" { elements } "]" | "[" arraydef "]"
exp ::= var in arrayname | arraydef
var ::= var { "[" var "]" }
1
2
3
4
5
高级数组代替类
在LUA里只有表这个数据结构,但是也能通过setmetatable方法实现面向对象。
因为数组和类的功能有重叠,都能存放数据,所以可以把二者合二为一。让数组可以存放函数,并且可以拥有继承和多态!!
下面的数组允许多继承,存放变量、赋值式、函数。
访问数组元素可通过索引[2]、点操作符.a、加引号的元素名"a",函数 .fun() 必须用点操作符来调用!
elements ::= var |
functiondef |
varlist ( "=" | is ) explist
arraynamelist ::= arrayname { "," arrayname }
arraydef ::= [ extends arraynamelist with ] ( "[" { elements } "]" | "[" arraydef "]" )
var ::= var { "["
( var |
""" elements """ )
"]" }
this ::= arrayname
1
2
3
4
5
6
7
8
9
10
包
没有包就不能灵魂,鸡蛋都放在一个篮子里是不对的!
可以通过一个变量来接收这个包,用这个变量来访问包内的元素,当然也可以直接访问。引用时可以引用整个包,或者包内的某个元素——为了使其他包内未引用的元素不被访问到,需要屏蔽。
%import ::= import """ dir/packname [ "." var ] """
exp ::= %import
var ::= [ packname "." ] var
functioncall ::= [ packname "." ] funcname "(" [ args ] ")"
1
2
3
4
实现不实现暂时不管了,就做个梦吧(笑)
参考:《两周自制脚本语言》
B站up的视频编程范式02BNF
————————————————
版权声明:本文为CSDN博主「Demllie」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41374099/java/article/details/102990659
阅读(898) | 评论(0) | 转发(0) |