怎麼用中文設計編程語言?

因為計算機科學起源於西方,現今各種編程語言都是用英文,如果用中文設計一種語言可行嗎?有大神是否想過怎麼設計呢?


開了下腦洞,覺得 @NightyNight 的文言編程有意思,關於語法規則的劃分可以考慮更加充分的利用文言虛詞,不一定要拘泥於句式。文言中的虛詞本身起到了語法的界定作用,用文言虛詞來進行語法界定可以避免那些亂七八糟的符號。

比如過程定義的文法可以寫成

definition := parameters "之" def_name "者" expression "也"
expression := (arguments "之" function) | (lhs function rhs)

也就是寫成

某之均者某之數除某之累和也

這一句就相當於

(define (均 某) (/ (sum 某) (count 某)))

不過有一點難處理的是,這樣的機制默認寫出來的 identifier 都是單個漢字,連續的單個漢字會被認為是並列的多個參數(如「甲乙之積」中認為「積」是兩個參數的函數,甲乙是兩個並列的參數),畢竟文言名詞也以單字詞居多。這種時候可能就不得不引入諸如引號(「」或「」)、逗號(,)、頓號(、)分號(;)等現代漢語的標點來進行輔助的界定,比如放在引號中的多個單字被認為是一個整體(「隔壁老王」藏於「衣櫃」)。

別的一些語義也可以用類似形式表達,比如 let...in... 寫成 「以……為……」

以十三為廣,十四為縱,廣縱之積

相當於

(let ((廣 13) (縱 14)) (* 廣 縱))

部分參考《九章算術》


當然可行,可以參考 vczh/tinymoe 。雖然這個是英文的,不過沒關係,只要把tokenizer改掉,每一個字元一個token(而不是按照非字母字元去切連續的字母作為token),立刻就搞定了。不過這種做法出來的不可能是自然語言,你寫出來的中文也是需要嚴格滿足一定的語法結構的。

原理其實很簡單,首先識別出來哪些行是函數聲明,每一個函數聲明其實就是聲明了一個短語,which給語言增加了新的語法結構。然後你把這些聲明收集起來,當作EBNF,跑一邊經典的LALR演算法,出來一個parser,然後再用parse一遍自己的函數體,你就成功的做完語法分析了。

