lua-token

一个变成语言基本分为 4 部分,入口,块,语句,表达式

其中入口便是程序开始部分

约定 :: 代表定义, {} 代表 0 次或者多次, [] 代表 0 - 1 次

人类自己制造的编程语言,不同于自然语言,相对简单的多,基本就是一个有穷状态机。

gammer ::= block
block ::= {stat} [retStat]
// 返回
retStat ::= return [expList] [';']

// 语句,一共有 15 种,语句只能执行,不能求值,比如 if
stat ::= ';'
	| varList '=' expList
	| functionCall
	| label
	| break
	| goto Name
	| do block end
	| while exp do block end
	| repeat block until exp
	| if exp then block {elseif exp then block} [else block] end
	| for Name '=' exp ',' exp [',',exp] do block end
	| function funcName funcBody
	| local function Name funcBody
	| local nameList ['=' expList]

// 表达式只能求值不能执行,比如 123  1 + 2
expList ::= exp {',' exp}
exp ::= nil | false | true | Numeral | LiteralString | '...' | functionDef | prefixExp
	| tableConstructor | exp binOp exp | unOp exp

// ps: 函数调用既可以是表达式也是语句
// hello() obg[key()] 这种都是合法的,前者属于语句,后者属于表达式

针对语句进行拆分
语句部分 ast 结构

// 拆分一下
emptyStat ::= ';'
breakStat ::= break
labelStat ::= '::' Name '::'
gotoStat ::= goto Name
doStat ::= do block end
funcCallStat ::= FuncCallExp
whileStat  ::= while exp do block end
repeatStat ::= repeat block until exp
// ifStat 可以将else 简化
ifStat ::= if exp then block {elseif exp then block} [else block] end
// ifStat ::= if exp then block {elseif exp then block} [elseif true then block] end
// ifStat ::= if exp then block {elseif exp then block} end

forNumStat ::= for Name '=' exp ',' exp [',',exp] do block end
forInStat ::= for nameList in expList do block end
localVarDeclStat ::= local nameList '=' expList
assignStat ::= varList '=' expList
// 是 assignStat 的语法糖,所以返回结构和 也是AssignStat.
// TODO: 没准我可以美化下
funcDefStat ::= function funcName funcBody
localFuncDefStat ::= local function Name funcBody

// util
nameList ::= Name {',' Name}
expList ::= exp {',' exp}
varList ::= var {',' var}
var ::= Name | prefixExp '[' exp ']' | prefixExp '.' Name
funcName ::= Name {'.' Name} [':' Name]
funcBody ::= '(' [parList] ')' block end
parList ::= nameList [',' '...'] | '...'

// 最终
tat ::= emptyStat
	| assignStat
	| funcCallStat
	| labelStat
	| breakStat
	| gotoStat
	| doStat
	| whileStat
	| repeatStat
	| ifStat
	| forNumStat
	| forInStat
	| funcDefStat
	| localFuncDefStat
	| localVarDeclStat

表达式部分精简

nilExp ::= nil
falseExp ::= false
trueExp ::= true
varArgExp ::= '...'
integerExp ::= Numeral
floatExp ::= Numeral
stringExp ::= LiteralString
nameExp ::= Name
concatExp ::= exp '...' exp
tableConstructorExp ::= '{' [fieldList] '}'
funcDefExp ::= function funcBody

// 原始版本
prefixExp ::= var | functionCall | '(' exp ')'
// 赋值语句等号左侧、名字表达式、表访问表达式、记录访问表达式
var ::= Name | prefixExp '[' exp ']' | prefixExp '.' Name
functionCall ::= prefixExp args | prefixExp ':' Name args

// 精简版
prefixExp ::= Name | parentExp | tableAccessExp | prefixExp '.' Name | functionCallExp

parentExp ::= '(' exp ')'
tableAccessExp ::= prefixExp '[' exo ']'
functionCallExp ::= prefixExp [':' Name] args

// util
Name ::= /^[_\d\w]+/


LiteralString ::= /(^'(\\\\|\\'|\\\n|\\z\s*|[^'\n])*')|(^"(\\\\|\\"|\\\n|\\z\s*|[^"\n])*")/;

Numeral ::= /^0[xX][0-9a-fA-F]*(\.[0-9a-fA-F]*)?([pP][+\-]?[0-9]+)?|^[0-9]*(\.[0-9]*)?([eE][+\-]?[0-9]+)?/;

fieldList ::= field {fieldSep field} [fieldSep]
field ::= '[' exp ']' '=' exp | Name '=' exp | exp
fieldSep ::= ',' | ';'


args ::= '{' [expList] '}' | tableConstructorExp | LiteralString

// 通过优先级解决歧义问题
exp ::= exp12
exp12 ::= epx11 {or exp11}
exp11 ::= exp10 {and exp10}
exp10 ::= exp9 {('<' | '>' | '<=' | '>=' | '~=' | '==') exp9}
exp9 ::= exp8 {'|' exp8}
exp8 ::= exp7 {'~' exp7}
exp7 ::= exp6 {'&' exp6}
exp6 ::= exp5 {('<<' | '>>') exp5}
exp5 ::= exp4 {'..' exp4}
exp4 ::= exp3 {('+' | '-') exp3}
exp3 ::= exp2 {( '*' | '/' | '//' | '&') exp2}
exp2 ::= {('not' | '#' | '-' | '~')} exp1
exp1 ::= exp0 ('^' exp2)
exp0 ::= nil | false | true | Numeral | LiteralString | '...' | funcDefExp | prefixExp
	| tableConstructorExp

LiteralString
LiteralString ::= /(^‘(\\|\’|\\n|\z\s*|[^'\n])')|(^“(\\|\”|\\n|\z\s|[^“\n])*”)/;

Numeral
Numeral ::= /^0[xX][0-9a-fa-f](.[0-9a-fA-F])?([pP][+-]?[0-9]+)?|^[0-9](.[0-9])?([eE][+-]?[0-9]+)?/;)

src=lua-token.js