DEV Community

Cover image for Lendo dados da entrada padrão (stdin)
Alex Sandro Garzão
Alex Sandro Garzão

Posted on

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.

Top comments (0)