我可以想像一下給出最終中文編程的例子(逃

語句:輸出(垃圾)
重定向到printf

短語:從(甲)加到(乙)的結果
令結果為0
令丙為甲
只要丙小於或等於乙就
令結果為結果加丙

語句:入口
輸出從1加到100的結果

不需要添加多餘的空格,爽!

分析一下,我們可以強行規定「短語/語句:」開頭的就是函數頭,然後用python一樣的那種縮進的辦法。於是我們就有了下面的EBNF:

(省略語言本身就預定義好的語句,譬如說「令 fuck 為 shit」和「只 要 expr 就」
stat := "輸" "出" expr
expr := "從" expr "加" "到" expr "的" "結" "果" // 你需要處理優先順序問題

剩下來就很容易了,龍書裡面都說過了。

而且跟現在的那些所謂的漢語編程不一樣,人家總是不斷地給單詞中間加入符號,看起來成了一堆屎。憑啥要在中文裡面加入空格?你說話的時候會加空格嗎?

(逃


好,放劍制。

來,我們來寫文言文。

首先下一個Parser(Python 3.6)框架。放心我不是調包黨,我是造輪子的。

這個框架真的很有趣的(吃我安利!),你要是有興趣可以問我實現原理,可以看我文章。

pip install -U EBNFParser

(剛剛花時間支持了中文parser名...不然我早就來回答了。吐槽一下,shutil包真的很玄幻。

然後,這裡有一個文件。

很騷氣的文言編程文法(對不齊是因為unicode字元的鍋。。)

複製它,找個地方,放著。

然後在這裡打開命令行。

parserGenerator ./grammar ./myparser.py
# EBNFParser已經更新,現在的命令是
# ruiko ./grammar ./myparser.py

然後就可以開始玩了。

python testLang.py 語句 "[吾身]乃劍所[天成]。" -o 吾身乃劍所天成
python testLang.py 語句 "血作為[鐵潮];心作為[琉璃]。" -o 血潮為鐵,心為琉璃
....

詳見travis測試文件

結果放點圖,現在是ast。

(這個圖比較舊,如果你認真看會發現分號被當成了變數(概念),因為token沒對。吃飯後更正

文件名叫無限劍制.sh。


其實這本質上是一個函數單參數,然後有兩種倒裝運算的Lisp。

下午有課,解釋器等下。

語法是這樣的。

lambda定義是用開頭,後面跟一個,或者一個方括弧括起來的詞,表示參數,再後面跟一個具象,你把它理解為表達式即可。

調用函數的形式是以字開頭,後面跟參數,參數是一個具象(剛剛發現上面寫錯了。上面的圖其實用的是概念這個Ast,是錯的,但是生成Ast階段是不報錯的,在Ast解析時,這個位置的類型不是具象的話,會拋出異常)。再跟一個表達式,這個表達式得到的結果將調用前面這個參數。所有的函數都是單參數的,很洋氣:)

然後倒裝句有作為三種,其中的優先順序是一樣的,作為比他們靠後。

[吾身](乃( 劍(所(天成)) ) ) # 劍所天成是會結合成一個表達式,然後用被乃調用
(人)作為((天)所(寵幸)) # 這裡就是優先順序的體現了。

Emmmmm

想了一晚上還是加一句... 可以的話,github上給這項目加個星吧。

thautwarm/EBNFParser

畢竟也確實能方便到有些工作。個人也覺得挺好玩的。


以下原文

這個問題突然提起了我對所謂中文編程的興趣。之前見過的都是些符號替換,實在沒有半點興趣。
然後我今天早上看到大v輪的答案,他說把token搞成單一字元拆分(這個其實很有趣),然後給了自己的語言的例子。然後我來了一點靈感。
我想理想中大概是這樣的

&>&> 以我為0,以你為1,問以我加你是為你?
=&> 是
&>&> 有年為天,干,地,支 #容器
&>&> 以吾之事為由某年言若某年是為天則1而若某年是為地則2否則3 # let一個lambda
# 以 吾之事 為 由 某年 言 若某年是為天 則1 而若某年是為地 則2 否則3 :)
# 這個語法在我後來的實現里改了,詳見更新寫的
&>&> 以年之天行吾之事
=&> 1

上面這些都很好做(吃完飯放解釋器),問題在於這些例子:
以1加2
以人余聖
解析時,怎麼判斷1加2不是符號,以及人余妖不是符號。怎麼把他們解析成
以(1)(加)(2)
以(人)(余)(聖)

我解決思路應該非常清真,全部單子化
以具象行具象,等於
具象(具象)
那麼上面的以1加2就是
以1行以2行加

加 :: Int -&> Int -&> Int

好的,答題前其實還沒想清楚,答題後已經搞定。


可以用數學教材當中常用的中文描述,比如

定義 f(名字,次數):

取i從範圍(次數):

輸出「你好世界」,名字

f(「用戶」,2)

主要的優點:

可以省略空格(但是分詞演算法可能會很複雜)

主要的缺點:

輸入真TM累,如果有輔助的輸入法的話可能能好一點

附關鍵字:

若 否則若 否則

取(變數)從(範圍)

當(條件)

繼續

跳出

嘗試 拋出 捕捉(為) 否則 最終

定義

返回

交出(yield)

……


把 APL 漢化了就行了(逃


為什麼不願意搜一下尼?

蕭涵:為什麼程序都要用英文寫,中文不行嗎?


我就問一句,用英文直接敲代碼就好,用中文開著輸入法你不嫌打字慢嘛?


火了這麼多年的易語言你們都沒聽說過???


洛谷P1001 A+B Problem的一篇討論

你自己看看這群……hhhhhhhhhh


你可以用拼音的。

編程語言就是一門語言,有自己的語法,並不是英文,只是利用了ascii碼


更新一下 Python 怎麼加中文token

1.90%語法,可以按下面方法加同義的中文token
以while為例
第1步. 編譯pgen
cd到python的源代碼目錄下,
./configure
make Parser/pgen

第2步. 修改 ./Grammar/Grammar,添加同義詞並生成語法代碼。
原文:
while_stmt: "while" test ":" suite ["else" ":" suite]
改為:
while_stmt: ("while"|當) test ":" suite [("else"|另) ":" suite]
執行
./Parser/pgen ./Grammar/Grammar ./Include/graminit.h ./Python/graminit.c


之後 make 編譯python即可。

中文的py文件也需要保存為UTF-8格式。

2.還有一較複雜語法在/Python/ast.c 里有輔助解析

例如

comp_op: ... |"in"|"not" "in"|"is"|"is" "not"

改為 comp_op: ... |("in"|在)|("not" "in"|不在)|("is"|為)|("is" "not"|不為)

在ast.c里的 ast_for_comp_op 中

if (NCH(n) == 1)

switch (TYPE(n))

case NAME

/******添加如下代碼*******/

if (strcmp(STR(n), "在") == 0)

return In;

if (strcmp(STR(n), "不在") == 0)

return NotIn;

if (strcmp(STR(n), "為") == 0)

return Is;

if (strcmp(STR(n), "不為") == 0)

return IsNot;

其實從源代碼我們可以看出來,comp_op原來的判斷是token有兩個單詞的話,第二個單詞為in返回NotIn,第一個單詞為is返回IsNot。

3.內置函數 中文化

在/Python/bltinmodule.c中的builtin_methods[]中添加

以print為例,將含"print"的一行複製粘貼,替換第二行的"print"為"列印"即可

其他的還有一些宏,展開看一下,就明白了。

/*********************************/

我用clang做了一個與C++、C兼容的純中文的編譯器

swizl/cnlang

其實就是加token

在/include/clang/Basic/TokenKinds.def 中用ALIAS添加中文關鍵字

在 /lib/Basic/IdentifierTable.cpp 中 加個頭文件 #include "llvm/ADT/StringSwitch.h"

例如

KEYWORD(char, KEYALL)

ALIAS("字", char, KEYALL)

在 tok::PPKeywordKind IdentifierInfo::getPPKeywordID() const 里用llvm::StringSwitch添加 中文宏

例如

//default: return tok::pp_not_keyword;

default: return llvm::StringSwitch&(Name)

.Case("如", tok::pp_if)

.Case("定義", tok::pp_define)

.Default(tok::pp_not_keyword);

至於llvm/clang的編譯方法,網上一堆。

還用tinycc做了個中文自舉編譯器,也是加token。

再把源代碼里的關鍵字都替換掉。

swizl/tinycc_cn 添加了中文token的tinycc

swizl/tinycc_zh 關鍵字全換了的tinycc,用tinycc_cn編了之後,可以自舉


#include&

#define shiyong using
#define minmingkongjian namespace
#define changliang const
#define zhengxing int
#define changzheng long long
#define wufuhao unsigned
#define buer bool
#define ruguo if
#define xunhuan for
#define mo %
#define jiashang +
#define jianqu -
#define chengyi *
#define chuyi /
#define zuiyi haiyaoshuchu
#define youyi dayu dayu
#define haiyou ,
#define canshukaishi (
#define canshujieshu )
#define jieshubencixunhuan continue
#define tiaochuxunhuan break
#define zhuhanshu main
#define fanhui return
#define fuzhi =
#define dengyu =
#define wancheng ;
#define kaishi {
#define jieshu }
#define biaozhunku std
#define jiegouti struct
#define lei class
#define duilie queue
#define shuangduanduilie deque
#define zhan stack
#define youxianduilie priority_queue
#define zhuhanshu main
#define zifuchuan string
#define shuru cin
#define shuchu cout
#define yaoshurude &>&>
#define yaoshuchude &<&< #define haiyaoshuchude &<&< #define haiyaoshurude &>&>
#define xiaoyu &< #define dayu &>
#define de .
#define bufanhui void
#define kongde bufanhui
#define neilian inline
#define youhua __attribute__((__optimize__("-O4")))
#define zijia ++
#define zairuguo else ruguo
#define bumanzu else
#define quandengyu ==
#define jiaguoqu +=
#define jianguoqu -=
#define chengguoqu *=
#define chuguoqu /=
#define moguoqu %=
#define xiaoyudengyu &<= #define dayudengyu &>=
#define huozhe ||
#define bingqie
#define budengyu !=
#define hangjieshule endl
#define manzutiaojianjiuxunhuan while
#define qudizhi
#define paixu sort
#define fanhui return
#define zhuhanshu main

shiyong minmingkongjian biaozhunku ;
zhengxing a , b;
zhengxing zhuhanshu canshukaishi canshujieshu
kaishi
shuru yaoshurude a; shuru yaoshurude b;
shuchu yaoshuchude canshukaishi a jiashang b canshujieshu ;
fanhui 0;
jieshu

一份putong的a + b

(別打我哈哈哈哈哈哈哈哈哈)


當然是用lisp的宏呀


給我一個Chinese.h就行


在程序員眼中,int,if,true等這些並不是英語,而是計算機語。


你們煩不煩啊,這種提問都是月經題了吧。先去了解易語言再談別的好不好?


中文編程語言之Z語言初嘗試: ZLOGO 4

已經商用的日語編程語言, 語法還是有點接近自然語言的: 日語編程語言"撫子" - 第三版特色初探

還遠未實現的中文彙編編譯器原型. 基於現有開源彙編器漢化關鍵詞開始應該會省力的多. 當時是想從頭做一個編譯器, 順便在Java中實踐中文命名. 對x64體系和intel指令的認識有限, 生成二進位碼時遇到瓶頸. 項目已擱置.

設想的效果圖(中英對比):


為什麼ruby一個日本人發明的卻用英文,為什麼python是荷蘭人發明卻用英文,為什麼易語言沒有走向世界。
對不起偏題了但是就想表達一下。


用中文變成意義不大,弊大於利。設計一門中文變成語言不難,以前就有e語言啊,但是一門編程語言用什麼文字書寫區別不大 因為就那麼幾個關鍵字。重要的事學習資料是中文還是英文,社區是中文還是英文


中文編程已經有了很久了,丙正正這門語言就是中文版的C++,只是因為沒人使用,所以沒發展起來


推薦閱讀:

瀏覽器是如何識別惡意站點並提示的?
怎麼看待鬥魚TV這段時間負面不斷?是鬥魚出現了問題,還是行業出現了瓶頸?
2016~20 年矽谷需求量最大的是什麼方向的技術人才?
為什麼工資高的程序員會難找到女朋友?
IT上班族怎樣才能有情調、有意義地過生活?

TAG:編程語言 | 編程 | 軟體工程 | 計算機科學 | IT行業 |