想法源头
父亲是多年易语言资深用户,易语言虽然强大但也存在诸多问题,主要体现在效率、扩展性、跨平台等方面,比如:
- 代码无法版本控制:易语言一个工程师所有内容都打包在一个私有定制文件中,无法以文件、文本形式拆分从而无法通过 git/svn 做代码版本记录和控制
- 不能跨平台:无法在在非 Windows 平台下开发和运行,比如 macOS
- 应用领域狭窄:无法开发如 Linux Server、Web UI 相关应用
- 生态封闭:这不是易语言的问题,是整个中文编程圈的问题,中文编程需要一个良好的开源生态,极低成本桥接或利用当今火热的 JavaScript/Python 相关能力。
- 语法累赘:待补充
一些现有的中文编程开源项目
- wenyan-lang/wenyan - 文言文編程語言
- StepfenShawn/Cantonese - 粤语编程语言
- Klang
- 草蟒
- 木兰编程语言重现
语法
- 设计原则尽量简单简洁,极大程度参考 Javascript 标准语法,不引入类型系统(如 Typescript)增加复杂度(暂时)
- 代码中涉及的标准函数、标准库、甚至三方库期望都是中文,沉浸式中文编程
有些问题还没想明白:
- 英中文全角半角问题,比如字符串表示是 “”这样的全角符号好还是和其他编程语言一样用半角”” 好?
- 全角好处:
- 输入效率:编写中文代码时候无需切换英文输入法或半角开关,输入效率高
- 美观:全角符号更符合中文文章阅读习惯
- 半角好处:
- 开发简单:语法越接近 Javascript 成本越低(创作者角度)
- 全角好处:
保留字
- 变量
- 常量
- 如果
- 否则
- 否则如果
- 循环
- 函数
Hello World!
控制台.输出("你好,世界!")
注释
同 JavaScript 注释语法
// 这是一行注释
/*
多行注释
多行注释
*/
定义变量
通过关键字“变量”来定义一个变量,类似 JavaScript 中的 var。
变量 a = 1
变量 b = 2
or
定义 a = 1
定义常量
通过关键字“常量”来定义一个常量,类似 JavaScript 中的 const。
常量 a = "hello"
运算符
同 Javascript 运算符
运算符 | 例子 | 等同于 | 运算结果 |
---|---|---|---|
= | x=y | x=5 | |
+= | x+=y | x=x+y | x=15 |
-= | x-=y | x=x-y | x=5 |
*= | x*=y | x=x*y | x=50 |
/= | x/=y | x=x/y | x=2 |
%= | x%=y | x=x%y | x=0 |
字符串拼接
变量 字符串1 = “你好” + “中文编程!”
分支
如果() {
// ...
}另如(){
// ...
}否则{
// ...
}
如果 x==1
控制台.输出("123")
循环
同 JavaScript 中的 for 语句
循环(变量 a = 0; a<10; a++){
// ...
}
计次循环xx
函数
同 JavaScript 中 function 关键字定义函数
函数 加(a,b)「
返回 a + b
」
例:加法函数
函数 加法(值1, 值2) {
返回 值1 + 值2;
}
工具链
- 代码高亮(Code highlight)
- 代码自动补全(Autocomplete)
- 代码语法检查(Lint)
实现原理
如果考虑目标语言是 Javascript 的化,转译(Transpile)Source-to-source compiler 几种方式:
- 通过通用的词法分析、语法分析开源库进行编译,需要自己写分词规则,但要实现完整 ES 语法规范还是比较复杂,类似 jison(bison)、PEG.js、ANTLR等
- jison 相对还算比较成熟,还有 jison debugger 比较好用。
- PEG.js 的 example 中有一份基于 ECMA-262 规范的 Javascript 语法规则文件,可以考虑基于这份规则进行二次修改。
- 基于现有 Javascript 编译器进行扩展或改写,参考项目 Babel、Esprima
- Babel 开放的插件 Plugin 能力威力有限,无法对某些原始 Javascript 语法进行扩展,比如将 var 关键字修改为“变量”,可以参考这个 Discussion:《How to add custom syntax/operators/keywords to JavaScript with Babel?》
- 也提到这各 Stackoverflow 回答:《How would I extend the JavaScript language to support a new operator?》,提供的思路是通过 fork 出 esprima 源码来修改分词逻辑分析成 AST,然后通过 escodegen 生成 Javascript 代码,还提供了一份基于早期 esprima 源码进行增加操作符的例子,可以说很是良心了。
尝试写的未完成版 jison 语法规则:
%lex
%s INITIAL INCOMMENT
/** identifiers **/
keywords "变量"|"常量"|"如果"|"否则"|"否则如果"|"循环"|"函数"
symbols "="|"/="|"+"|"-"|"*"|"/"|"%"|"<="|">="|">"|"<"|";"|"("|")"|"「"
/** whitespaces **/
whitespaces \s
%%
\n return 'NEWLINE'
{whitespaces} /** skip **/
"变量" return 'KEYWORDS_VAR'
"常量" return 'KEYWORDS_CONST'
"=" return '='
[a-zA-Z\u4e00-\u9fa5]+[a-zA-Z0-9\u4e00-\u9fa5] return 'IDENTIFIER'
{symbols} return 'SYMBOLS'
{keywords} return 'KEYWORDS'
{number} return 'NUMBERS'
<<EOF>> return 'EOF'
/lex
%start source
%left '或' '且' '并'
%left '=' '/='
%left '>' '<' '>=' '<='
%left '+' '-'
%left '*' '/' '%'
%%
source
: program EOF { return $1 }
| EOF { return '' }
;
program
: statement { $$ = $1 + ';' }
| program statement { $$ = $1 + '\n' + $2 + ';' }
;
statement
: KEYWORDS_VAR IDENTIFIER '=' e { $$ = `let ${$2} = ${$4}` }
| KEYWORDS_CONST IDENTIFIER '=' e { $$ = `const ${$2} = ${$4}` }
;
e
: IDENTIFIER { $$ = $1 }
| NUMBERS { $$ = $1 }
| e '+' e { $$ = `(${$1}+${$3})`}
| e '-' e { $$ = `(${$1}-${$3})`}
| e '*' e { $$ = `(${$1}*${$3})`}
| e '/' e { $$ = `(${$1}/${$3})`}
| e '%' e { $$ = `(${$1}%${$3})`}
| '(' e ')' { $$ = `(${$2})`}
;
生态
标准库中文化
标准库的存在和易用的重要性非常高,想想还存在如下问题:
- 哪一套标准库?如果是以 Javascript 作为源语言,Javascript 并没有语言级别标准库,依赖不同平台(如 Chrome、Node、Deno)有不同的标准库API,参考《JavaScript 竟然没有标准库?》,到底以哪个平台实现为准?还是各平台实现各平台标准库?还是自定一套标准库?
- 成本问题:大量标准库、涉及的包、类、方法的中文化带来成本问题,初步想到有两种实现方式,一是通过「包装」方式将如 Node 某个内置库包一层,但工作量不小,因为需要包装所有涉及的类、方法签名等;二是通过一套名称映射机制在编译时进行名称(类名、方法名)替换,如果可以做到完美替换,那成本将会低很多。
源语言开源三方包桥接方案
这是中文编程生态对接开源世界的核心桥梁。
TODO
Web 后端应用模版
TODO
HTML 前端中文化
TODO