对于那些不遵循 poj(jvm 上的 pascal)的人来说,它是一个编译器,将子集从 pascal 转换为 jasm(java 程序集),以便我们可以使用 jvm 作为执行环境。
在上一篇文章中,讨论了上下文(来自parser)和嵌套句子。在本出版物中,我们将讨论使用 pascal 的 read/readln 函数从标准输入 (stdin) 读取数据所需的更改。
当我们为 jvm 进行编译时,有必要详细说明这个令人难以置信的虚拟机的各个点的功能。因此,我多次详细介绍 jvm 的内部工作原理以及它的一些指令(操作码)。
从stdin(标准输入)读取数据
标准输入(stdin)是程序从中读取输入数据的流。到目前为止,我们仅支持stdout(标准输出)。
在这个commit中,实现了一个java程序来了解jvm如何处理stdin:
public class inputdata {
public static string name;
public static int age;
public static void main(string[] args) {
name = system.console().readline();
age = integer.parseint(system.console().readline());
system.out.println("you entered string " + name);
}
当我们反汇编 class 文件时,我们得到下面的程序集。不相关的片段被省略,并且产生汇编的原始片段(java)被插入了“;;”:
1: public class inputdata {
2: ;; public static string name;
3: public static name java/lang/string
4:
5: ;; public static int age;
6: public static age i
7:
8: public static main([java/lang/string)v {
9: ;; name = system.console().readline();
10: invokestatic java/lang/system.console()java/io/console
11: invokevirtual java/io/console.readline()java/lang/string
12: putstatic inputdata.name java/lang/string
13:
14: ;; age = integer.parseint(system.console().readline());
15: invokestatic java/lang/system.console()java/io/console
16: invokevirtual java/io/console.readline()java/lang/string
17: invokestatic java/lang/integer.parseint(java/lang/string)i
18: putstatic inputdata.age i
19:
20: ;; system.out.println("you entered string " + name);
21: getstatic java/lang/system.out java/io/printstream
22: getstatic inputdata.name java/lang/string
23: invokedynamic makeconcatwithconstants(java/lang/string)java/lang/string {
invokestatic java/lang/invoke/stringconcatfactory.makeconcatwithconstants(java/lang/invoke/methodhandles$lookup, java/lang/string, java/lang/invoke/methodtype, java/lang/string, [java/lang/object)java/lang/invoke/callsite
["you entered string "]
}
24:
25: invokevirtual java/io/printstream.println(java/lang/string)v
26:
27: return
}
}
通过此示例,可以确定要从 stdin 读取数据,必须使用指令system.console().readline()(第 11 行和第 16 行)。由于 readline() 返回一个字符串,因此要读取数字,需要使用函数 integer.parseint 进行转换(第 17 行)。
也就是说,来自下面的 pascal 程序:
program nameandage;
var
myname: string;
myage: integer;
begin
write('what is your name? '); readln(myname);
write('how old are you? '); readln(myage);
writeln;
writeln('hello ', myname);
writeln('you are ', myage, ' years old');
end.
poj 已调整生成以下 jasm:
// Code generated by POJ 0.1
public class name_and_age {
;; var myname: string;
public static myname java/lang/String
;; var myage: integer;
public static myage I
;; procedure main
public static main([java/lang/String)V {
;; write('What is your name? ');
getstatic java/lang/System.out java/io/PrintStream
ldc "What is your name? "
invokevirtual java/io/PrintStream.print(java/lang/String)V
;; readln(myname);
invokestatic java/lang/System.console()java/io/Console
invokevirtual java/io/Console.readLine()java/lang/String
putstatic name_and_age.myname java/lang/String
;; write('How old are you? ');
getstatic java/lang/System.out java/io/PrintStream
ldc "How old are you? "
invokevirtual java/io/PrintStream.print(java/lang/String)V
;; readln(myage);
invokestatic java/lang/System.console()java/io/Console
invokevirtual java/io/Console.readLine()java/lang/String
invokestatic java/lang/Integer.parseInt(java/lang/String)I
putstatic name_and_age.myage I
;; writeln;
getstatic java/lang/System.out java/io/PrintStream
invokevirtual java/io/PrintStream.println()V
;; writeln('Hello ', myname);
getstatic java/lang/System.out java/io/PrintStream
ldc "Hello "
invokevirtual java/io/PrintStream.print(java/lang/String)V
getstatic java/lang/System.out java/io/PrintStream
getstatic name_and_age.myname java/lang/String
invokevirtual java/io/PrintStream.print(java/lang/String)V
getstatic java/lang/System.out java/io/PrintStream
invokevirtual java/io/PrintStream.println()V
;; writeln('You are ', myage, ' years old');
getstatic java/lang/System.out java/io/PrintStream
ldc "You are "
invokevirtual java/io/PrintStream.print(java/lang/String)V
getstatic java/lang/System.out java/io/PrintStream
getstatic name_and_age.myage I
invokevirtual java/io/PrintStream.print(I)V
getstatic java/lang/System.out java/io/PrintStream
ldc " years old"
invokevirtual java/io/PrintStream.print(java/lang/String)V
getstatic java/lang/System.out java/io/PrintStream
invokevirtual java/io/PrintStream.println()V
return
}
}
此提交实现了对 poj 解析器的必要更改。
这是完整的 pr。
下一步
在下一篇文章中,我们将完成该项目的目标之一:递归计算阶乘。
完整的项目代码
包含项目完整代码和文档的存储库在这里。