Apple语言概述
Facebook的Libra项目,主体采用Rust语言,以安全高效著称。智能合约采用了自定义的Move语言,可以更方便安全处理金融业务。让一般的东摘西抄区块链项目相形见绌。其实定义一门语言,现在并不像几十年前那么困难了。缺的是思想。
Apple语言就是一门为孩子设计的语言。可以用于体验新设计语言的过程。
随着人类社会的发展,人类需要面临的计算越来越复杂。最开始的计算机,是几千年前的算盘类的机械装置。1694年德国发明家戈特弗里德-莱布尼茨发明了步进计算器,类似汽车的里程表,采用齿轮装置,手摇计算。每当一个一个齿轮转1圈10个齿,就会变成0,相邻的齿轮变成1.做减法时反向运动。做乘除法就是转为加减法。
1822年,Charles Babbage 提出一种机械装置,差分机,可以处理多项式计算,后面他又提出了更先进的“分析机”,有点类似现代的计算机,有存储,有指令。但都没有实现。英国数学家Ada lovelace,是诗人拜伦的女儿。她为分析机设想了一种语言,可以在分析机运行通用计算。Ada是公认的第一位程序员。
1890年美国人用打孔机电装置来统计人口,以分配预算和选票,大大缩减了原始统计方式,由原来的7年完成缩减到2年半。1924年IBM 成立,为何叫国际商业机器公司?因为那时的计算设备都是机械电子的。当时最大的哈佛马克一号用继电器来做开关计算,用于曼哈顿计划。继电器相比齿轮有了很大进步,因为直接用机电来控制开关,速度有了很大提高。但机械装置的问题是效率不高能耗高,还容易损坏,每秒能做50次翻转,3次加减运算。3秒完成一次乘法运算。机电装置还长虫。1947年9月,哈佛马克2号操作员从故障的继电器中拔出一只死虫。所以后面的程序员都需要在程序中找“Bug”。
1904年,英国物理学家John Fleming发明了热电子管(Thermionic Valve)——真空管。将两个电极装在一个气密的玻璃灯泡里,用电的方式来做开关。其中一个电极加热时会发射电子,,叫热电子发射。另一个电极会吸引电子。只有正电子可以穿过真空,负电子不能穿过,形成一个电子器件,电流只能单向流动,叫二极管(Diode)。1906年,美国发明家Lee de Forest改进成三级管,在中间加一个控制电极,通过加正电荷,允许电子流动,加负电荷,禁止电子流动,来控制电流的断开和闭合,形成一个开关。真空管相比继电器,没有机械运动,所以效率大大提高,每秒开闭数千次。但真空管很大,造价高,而且容易烧坏。真空管使用了半个世纪,广泛用于计算,通信,广播等领域。1943年底完成的“巨人1号”是第一个大规模使用真空管的计算机,由英国工程师Tommy Flowers设计,用于破解纳粹通信。这是第一台可编程计算机,采用把几百根电线插入插板的方式完成。1946年美国的Eniac则是第一台通用可编程计算机,每秒执行5000次加法运算,半天出一次故障。
直到1947年,贝尔实验室科学家John Bardeen等发明了晶体管,这种半导体电子器件才让电子计算往高效低耗稳定的方向持续发展。晶体管有两个电极,电极之间有一个隔开他们。这种材料有时导电,有时不导电。叫半导体。控制线连到一个门电极,通过改变门的电荷,来控制电极的导电性,从而形成一个开关,完成高性能逻辑数值运算。晶体管一下子提高到每秒10000次的开关,而且不容易坏,固体材料,体积小,节省能源。1957年,IBM的计算机508,就是采用晶体管设计,体积变小,造价变低,每秒执行4500次加法。而且逐渐引入个人电脑,得到广泛应用。现在一个晶体管小于50nm。而且正在向几纳米改进。一张纸的厚度是10万纳米。在纸的截面上,可以横着并排放数万个晶体管。每秒切换上百万次,用几十年不会坏。
在20世纪40年代,第一台计算机发明的时候,那时候人们只能用二进制编程,然后进化成用汇编。这些编程方式和计算机硬件关系紧密。输入输出的方式,都是打孔纸带,和阿兰图灵的设想非常像。图灵计算机系统有寄存器,ALG,指令集,内存等组成。那时程序员都是科学家兼任。
而现在的高级语言,使程序员只需关注逻辑算法需求,而无需关注底层硬件具体实现,为程序开发专业化工程化铺平了道路。
未来随着通用人工智能的实现,人类可以做的工作越来越少。人类的价值可能还是在创新创造文艺,对人类自身和宇宙的研究,创造更强大的机器智能,为人类未来千年亿年发展做规划,满足人类日益增长的物质文化需求。
编程作为一项综合性,基础性的学科,应该是每个人都需要掌握的,否则就没法适应时代的发展。
我想为孩子们创建一门简单的语言叫Apple,作为孩子们入门的语言。
Apple语言基于java jvm,这样方便不停的扩展,具有完善的功能和库,也利于快速实现。
这门语言要简单而强大,减少出错。
实现需求第一版
- 实现整数加减乘除括号四则运算
- 实现变量赋值
- 实现单行和多行注释
- 实现多行代码
- 实现两行续为一行
- 文件格式后缀为.ap
未来规划
实现图灵完备语言,内存自动管理,基本数据结构和算法,多线程,基本安全和tcp/ip, http web服务。
code
https://github.com/ablozhou/apple
ANTLR
网站:https://www.antlr.org/
为何要用ANTLR?
ANTLR (ANother Tool for Language Recognition) 是一个词法分析和语法分析的工具。作者Terence Parr ,从1989年开始做语言工具,现在圣地亚哥大学担任计算机教授。从元语言定义语法,最后可以生成相关词法分析,词,语法,生成分析树。是现在广泛使用的语言定义工具。
记得我上大学时,计算机课的老师就要求在Unix上,利用Lex/Yacc实现词法分析和语法分析,但那时做得并不精。Lex(词法分析生成器/A Lexical Analyzer Generator)和Yacc(Yet Another Compiler-Compiler)是原来计算机课程广泛使用的两个工具。 不过有了Antlr这样的工具,对开发语言又变容易了。
环境准备
- MacOS:本项目测试主要是在Mac book完成,示例也是该系统。
- Java:1.8+
- antlr:4.7.2+
安装antlr4
cd /usr/local/lib
$ sudo curl -O https://www.antlr.org/download/antlr-4.7.2-complete.jar
$ vi ~/.zshrc
export CLASSPATH=".:/usr/local/lib/antlr-4.7.2-complete.jar:$CLASSPATH"
alias antlr4='java -jar /usr/local/lib/antlr-4.7.2-complete.jar'
alias grun='java org.antlr.v4.gui.TestRig'
$ source ~/.zshrc
创建项目
完成后目录结构如下:
zhouhh@/Users/zhouhh/apple git:(master) $ tree
.
├── LICENSE
├── Readme.md
├── antlr
│ ├── pom.xml
│ └── src
│ └── main
│ └── antlr4
│ ├── Apple.g4
│ └── compile.sh
├── compiler
│ ├── pom.xml
│ └── src
│ └── main
│ ├── java
│ │ └── com
│ │ └── abloz
│ │ └── compile
│ │ ├── AppleVisitorImpl.java
│ │ └── Main.java
│ └── resources
├── hello.ap
└── pom.xml
这是maven组成的两个子模块的项目。
antlr项目只存放用于生产语法树的g4文件。
compiler项目则用于真正实现这门语言。
g4 文件
Apple.g4是语法定义文件。
grammar Apple;
// Author: Andy zhou <ablozhou@gmail.com>
// Date 2019.8.15
@header {package com.abloz.antlr;}
prog: (stmt)*;
stmt: expr ((NEWLINE|';'))* # express
| NEWLINE # newLine
;
expr: expr op=(MUL|DIV) expr # MulDiv
| expr op=(ADD|SUB) expr # AddSub
| INT # int
| ID # id
| ID '=' expr # assign
| '(' expr ')' # parens
;
NEWLINE : [\r\n]+ ;
INT : [0-9]+ ;
MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
ID : [_a-zA-Z0-9]+ ; // match alpha,digital,_ identifiers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
SPACES
: [ \t]+
;
COMMENT
: '//' ~[\r\n\f]*
;
BLOCK_COMMENT
: '/*' .*? '*/'
;
LINE_JOINING
: '\\' SPACES? ( '\r'? '\n' | '\r' | '\f')
;
SKIPS: (WS|COMMENT|BLOCK_COMMENT|LINE_JOINING)+ -> skip;
$ antlr4 Apple.g4
$ javac Apple*.java
$ grun Apple prog -gui
100+2*34
^D
pom文件
请参考github项目
Java 文件
- AppleVisitorImpl.java
package com.abloz.compile;
import com.abloz.antlr.AppleBaseVisitor;
import com.abloz.antlr.AppleParser;
import java.util.HashMap;
import java.util.Map;
/**
*
*@author Andy Zhou <ablozhou@gmail.com>
*@date 2019.08.15
*/
public class AppleVisitorImpl extends AppleBaseVisitor<Integer> {
/** "memory" for our calculator; variable/value pairs go here */
Map<String, Integer> memory = new HashMap<String, Integer>();
@Override
public Integer visitParens(AppleParser.ParensContext ctx) {
return visit(ctx.expr());
}
@Override
public Integer visitNewLine(AppleParser.NewLineContext ctx) {
return 0;
}
/**
* expr op=('*'|'/') expr
* @param ctx
* @return
*/
@Override
public Integer visitMulDiv(AppleParser.MulDivContext ctx) {
int left = visit(ctx.expr(0)); // get value of left subexpression
int right = visit(ctx.expr(1)); // get value of right subexpression
if ( ctx.op.getType() == AppleParser.MUL ) return left * right;
return left / right; // must be DIV
}
@Override
public Integer visitExpress(AppleParser.ExpressContext ctx) {
Integer value = visit(ctx.expr());
System.out.printf("%d\n",value);
return value;
}
@Override
public Integer visitProg(AppleParser.ProgContext ctx) {
Integer c = ctx.getChildCount();
Integer value = 0;
for(Integer i = 0; i < c; i++){
value = visit(ctx.getChild(i));
}
return value;
}
@Override
public Integer visitAssign(AppleParser.AssignContext ctx) {
String id= ctx.ID().getText();
Integer value = visit(ctx.expr());
memory.put(id,value);
return value;
}
@Override
public Integer visitAddSub(AppleParser.AddSubContext ctx) {
Integer left = visit(ctx.expr(0));
Integer right = visit(ctx.expr(1));
if(ctx.op.getType() == AppleParser.ADD) {
return left + right;
}
return left-right;
}
@Override
public Integer visitId(AppleParser.IdContext ctx) {
String id = ctx.ID().getText();
if ( memory.containsKey(id) ) return memory.get(id);
//System.out.println("id:"+id);
return 0;
}
@Override
public Integer visitInt(AppleParser.IntContext ctx) {
return Integer.valueOf(ctx.INT().getText());
}
}
- Main.java
package com.abloz.compile;
import com.abloz.antlr.AppleLexer;
import com.abloz.antlr.AppleParser;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.IOException;
/**
*
*@author Andy Zhou <ablozhou@gmail.com>
*@date 2019.08.15
*/
public class Main {
public static void main(String[] args) {
if(args.length < 1) {
System.out.println("run:\n java -jar compiler-1.0-SNAPSHOT-jar-with-dependencies.jar xxx.ap");
return;
}
String inputFile = args[0];
CharStream input =null;
try {
input = CharStreams.fromFileName(inputFile);
} catch (IOException e) {
e.printStackTrace();
}
// String appleExpr = "3+2*5";
// CharStream input = CharStreams.fromString(appleExpr);
AppleLexer lexer=new AppleLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
AppleParser parser = new AppleParser(tokens);
ParseTree tree = parser.prog(); // parse
AppleVisitorImpl vt=new AppleVisitorImpl();
Integer i = vt.visit(tree);
System.out.println("out:"+i);
}
}
编译
$ java -jar /usr/local/lib/antlr-4.7.2-complete.jar -visitor -no-listener -encoding UTF-8 Apple.g4
也可以直接用mvn package来联编整个项目。
Apple语言测试文件
// test data
// Computer v1.0
/* 这是一个多行的apple语言测试
第一版主要实现复杂表达式,变量和注释
*/ //UTF-8
4+3*2
7 - 10 / 2 //with spaces.
a=3;
3+a
3*(2+3)
b=3*2
c=b/ \
2 //another line
e = 2+ (3*(3+2)-5)
x = 3;
x
/* test other */
f=x+2
测试
$ java -jar compiler-1.0-SNAPSHOT-jar-with-dependencies.jar hello.ap
输出结果:
10
2
3
6
15
6
3
12
3
3
5
out:5
参考
- ANTLR 官方网址 http://www.antlr.org/
- ANTLR 官方 Github https://github.com/antlr/antlr4
- 大量语法文件例子 https://github.com/antlr/grammars-v4
如非注明转载, 均为原创. 本站遵循知识共享CC协议,转载请注明来源