狗牙根就是天堂草吗? 当前位置:首页>狗牙根就是天堂草吗?>正文

狗牙根就是天堂草吗?

发布时间:2019-04-23

原标题:手写JAVA虚拟机(二)——实现java命令行

纷乱的声音就像是被利刃斩断般嘎然而止。谁能想到,之前还一脸恬淡,优雅自若的唐三,竟然能够释放出这犹如实质般地强横杀气。

贵州可以栽植小叶黄杨吗?

当年伏羲创造女性神族也是以后土的外表作为参照物创造出来的,她是神族之中唯一一个由自己从神树果实化形而成的神,同时也是神族之中除了伏羲之外最强大的神。”神农说道:
而赤瞳现在显然不是如此,她这一刀在布兰德眼前比起刚才她斩出的每一刀都更胜一筹,如果说赤瞳刚才的攻击是将力量都集中在刀锋上,那么现在就是将力量都集中在刀尖上,在力量的运用上更胜一筹了。

下午,一队队金吾卫和巡查营和士兵出现在长安街头,平康坊内更是官府关注的重点,河东客栈的客人、掌柜和伙计全部被带回衙门询问,衙役们在平康坊挨家挨户盘问,来历不明的人一律带回衙门。

  查看手写JAVA虚拟机系列可以进我的博客园主页查看。

  我们知道,我们编译.java并运行.class文件时,需要一些java命令,如最简单的helloworld程序。

  

  这里的程序最好不要加包名,因为加了包名的话编译和运行需要有所改动。

  看这里的命令。javac为编译命令,我们知道java的特点是一次编译,到处运行。这里的编译指的就是javac,对于java程序即.java文件,先要用javac编译成字节码。然后将字节码(.class文件)放到java虚拟机中运行,即上图中的java HelloWorld,java虚拟机把字节码翻译成对应机器上的机器指令,再由机器来执行具体的机器指令。也就是说java程序员是直接与java虚拟机交互,简介与机器交互。所以虚拟机完成的是java命令,也就是我们要完成的是java这个指令的功能

  那么我们把第一个目标定为,实现简单的命令行。即我们通过命令行可以输入一些内容,虚拟机读取之后可以给一定的反馈。

  GO语言中有两个和命令行相关的包,分别是os和flag(java中以类库即jar文件导入,go中直接以包的形式导入)。

  首先在GOPATH目录下的src里面新建一个jvmgo文件夹作为我们的工作空间目录,jvmgo里面再新建一个ch01为我们的第一个目标源码文件夹,添加cmd.go文件。

  

  在cmd.go里面输入如下代码(由于博客园的添加代码方式不支持go语言着色,所以采用C语言着色,高亮可能不太正确

package main

import "flag"
import "fmt"
import "os"

//定义Cmd结构体
type Cmd struct{
    helpFlag     bool
    versionFlag     bool
    cpOption     string
    class     string
    args     []string
}

//解析命令行参数
func parseCmd() *Cmd {
    cmd:=&Cmd{}

    //将printUsage函数传给flag.Usage
    flag.Usage=printUsage
    //设置各种解析的选项
    flag.BoolVar(&cmd.helpFlag, "help", false, "print help message")
    flag.BoolVar(&cmd.helpFlag, "?", false, "print help message")
    flag.BoolVar(&cmd.versionFlag, "version", false, "print version and exit")
    flag.StringVar(&cmd.cpOption, "classpath", "", "classpath")
    flag.StringVar(&cmd.cpOption, "cp", "", "classpath")
    //所有选项设置完成后调用flag.Parse解析所有选项,如果Parse失败,则调用flag.Usage打印帮助信息
    flag.Parse()

    //调用flag.Args函数捕获未被解析的参数,第一个参数为主类名,后面的为传递给主类的参数
    args:=flag.Args()
    if len(args)>0{
        cmd.class=args[0]
        cmd.args=args[1:]
    }

    return cmd
}

func printUsage() {
    fmt.Printf("Usage:%s[-options] class [args...]
",os.Args[0])
}

 

  第一行为包名,main包,接着引入了三个包os,flag,fmt。os和flag都是处理命令行所需的包fmt类似于C语言的printf和scanf等格式化IO。再往下定义了一个结构体Cmd,用来这个数据结构来格式化存储输入的命令行信息。helpFlag参数为命令行是否请求help,versionFlag参数为命令行是否请求version,cpOption为命令行传入的classpath即目标.class文件所在文件夹,class为命令行传入的.class文件名(不包括.class),args为命令行传入的其他参数。

  紧接着是一个parseCmd函数(go语言有函数和方法之分,方法调用需要receiver,函数调用则不需要 ),返回值为*Cmd,用来解析cmd传过来的参数。该函数里面先声明一个cmd并给这个cmd赋值一个新建的Cmd对象。go语言中的“:=”为声明并赋值,而"="为赋值。先把printUsage的函数赋值给flag.Usage,然后调用flag设置需要解析的选项,全部解析完毕,调用Parse函数解析所有选项。解析成功则结束,解析失败则调用printUsage打印到控制台。

  flag.Args可以捕获其他没有被解析的参数。上面解析成功之后,第一个参数就是主类名,剩下的就是传给主类的参数。

  工具类编写完成,下一个是主函数。先上主函数代码:

package main

import "fmt"

func main() {
    //调用parseCmd解析命令行参数
    cmd:=parseCmd()

    if cmd.versionFlag{
        //输入了-version选项
        fmt.Println("version 0.0.1")
    }else if cmd.helpFlag||cmd.class==""{
        //输入了-help选项
        printUsage()
    }else{
        //启动jvm
        stratJVM(cmd)
    }
}

func stratJVM(cmd *Cmd){
    fmt.Printf("classpath:%s class:%s args:%v
",
        cmd.cpOption,cmd.class,cmd.args)
}

  跟java类似,在go里面main是一个特殊的包,go程序的入口就是main函数,但是不接受任何参数,也不能有返回值。main函数先调用parseCmd解析命令行参数,如果是-version则返回版本号,如果是-help则返回帮助信息,如果是其他则启动jvm,这里用一些输出信息“假装”启动了jvm,真正的jvm代码后面会加上。

  至此,对命令行的解析工作全部完成。先展示一下整个工作目录的结构,不然后面编译运行的时候会出错。

  

  我们的工作目录是D盘下的JVM里的goWorkSpace,再下面src,jvmgo,ch01,ch01里面包含的是我们的go文件。

  来测试一下,打开一命令行,输入go install jvmgoch01。这个命令是使用go.exe来install文件,这个文件存在于GOPATH下面的文件夹(jvmgoch01中),结果如图:

  

  然后在工作空间(GOPATH)的bin文件夹中就多出了一个ch01.exe。

  

  在此处打开命令行。可以进行一些操作:

  

  到这里,我们的命令行工具就完成了,虽然还没有涉及真正的虚拟机设计,但这也是虚拟机运行的重要一步,后面会逐渐介绍虚拟机的设计。

编辑:乙成陵安

发布:2019-04-23 00:25:06

当前文章:http://www.nsmsa.com.cn/home/m81prmhmc6.html

哪里有紫荆树卖_出售? 高羊茅草籽哪里有卖? 看榉树是如何在各界中脱颖而出的,没有什么树能与它相提并论了 常见的美人蕉品种有哪些? 想买月季大苗,请来江苏沭阳,3年5年生大棵型 优质大叶黄杨苗哪家好? 美国红枫小苗什么价格? 四川哪里有卖月季苗?

32768 75366 92585 51380 41458 98395 14784 20642 53215 10322 20048 15541 44921 81207 25228 77425 81302 38665 87787 38322

责任编辑:成通侯