Lendo dados da entrada padrão (stdin)

alexgarzao

Alex Sandro Garzão

Posted on August 7, 2024

Lendo dados da entrada padrão (stdin)

Para quem não está acompanhando o POJ (Pascal on the JVM) é um compilador que transforma um subset de Pascal para JASM (Java Assembly) de forma que possamos usar a JVM como ambiente de execução.

Na última postagem foi abordado contextos (do parser) e sentenças aninhadas. Nesta publicação vamos falar sobre as alterações necessárias para possibilitar a leitura de dados da entrada padrão (stdin), isso utilizando a função read/readln do Pascal.

Como estamos compilando para a JVM faz-se necessário detalhar o funcionamento de vários pontos desta incrível máquina virtual. Com isso, em vários momentos eu detalho o funcionamento interno da JVM bem como algumas das suas instruções (opcodes).

Lendo dados de stdin (entrada padrão)

Standard input (stdin) é o stream do qual um programa lê seus dados de entrada. Até o momento tínhamos suporte ao stdout (saída padrão) apenas.

Neste commit foi implementado um programa em Java para entendermos como a JVM lida com 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);
    }
Enter fullscreen mode Exit fullscreen mode

Quando desassemblamos o arquivo class obtemos o assembly abaixo. Trechos irrelevantes foram omitidos, bem como o trecho original (em Java) que deu origem ao assembly foi inserido com ";;":

 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
    }
}
Enter fullscreen mode Exit fullscreen mode

Com este exemplo foi possível identificar que para ler dados da stdin era necessário utilizar a instrução System.console().readLine() (linhas 11 e 16). E como readLine() retorna uma string, para lermos números era necessário converter com o uso da função Integer.parseInt (linha 17).

Dito isso, a partir do programa Pascal abaixo:

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.
Enter fullscreen mode Exit fullscreen mode

O POJ foi ajustado para gerar o seguinte 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
    }
}
Enter fullscreen mode Exit fullscreen mode

Este commit implementa as alterações necessárias no parser do POJ.

Aqui está o PR completo.

Próximos passos

Na próxima publicação vamos concluir um dos objetivos deste projeto: cálculo do fatorial de forma recursiva.

Código completo do projeto

O repositório com o código completo do projeto e a sua documentação está aqui.

💖 💪 🙅 🚩
alexgarzao
Alex Sandro Garzão

Posted on August 7, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Lendo dados da entrada padrão (stdin)
Novos operadores e a sentença if
compiling Novos operadores e a sentença if

April 4, 2024