Pagina 1 di 1

[JAVA] Compilatore BrainFuck

Inviato: gio 27 ago 2009, 15:25
da Porky
Ecco la mia ultima creazione in java: un compilatore per BrainFuck, il linguaggio di programmazione esoterico.

Download: http://porkynator.altervista.org/pbfi-1.1.zip

Sorgenti:

Main.java

Codice: Seleziona tutto

/*
Copyright 2009 Sebastiano Tronto <sebastiano@luganega.org>

This file is part of PBFI (Porky's Brain F*** Interpreter).

    PBFI is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    PBFI is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PBFI; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/

import javax.swing.JFrame;
import java.util.Scanner;
public class Main {
	public static Scanner scanner;
	public static char totalCode[], charCodeAux[], charCode[], chars;
	public static byte a[];
	public static int i;
	public static void main( String args[] ) {
		Frame frame = new Frame();
		frame.setSize( 200, 300 );
		frame.setVisible( true );
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	}
	public static void run( String code ) {
		chars = 'a';
		int j = 0;
		totalCode = code.toCharArray();
		charCodeAux = new char[totalCode.length*2];
		for ( int k = 0; k < totalCode.length; k++ ) {
			switch ( totalCode[k] ) {
				case '>':
				case '<':
				case '+':
				case '-':
				case '.':
				case ',':
					charCodeAux[j] = totalCode[k];
					j++;
					break;
				case '[':
					charCodeAux[j] = totalCode[k];
					j++;
					charCodeAux[j] = chars;
					chars++;
					j++;
					break;
				case ']':
					chars--;
					charCodeAux[j] = chars;
					j++;
					charCodeAux[j] = totalCode[k];
					j++;
					break;
			}
		}
		charCode = new char[j];
		for ( int k = 0; k < charCode.length; k++ )
			charCode[k] = charCodeAux[k];
		scanner = new Scanner( System.in );
		a = new byte[30000];
		for ( int count = 0; count < a.length; count++ )
			a[count] = 0;
		i = 0;
		execute( scanner, charCode, a, i, 0, charCode.length );
	}
	public static void execute( Scanner scanner, char charCode[], byte a[], int i, int start, int stop ) {
		for ( int count = start; count < stop; count++ ) {
			switch ( charCode[count] ) {
				case '>':
					i++;
					break;
				case '<':
					i--;
					break;
				case '+':
					a[i]++;
					break;
				case '-':
					a[i]--;
					break;
				case '.':
					System.out.print( (char) a[i] );
					break;
				case ',':
					String stringa = scanner.nextLine();
					a[i] = (byte) ( ( stringa.toCharArray() )[0] );
					break;
				case '[':
					if ( a[i] == 0 ) {
						count++;
						char key = charCode[count];
						count++;
						for ( ; charCode[count] != key; count++ ) ;
						count++;
					}
					break;
				case ']':
					if ( a[i] != 0 ) {
						count --;
						char key = charCode[count];
						count --;
						for ( ; charCode[count] != key; count-- ) ;
					}
					break;
			}
		}
	}
}
Frame.java

Codice: Seleziona tutto

/*
Copyright 2009 Sebastiano Tronto <sebastiano@luganega.org>

This file is part of PBFI (Porky's Brain F*** Interpreter).

    PBFI is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    PBFI is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with PBFI; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/

import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.io.*;

public class Frame extends JFrame {
public static int valoreChooser;
	public static boolean firstSave;
	public static String defaultSave;
	public static Main main;
	public static JTextArea textArea;
	public static JButton runButton;
	public static JMenuBar bar;
	public static JMenu menuFile, menuAiuto;
	public static JMenuItem esci, esegui, salva, salvaConNome, apri, info;
	public static JFileChooser chooser;
	public static FileInputStream in;
	public static FileOutputStream out;
		public Frame() {
		super( "Porky's BrainF** Interpreter - v1.1" );
		firstSave = true;
		main = new Main();
		defaultSave = "";
		chooser = new JFileChooser();
		textArea = new JTextArea( "Digitare qui il codice BrainF***", 15, 15 );
		bar = new JMenuBar();
		menuFile = new JMenu( "File" );
		menuAiuto = new JMenu( "?" );
		esci = new JMenuItem( "Esci" );
		esegui = new JMenuItem( "Esegui" );
		salva = new JMenuItem( "Salva" );
		salvaConNome = new JMenuItem( "Salva con nome" );
		apri = new JMenuItem( "Apri" );
		info = new JMenuItem( "Aiuto" );
		menuFile.setMnemonic( 'F' );
		menuAiuto.setMnemonic( '?' );
		esci.setMnemonic( 'E' );
		esegui.setMnemonic( 's' );
		salva.setMnemonic( 'a' );
		salvaConNome.setMnemonic( 'n' );
		apri.setMnemonic( 'p' );
		info.setMnemonic( 'i' );
		esci.addActionListener(
			new ActionListener() {
				public void actionPerformed ( ActionEvent e ) {
					System.exit( 0 );
				}
			}
		);
		esegui.addActionListener(
			new ActionListener() {
				public void actionPerformed ( ActionEvent e ) {
					main.run( textArea.getText() );
				}
			}
		);
		salva.addActionListener(
			new ActionListener() {
				public void actionPerformed ( ActionEvent e ) {
					if ( firstSave ) {
						valoreChooser = chooser.showSaveDialog( Frame.this );
						switch ( valoreChooser ) {
							case JFileChooser.APPROVE_OPTION:
								try {
									out = new FileOutputStream( chooser.getSelectedFile().getPath() );
									defaultSave = chooser.getSelectedFile().getPath();
									char caratteri[];
									byte bytes[];
									caratteri = textArea.getText().toCharArray();
									bytes = new byte[caratteri.length];
									for ( int i = 0; i <  caratteri.length; i++ )
										bytes[i] = ( byte ) caratteri[i];
									out.write( bytes );
								} catch ( Exception ex ) {
									JOptionPane.showMessageDialog( Frame.this, "Errore sconosciuto:\n\n" + ex + "\n\nPer favore riportare il bug a sebastiano@luganega.org", "Errore", JOptionPane.ERROR_MESSAGE );
								}
								break;
							case JFileChooser.ERROR_OPTION:
								JOptionPane.showMessageDialog( Frame.this, "Errore sconosciuto:\n\n" + e + "\n\nPer favore riportare il bug a sebastiano@luganega.org", "Errore", JOptionPane.ERROR_MESSAGE );
								break;
							//case JFileChooser.CANCEL_OPTION:
						}
						firstSave = false;
					} else {
						try {
							out = new FileOutputStream( defaultSave );
							char caratteri[];
							byte bytes[];
							caratteri = textArea.getText().toCharArray();
							bytes = new byte[caratteri.length];
							for ( int i = 0; i <  caratteri.length; i++ )
								bytes[i] = ( byte ) caratteri[i];
							out.write( bytes );
						} catch ( Exception ex ) {
							JOptionPane.showMessageDialog( Frame.this, "Errore sconosciuto:\n\n" + ex + "\n\nPer favore riportare il bug a sebastiano@luganega.org", "Errore", JOptionPane.ERROR_MESSAGE );
						}
					}
				}
			}
		);
		salvaConNome.addActionListener(
			new ActionListener() {
				public void actionPerformed ( ActionEvent e ) {
					valoreChooser = chooser.showSaveDialog( Frame.this );
					switch ( valoreChooser ) {
						case JFileChooser.APPROVE_OPTION:
							try {
								out = new FileOutputStream( chooser.getSelectedFile().getPath() );
								defaultSave = chooser.getSelectedFile().getPath();
								char caratteri[];
								byte bytes[];
								caratteri = textArea.getText().toCharArray();
								bytes = new byte[caratteri.length];
								for ( int i = 0; i <  caratteri.length; i++ )
									bytes[i] = ( byte ) caratteri[i];
								out.write( bytes );
							} catch ( Exception ex ) {
								JOptionPane.showMessageDialog( Frame.this, "Errore sconosciuto:\n\n" + ex + "\n\nPer favore riportare il bug a sebastiano@luganega.org", "Errore", JOptionPane.ERROR_MESSAGE );
							}
							break;
						case JFileChooser.ERROR_OPTION:
							JOptionPane.showMessageDialog( Frame.this, "Errore sconosciuto:\n\n" + e + "\n\nPer favore riportare il bug a sebastiano@luganega.org", "Errore", JOptionPane.ERROR_MESSAGE );
							break;
						//case JFileChooser.CANCEL_OPTION:
					}
					firstSave = false;
				}
			}
		);
		apri.addActionListener(
			new ActionListener() {
				public void actionPerformed ( ActionEvent e ) {
					valoreChooser = chooser.showOpenDialog( Frame.this );
					switch ( valoreChooser ) {
						case JFileChooser.APPROVE_OPTION:
							try {
								String stringa;
								byte bytes[];
								char caratteri[];
								in = new FileInputStream( chooser.getSelectedFile().getPath() );
								bytes = new byte[in.available()];
								caratteri = new char[in.available()];
								in.read( bytes );
								for ( int i = 0; i < bytes.length; i++ )
									caratteri[i] = ( char ) bytes[i];
								stringa = new String( caratteri );
								textArea.setText( stringa );
							} catch ( Exception ex ) {
								JOptionPane.showMessageDialog( Frame.this, "Errore sconosciuto:\n\n" + ex + "\n\nPer favore riportare il bug a sebastiano@luganega.org", "Errore", JOptionPane.ERROR_MESSAGE );
							}
							break;
						case JFileChooser.ERROR_OPTION:
							JOptionPane.showMessageDialog( Frame.this, "Errore sconosciuto:\n\n" + e + "\n\nPer favore riportare il bug a sebastiano@luganega.org", "Errore", JOptionPane.ERROR_MESSAGE );
							break;
						//case JFileChooser.CANCEL_OPTION:
					}
				}
			}
		);
		info.addActionListener(
			new ActionListener() {
				public void actionPerformed ( ActionEvent e ) {
					JOptionPane.showMessageDialog( Frame.this, "Brainfuck è un linguaggio di programmazione esoterico per computer,\ncreato da Urban Müller intorno al 1993. Il linguaggio viene\nin taluni casi denominato Brainf*ck, Brainf***\no anche soltanto BF per evitare di offendere\nla sensibilità altrui.\nNella directory src trovate alcuni esempi di programmi in questo linguaggio.\n\nPer maggiori informazioni visitate la pagina:\nhttp://it.wikipedia.org/wiki/Brainfuck", "BrainF*** - Informazioni", JOptionPane.INFORMATION_MESSAGE );
				}
			}
		);
		menuFile.add( esegui );
		menuFile.add( salva );
		menuFile.add( salvaConNome );
		menuFile.add( apri );
		menuFile.add( esci );
		menuAiuto.add( info );
		bar.add( menuFile );
		bar.add( menuAiuto );
		runButton = new JButton( "Esegui" );
		runButton.addActionListener(
			new ActionListener() {
				public void actionPerformed( ActionEvent e ) {
					main.run( textArea.getText() );
				}
			}
		);
		setLayout( new BorderLayout() );
		setJMenuBar( bar );
		add( new JScrollPane( textArea ), BorderLayout.CENTER );
		add( runButton, BorderLayout.SOUTH );
	}
}
Permette anche di salvare/aprire un progetto.

Riguardo alla gestione delle parentesi: non riuscivo a uscirne (scusate il gioco di parole), quindi ho usato questo " trucchetto": innanzitutto creo un array di char che contiene tutti i caratteri .,+-><[] che trova nella casella di testo e aggiunge un carattere (da 'a' in avanti) dopo ogni parentesi aperta e prima di ogni chiusa, in modo da segnare le corrispondenti. quindi se inserite il codice:

Codice: Seleziona tutto

codice casuale che non ho la minima idea di cosa faccia:
,+++++++[ dg< +++++++. [ -- <] [ ++ > [ +. <] --> ]>>]
il mio compilatore se lo traduce in :

Codice: Seleziona tutto

,+++++++[a<+++++++.[b --<b][b++>[c+.<c]-->b]>>a]
per riuscire a trovare le parentesi corrispondenti.
Ad esempio quando arriva a una parentesi aperta, se il byte al puntatore è 0, guarda il byte successivo e lo memorizza come "chiave", poi va avanti fino all'istruzione dopo la parentesi quadra chiusa che segue il successivo simbolo chiave.

Si lo so è un casino, mi sono scervellato 2 giorni (o erano 3? ho anche perso il conto...) per arrivarci.

Re: [JAVA] Compilatore BrainFuck

Inviato: gio 27 ago 2009, 16:49
da wakkokid
Per chi vuole divertirsi 10 minuti con questo linguaggio, segnalo il blog di un amico che ne ha implementato un debugger in Javascript
http://www.lordalcol.com/blog/2008/03/0 ... -debugger/