clojure fn 编译为一个类.
(def 的全局变量) 编译为一个 var
loading__5569__auto__.class .是 ns 宏生成的类
(defmacro with-loading-context [& body]
`((fn loading# [] ;loading 类在这里生成的. 因为这里有个fn 每个fn 都会被编译为一个类
(. clojure.lang.Var (pushThreadBindings {clojure.lang.Compiler/LOADER
(.getClassLoader (.getClass ^Object loading#))}))
(try
~@body
(finally
(. clojure.lang.Var (popThreadBindings)))))))
java -jar clojure.jar -i one/one.clj 直接运行一个文件.
java -jar clojure.jar -e "(* 3 2)" 直接eval 一个字符串
这里面的核心1在 RT.init 和 RT 的static中. 把环境都初始化好了.
java -jar clojure.jar 没有直接 compile 的方法. 在文件中 加入:gen-class 在内存中生成了类.
只有调用 Compiler.compile 方法的时候 才会生成 _init 类. 直接
java -jar clojure.jar -i one/one.clj 这样运行文件 因为 RT.var 全局环境中已经有了对应的对象. 不需要init 了...
internalName1:clojure/core/specs/alpha$eval134
internalName1:user$eval136
internalName1:one$eval138$loading__6725__auto____139
internalName1:one$eval138
internalName1:one$eval142$fn__143
internalName1:one$eval142
internalName1:one$_main
internalName1:one$eval147
例如
(ns ast.compiletest
; (:require [])
)
(def fenga 3)
(defn ashuchu [x]
(+ fenga x)
)
clojure.core__init.class 有 6000多行 . clojure.10.1.jar 中第一层有 2283个类..
(compile 'ast.compiletest) 后 会生成一个 __init类
package ast;
import ast.compiletest.ashuchu;
import ast.compiletest.fn__27216;
import ast.compiletest.loading__6721__auto____27214;
import clojure.lang.AFn;
import clojure.lang.Compiler;
import clojure.lang.IFn;
import clojure.lang.IPersistentMap;
import clojure.lang.LockingTransaction;
import clojure.lang.PersistentList;
import clojure.lang.RT;
import clojure.lang.Symbol;
import clojure.lang.Tuple;
import clojure.lang.Var;
import java.util.Arrays;
import java.util.concurrent.Callable;
public class compiletest__init {
public static final Var const__3;
public static final AFn const__9;
public static final Object const__10;
public static void __init0() {
const__0 = (Var)RT.var("clojure.core", "in-ns");
const__1 = (AFn)Symbol.intern((String)null, "ast.compiletest");
const__2 = (AFn)Symbol.intern((String)null, "clojure.core");
const__3 = (Var)RT.var("ast.compiletest", "fenga");
const__10 = 3L;
const__11 = (Var)RT.var("ast.compiletest", "ashuchu");
}
public static void load() {
Var var10003 = const__3;
var10003.setMeta((IPersistentMap)const__9);
var10003.bindRoot(const__10);
}
static {
__init0();
load();
}
}
静态编译
简称 AOT(Ahead-Of-Time)即 提前编译 ,静态编译的程序会在执行前,会使用指定编译器,将全部代码编译成机器码。
动态解释
简称 JIT(Just-In-Time)即 即时编译 ,动态解释的程序会使用指定解释器,一边编译一边执行程序。
然而,以上这些难度,其实并非 parser 本身造成的,
人们常用的、手写的递归下降 LL(k) 解析器,已经可以解决大多数问题了。
所以,在学习 parser 之前,得先不要被它吓倒。
clojure 中每个fn 都被编译成了java的一个独立类. 方法中的内嵌方法 使用了内部类 使用$连接.
clojure 启动的时候,会使用Rt.java默默的把clojure.core中的函数类都加载到namespace中.
Symbol NameSpace Var 构成了 clojure 运行在jvm的地基.
clojure 使用Ifn 体系 让asm 把fn转化成 extend RestFn的基类
public interface IFn extends Callable, Runnable{
public Object invoke() ;
public Object invoke(Object arg1) ;
public Object invoke(Object arg1, Object arg2) ;
.......
public Object applyTo(ISeq arglist) ;
static public interface L{long invokePrim();}
static public interface D{double invokePrim();}
static public interface OL{long invokePrim(Object arg0);}
....
}
clojure.core$desc class文件 反编译代码
package clojure;
import clojure.lang.AFunction;
import clojure.lang.Numbers;
public final class core$dec extends AFunction {
public core$dec() {
}
public static Object invokeStatic(Object x) {
Object var10000 = x;
x = null;
return Numbers.dec(var10000);
}
public Object invoke(Object var1) {
Object var10000 = var1;
var1 = null;
return invokeStatic(var10000);
}
}
clojure 方法整体调用 . load-file -> eval ->analyze -> parse -> compile ->emit (里面互相递归调用)
clojure 前期开发的时候 使用了 common lisp
git checkout da14d89c
经过 88元红包在群里请教 . clisp 能运行
本次clisp 运行clojure 是在wsl ubuntu 上直接 apt install clisp 搞的.
clisp (load "clojure.lisp") (in-package "clojure")
然后把clojure.lisp中的一段代码粘贴运行. (需要先设置好文件夹和文件. )
(let ((*clojure-source-path* #p"/dev/clojure/src/lisp/")
(*clojure-target-path* #p"/dev/clojure/classes/"))
(compile-to :jvm "clojure.lib" "Clojure"
"lib.lisp"))
输出的时候会提示安全问题 <OUTPUT BUFFERED FILE-STREAM CHARACTER
直接输入 continue 则会生成Clojure.java
https://hub.fastgit.org/sbcl/sbcl/tree/master/src/compiler
使用sbcl 编译器体验 下
win10 下载安装
https://download.fastgit.org/sbcl/sbcl/releases/download/sbcl-1.4.14/sbcl-1.4.14-x86-64-windows-binary.msi
命令行下
sbcl --script .\test.lisp
https://acl.readthedocs.io/en/latest/index.html
2021年3月18日 不小心又深入到了 chezschema racket sbcl ... nanopass
(早期的 clojure.lisp 是用sbcl . 但现在运行报错.. psil)
https://raw.fastgit.org/kanaka/mal
lisp 解释器
kanaka/mal
mal - Make a Lisp
Mal is a Clojure inspired Lisp interpreter. (语法都是从clojure中吸取的)
(超多語言都有XDD)
clojure.lisp中的 注释 #| 之间 |#
Comments
;; Single line comments start with a semicolon, and can start at any point in the line
|
This is a multi-line comment.
|
They can be nested!
|#
|#
https://stackoverflow.com/questions/2320348/symbols-in-clojure
var 的 bound 比较重要
有一个较大社区的lisp 很不容易. clojure 有力的在成长
Why Clojure over other JVM Lisps: Kawa, Armed Bear or SISC?
麻杆打狼,两头怕
struct 就是 class 就是 map {:type "onetype" :p1 3 }
根据各种具体的类型来做各种编译操作. (要深刻知道理解这三者在本质上是一样的. 这样ast 和 各种语言编译的本质抓住了. 对各种具体类型的数据做具体操作)
早期( git checkout 348f4fa0 ) Compiler 放弃了clojure.lisp 使用java 把clj代码生成了 java代码
static String compile(String ns, String className, LineNumberingPushbackReader... files) throws Exception {
StringWriter w = new StringWriter();
try
{
_CRT_OUT.pushThreadBinding(w);
KEYWORDS.pushThreadBinding(null);
VARS.pushThreadBinding(null);
METHOD.pushThreadBinding(null);
LOCAL_ENV.pushThreadBinding(null);
FNS.pushThreadBinding(new PersistentArrayList(4));
format("/* Generated by Clojure */~%~%");
format("package ~A;~%", ns);
format("import clojure.lang.*;~%~%");
format("public class ~A{~%", className);
PersistentArrayList forms = new PersistentArrayList(20);
for (LineNumberingPushbackReader reader : files)
{
try
{
IMPORTS.pushThreadBinding(null);
USES.pushThreadBinding(null);
Object eof = new Object();
Object form = null;
while ((form = LispReader.read(reader, false, eof, false)) != eof)
{
form = macroexpand(form);
if (!(form instanceof ISeq))
throw new Exception("No atoms allowed at top level");
Object op = RT.first(form);
//enact import and use at compile-time
if (op == IMPORT)
{
//(import org.package ThisClass ThatClass ...)
//makes entries in IMPORTS for:
//"ThisClass"->"org.package.ThisClass"
//"ThatClass"->"org.package.ThatClass"
IPersistentMap importMap = (IPersistentMap) IMPORTS.getValue();
String pkg = RT.second(form).toString();
for (ISeq classes = RT.rest(RT.rest(form)); classes != null; classes = classes.rest())
{
String iclassName = classes.first().toString();
importMap = (IPersistentMap) RT.assoc(iclassName, pkg + "." + iclassName, importMap);
}
IMPORTS.setValue(importMap);
}
else if (op == USE)
{
//todo implement use
}
else
forms = forms.cons(analyze(C.STATEMENT, form));
}
}
finally
{
IMPORTS.popThreadBinding();
USES.popThreadBinding();
}
}
//declare static members for keywords, vars
for (ISeq keys = RT.seq(KEYWORDS.getValue()); keys != null; keys = keys.rest())
{
KeywordExpr k = (KeywordExpr) ((IMapEntry) keys.first()).val();
format("static Keyword ~A;~%", k.emitExpressionString());
}
for (ISeq vars = RT.seq(VARS.getValue()); vars != null; vars = vars.rest())
{
Var v = (Var) ((IMapEntry) vars.first()).val();
format("static Var ~A;~%", munge(v.toString()));
}
//todo declare static members for syms, quoted aggregates
//emit nested static class/method declarations for nested fns
PersistentArrayList fns = (PersistentArrayList) FNS.getValue();
for (int f = 0; f < fns.count(); f++)
{
FnExpr fn = (FnExpr) fns.nth(f);
fn.emitDeclaration();
}
//define the load function
format("public void load() throws Exception{~%");
//init the keywords and vars
for (ISeq keys = RT.seq(KEYWORDS.getValue()); keys != null; keys = keys.rest())
{
KeywordExpr k = (KeywordExpr) ((IMapEntry) keys.first()).val();
format("~A = (Keyword)Symbol.intern(~S);~%", k.emitExpressionString(), k.sym.name);
}
for (ISeq vars = RT.seq(VARS.getValue()); vars != null; vars = vars.rest())
{
Var v = (Var) ((IMapEntry) vars.first()).val();
format("~A = Module.intern(~S,~S);~%", munge(v.toString()), v.module.name, v.name.name);
}
//todo init syms and quoted aggregates
//emit the top level forms
for (int i = 0; i < forms.count(); i++)
{
Expr e = (Expr) forms.nth(i);
e.emitStatement();
}
//close load function
format("}~%");
//close class def
format("}~%");
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
_CRT_OUT.popThreadBinding();
KEYWORDS.popThreadBinding();
VARS.popThreadBinding();
METHOD.popThreadBinding();
LOCAL_ENV.popThreadBinding();
FNS.popThreadBinding();
}
return w.toString();
}
“悦刻已经证明行业没有问题,发展方向没有问题,那产品没有做好最大的问题就是管理层,人不对,那就换人。” Thomas告诉《深网》,而本人则正式担任喜雾CEO,随后则亲自抓产品、找新的代工。
git checkout b8e4aa52
需要传的参数.
feng.one First E:\clojure\luminusweb\clojureyanjiu\src\one.clj
one.clj 内容
(def xa 12 )
(3 2 xa)
/* Generated by Clojure */
package feng.one;
import clojure.lang.*;
public class First{
static Var clj_DSH_user_CLN_xa;
public void load() throws Exception{
clj_DSH_user_CLN_xa = Module.intern("clj-user","xa");
clj_DSH_user_CLN_xa.bind(12);
((IFn)3).invoke(2, clj_DSH_user_CLN_xa.getValue());
}
}
(def onefn (fn (x) x))
(def xa 12 )
(3 2 xa)
(onefn 3)
/* Generated by Clojure */
package feng.one;
import clojure.lang.*;
public class First{
static Var clj_DSH_user_CLN_onefn;
static Var clj_DSH_user_CLN_xa;
static public class FN__onefn__2 extends AFn{
public Object invoke(Object x) throws Exception{
return x;
}
}
public void load() throws Exception{
clj_DSH_user_CLN_onefn = Module.intern("clj-user","onefn");
clj_DSH_user_CLN_xa = Module.intern("clj-user","xa");
clj_DSH_user_CLN_onefn.bind((new FN__onefn__2()));
clj_DSH_user_CLN_xa.bind(12);
((IFn)3).invoke(2, clj_DSH_user_CLN_xa.getValue());
((IFn)clj_DSH_user_CLN_onefn.getValue()).invoke();
}
}
天才设计.?
static Var clojure__assoc_if = Namespace.intern("clojure", "assoc_if");
Namespace.intern("clojure", "assoc_if").bind(new assoc_if());
/* Generated by Clojure from the following Lisp:
(defn* assoc-if ((fun alist) (assoc-if fun alist nil))
((fun alist keys)
(cond ((atom? alist) nil)
((and (cons? (first alist)) (fun (if (:key keys) ((:key keys) (ffirst alist)) (ffirst alist)))) (first alist))
(t (assoc-if fun (rest alist) keys)))))
*/
static public class assoc_if extends AFn {
public Object invoke(Object fun, Object alist) throws Exception {
return clojure__assoc_if.fn().invoke(fun, alist, null);
}
public Object invoke(Object fun, Object alist, Object keys) throws Exception {
if (clojure__atomQMARK__.fn().invoke(alist) != null) {
return null;
} else {
if ((((clojure__consQMARK__.fn().invoke(clojure__first.fn().invoke(alist)) != null))
? ((IFn) fun).invoke((((IFn) KEY__key).invoke(keys) != null ?
((IFn) ((IFn) KEY__key).invoke(keys)).invoke(clojure__ffirst.fn().invoke(alist)) :
clojure__ffirst.fn().invoke(alist))) : null) != null) {
return clojure__first.fn().invoke(alist);
} else {
return clojure__assoc_if.fn().invoke(fun, clojure__rest.fn().invoke(alist), keys);
}
}
}
}
git chekout 3ed36822 clojure 尝试了 antlr
http://uternet.github.io/TLS/10.html
good
git checkout 92075ac2 got rid of ANTLR reader 摆脱了ANTLR阅读器
git checkout 4b899d76 加入了 boot.clj
540e1195 加入了 pom.xml
2021年3月26日 终于初步明白了 一个clj fn 或宏 如何转化为一个可被jvm执行的class
static class FnExpr implements Expr{
IPersistentCollection methods;
//if there is a variadic overload (there can only be one) it is stored here
FnMethod variadicMethod = null;
String name;
String simpleName;
String internalName;
Type fntype;
//localbinding->itself
IPersistentMap closes = PersistentHashMap.EMPTY;
//Keyword->KeywordExpr
IPersistentMap keywords = PersistentHashMap.EMPTY;
IPersistentMap vars = PersistentHashMap.EMPTY;
Class compiledClass;
int line;
final static Method kwintern = Method.getMethod("clojure.lang.Keyword intern(String, String)");
final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String, String)");
final static Method varintern = Method.getMethod("clojure.lang.Var intern(clojure.lang.Symbol)");
final static Method afnctor = Method.getMethod("void <init>()");
final static Method restfnctor = Method.getMethod("void <init>(int)");
final static Type aFnType = Type.getType(AFn.class);
final static Type restFnType = Type.getType(RestFn.class);
static Expr parse(C context, ISeq form, String name) throws Exception{
FnExpr fn = new FnExpr();
FnMethod enclosingMethod = (FnMethod) METHOD.get();
String basename = enclosingMethod != null ?
(enclosingMethod.fn.name + "$")
: (munge(currentNS().name) + ".");
fn.simpleName = (name != null ?
munge(name)
: ("fn__" + RT.nextID()));
fn.name = basename + fn.simpleName;
fn.internalName = fn.name.replace('.', '/');
fn.fntype = Type.getObjectType(fn.internalName);
try
{
Var.pushThreadBindings(
RT.map(
KEYWORDS, PersistentHashMap.EMPTY,
VARS, PersistentHashMap.EMPTY));
//(fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...)
//turn former into latter
if(RT.second(form) instanceof IPersistentVector)
form = RT.list(FN, RT.rest(form));
fn.line = (Integer) LINE.get();
FnMethod[] methodArray = new FnMethod[MAX_POSITIONAL_ARITY + 1];
FnMethod variadicMethod = null;
for(ISeq s = RT.rest(form); s != null; s = RT.rest(s))
{
FnMethod f = FnMethod.parse(fn, (ISeq) RT.first(s));
if(f.isVariadic())
{
if(variadicMethod == null)
variadicMethod = f;
else
throw new Exception("Can't have more than 1 variadic overload");
}
else if(methodArray[f.reqParms.count()] == null)
methodArray[f.reqParms.count()] = f;
else
throw new Exception("Can't have 2 overloads with same arity");
}
if(variadicMethod != null)
{
for(int i = variadicMethod.reqParms.count() + 1; i <= MAX_POSITIONAL_ARITY; i++)
if(methodArray[i] != null)
throw new Exception(
"Can't have fixed arity function with more params than variadic function");
}
IPersistentCollection methods = null;
for(int i = 0; i < methodArray.length; i++)
if(methodArray[i] != null)
methods = RT.conj(methods, methodArray[i]);
if(variadicMethod != null)
methods = RT.conj(methods, variadicMethod);
fn.methods = methods;
fn.variadicMethod = variadicMethod;
fn.keywords = (IPersistentMap) KEYWORDS.get();
fn.vars = (IPersistentMap) VARS.get();
}
finally
{
Var.popThreadBindings();
}
fn.compile();
return fn;
}
boolean isVariadic(){
return variadicMethod != null;
}
private void compile(){
//create bytecode for a class
//with name current_ns.defname[$letname]+
//anonymous fns get names fn__id
//derived from AFn/RestFn
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
// ClassWriter cw = new ClassWriter(0);
ClassVisitor cv = cw;
//ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out));
//ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out));
cv.visit(V1_5, ACC_PUBLIC, internalName, null, isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFn", null);
String source = (String) SOURCE.get();
String smap = "SMAP\n" +
simpleName + ".java\n" +
"Clojure\n" +
"*S Clojure\n" +
"*F\n" +
"+ 1 " + source + "\n" +
(String) SOURCE_PATH.get() + "\n" +
"*L\n" +
"1#1,1000:1\n" +
"*E";
if(source != null && SOURCE_PATH.get() != null)
//cv.visitSource(source, null);
cv.visitSource(source, smap);
//static fields for keywords
for(ISeq s = RT.keys(keywords); s != null; s = s.rest())
{
Keyword k = (Keyword) s.first();
cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, munge(k.sym.toString()),
KEYWORD_TYPE.getDescriptor(), null, null);
}
//static fields for vars
for(ISeq s = RT.keys(vars); s != null; s = s.rest())
{
Var v = (Var) s.first();
cv.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, munge(v.sym.toString()),
VAR_TYPE.getDescriptor(), null, null);
}
//static init for keywords and vars
GeneratorAdapter clinitgen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC,
Method.getMethod("void <clinit> ()"),
null,
null,
cv);
clinitgen.visitCode();
clinitgen.visitLineNumber(line, clinitgen.mark());
for(ISeq s = RT.keys(keywords); s != null; s = s.rest())
{
Keyword k = (Keyword) s.first();
clinitgen.push(k.sym.ns);
clinitgen.push(k.sym.name);
clinitgen.invokeStatic(KEYWORD_TYPE, kwintern);
clinitgen.putStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE);
}
for(ISeq s = RT.keys(vars); s != null; s = s.rest())
{
Var v = (Var) s.first();
clinitgen.push(v.sym.ns);
clinitgen.push(v.sym.name);
clinitgen.invokeStatic(SYMBOL_TYPE, symcreate);
clinitgen.invokeStatic(VAR_TYPE, varintern);
clinitgen.putStatic(fntype, munge(v.sym.toString()), VAR_TYPE);
}
clinitgen.returnValue();
clinitgen.endMethod();
// clinitgen.visitMaxs(1, 1);
//instance fields for closed-overs
for(ISeq s = RT.keys(closes); s != null; s = s.rest())
{
LocalBinding lb = (LocalBinding) s.first();
cv.visitField(ACC_PUBLIC + ACC_FINAL, lb.name, OBJECT_TYPE.getDescriptor(), null, null);
}
//ctor that takes closed-overs and inits base + fields
Method m = new Method("<init>", Type.VOID_TYPE, ARG_TYPES[closes.count()]);
GeneratorAdapter ctorgen = new GeneratorAdapter(ACC_PUBLIC,
m,
null,
null,
cv);
ctorgen.visitCode();
ctorgen.visitLineNumber(line, ctorgen.mark());
ctorgen.loadThis();
if(isVariadic()) //RestFn ctor takes reqArity arg
{
ctorgen.push(variadicMethod.reqParms.count());
ctorgen.invokeConstructor(restFnType, restfnctor);
}
else
ctorgen.invokeConstructor(aFnType, afnctor);
int a = 1;
for(ISeq s = RT.keys(closes); s != null; s = s.rest(), ++a)
{
LocalBinding lb = (LocalBinding) s.first();
ctorgen.loadThis();
ctorgen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), a);
ctorgen.putField(fntype, lb.name, OBJECT_TYPE);
}
ctorgen.returnValue();
// ctorgen.visitMaxs(1, 1);
ctorgen.endMethod();
//override of invoke/doInvoke for each method
for(ISeq s = RT.seq(methods); s != null; s = s.rest())
{
FnMethod method = (FnMethod) s.first();
method.emit(this, cv);
}
//end of class
cv.visitEnd();
//define class and store feng: 此处动态生成了一个class jvm可以执行的.
DynamicClassLoader loader = (DynamicClassLoader) LOADER.get();
compiledClass = loader.defineClass(name, cw.toByteArray());
}
public Object eval() throws Exception{
return compiledClass.newInstance();
}
public void emit(C context, FnExpr fn, GeneratorAdapter gen){
//emitting a Fn means constructing an instance, feeding closed-overs from enclosing scope, if any
//fn arg is enclosing fn, not this
if(context != C.STATEMENT)
{
gen.newInstance(fntype);
gen.dup();
for(ISeq s = RT.keys(closes); s != null; s = s.rest())
{
LocalBinding lb = (LocalBinding) s.first();
fn.emitLocal(gen, lb);
}
gen.invokeConstructor(fntype, new Method("<init>", Type.VOID_TYPE, ARG_TYPES[closes.count()]));
}
}
public boolean hasJavaClass() throws Exception{
return true;
}
public Class getJavaClass() throws Exception{
return IFn.class;
}
private void emitLocal(GeneratorAdapter gen, LocalBinding lb){
if(closes.containsKey(lb))
{
gen.loadThis();
gen.getField(fntype, lb.name, OBJECT_TYPE);
}
else
gen.visitVarInsn(OBJECT_TYPE.getOpcode(Opcodes.ILOAD), lb.idx);
}
public void emitVar(GeneratorAdapter gen, Var var){
gen.getStatic(fntype, munge(var.sym.toString()), VAR_TYPE);
}
public void emitKeyword(GeneratorAdapter gen, Keyword k){
gen.getStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE);
}
}
操作系统开始加载一个exe 或linux下的执行文件的时候,会给该程序 init 堆栈 空间. 后才进入 main 函数.
不然直接使用malloc 就会报错.
在main函数执行前 .需要执行 getversion() _heap_init getcommandlina setenvp _cinit
这就是一个进程堆栈的来源.是操作系统赐予的.
一条汇编指令包含的步骤. 汇编指令在语言层面可以看做是原子的. 但在cpu内部又是很多电子步骤组成的
printf 不定参数,由编译器计算 平衡堆栈
这就是在反编译其他人发布的程序的时候,大部分都是用esp..
c++ this 终于明白入门了. malloc 返回的地址 用ecx 传给了成员函数.
画的最后好的一个 push pop后 sp永远指向栈顶. 该地址保存着栈顶数据.是相等的.不是大于1 或 小于1 的.
pop 导致的栈越界
“提供机制,而非策略
系统根据 用户的数据 逐步提供完善的 操作... (feng 灵感. 这样刚开始从极为简单开始, 让系统根据数据生长. 更多的分类,更多的按钮)
“所谓了解,就是知道对方 心灵最深的地方的痛处,痛在哪里”
最后,让我们以下面这段代码来结束第一章。再好的书,再好的资料,最多只能帮助我 们少走弯路,让我们在无助时有个依靠。但是“有些事,只能一个人做。有些关,只能一个 人过。有些路啊,只能一个人走”。 while(还没读懂 ucc\examples\sc){ 阅读并上机运行 ucc\examples\sc 的代码 }
E:\clojure\luminusweb\ucc162.3 非常好的项目.里面包含了 非常好的书籍... 感恩.阿弥陀佛
jvm 分 class 文件中的常量池 和 运行时的 常量池. hotspot 有个专门的Stringtable.用来存放全局的String常量 (一种优化手段)
http://asm.itstack.org/#/notes/2.1%E7%BB%93%E6%9E%84
java class file 编译类中不包含 package 和 import 部分,因此,所有类型名字都必须是完全限定的
这个asm 的方法有点巧妙 (不好理解)
public final FieldVisitor visitField(
final int access,
final String name,
final String descriptor,
final String signature,
final Object value) {
FieldWriter fieldWriter = new FieldWriter(symbolTable, access, name, descriptor, signature, value);
//理解要点 : 第一次 firstfield = lastfield . 然后是链表了. 让每个对象的 fv 指向下一个.
if (firstField == null) {
firstField = fieldWriter;
} else {
lastField.fv = fieldWriter;
}
return lastField = fieldWriter;
}
https://www.jianshu.com/p/cf78e68e3a99
clojure 手写的递归下降算法.在analyze中.
Go 编译器里基本上使用的都是经典的算法:经典的递归下降算法、经典的 SSA 格式的 IR 和 CFG、经典的优化算法、经典的 Lower 和代码生成,因此你可以通过一个编译器就把这些算法都贯穿起来。