001: package ca.draisey.free.tprolog;
002:
003:
004:
005:
006:
007: import java.awt.BorderLayout;
008: import java.awt.event.ActionEvent;
009: import java.awt.event.ActionListener;
010: import java.awt.event.WindowAdapter;
011: import java.awt.event.WindowEvent;
012: import javax.swing.Box;
013: import javax.swing.BoxLayout;
014: import javax.swing.JButton;
015: import javax.swing.JFrame;
016: import javax.swing.JLabel;
017: import javax.swing.JTextField;
018: import javax.swing.JTextArea;
019: import javax.swing.JTree;
020: import javax.swing.JPanel;
021: import javax.swing.JScrollPane;
022: import javax.swing.JSplitPane;
023: import javax.swing.Timer;
024: import javax.swing.border.BevelBorder;
025: import javax.swing.border.SoftBevelBorder;
026: import javax.swing.text.Document;
027: import javax.swing.text.PlainDocument;
028: import javax.swing.tree.TreeModel;
029: import javax.swing.tree.DefaultTreeModel;
030: import javax.swing.tree.TreeNode;
031: import javax.swing.tree.MutableTreeNode;
032: import javax.swing.tree.DefaultMutableTreeNode;
033: import javax.swing.tree.TreePath;
034:
035:
036: public final class PrologGUI {
037:
038:
039: public static void main( final String[] argv )
040: {
041:
042: try {
043: final java.io.FileReader ginDefault = new java.io.FileReader( argv[0] );
044: final java.io.FileReader dinDefault = new java.io.FileReader( argv[1] );
045:
046: new PrologGUI().mainLoop( ginDefault, dinDefault );
047: }
048: catch( java.io.FileNotFoundException x ) {
049: }
050: }
051:
052:
053:
054: final Inter interpreter = new Inter();
055:
056:
057:
058: final JFrame mainFrame = new JFrame( "Trivial Prolog" );
059: {
060: mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
061: mainFrame.setSize( 600, 400 );
062: }
063:
064: final JPanel mainPanel = new JPanel();
065: {
066: mainPanel.setLayout( new BorderLayout() );
067: mainFrame.getContentPane().add( mainPanel );
068: }
069:
070: final JTextField goalText = new JTextField();
071: {
072: goalText.setBorder( new SoftBevelBorder( BevelBorder.LOWERED ) );
073: goalText.addActionListener( new ActionListener() {
074: public void actionPerformed( ActionEvent e )
075: {
076: interpreter.queryGoal( goalText.getText() );
077: }
078: } );
079: }
080:
081: final JButton querButton = new JButton( "Query!" );
082: {
083: querButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
084: querButton.addActionListener( new ActionListener() {
085: public void actionPerformed( ActionEvent e )
086: {
087: interpreter.queryGoal( goalText.getText() );
088: }
089: } );
090: }
091: {
092: final Box goalPanel = Box.createHorizontalBox();
093: {
094: goalPanel.add( new JLabel( "Goal:" ) );
095: goalPanel.add( goalText );
096: goalPanel.add( querButton );
097: }
098: mainPanel.add( goalPanel, BorderLayout.NORTH );
099: }
100:
101: final JTree dictTree = new JTree( new DefaultMutableTreeNode( "empty" ) );
102: {
103:
104: dictTree.setRootVisible( false );
105: dictTree.setShowsRootHandles( true );
106: }
107:
108: final JTree querTree = new JTree( new DefaultMutableTreeNode() );
109: {
110:
111: querTree.setRootVisible( false );
112: querTree.setShowsRootHandles( true );
113: }
114:
115: final DefaultTreeModel querTreeModel()
116: {
117: return (DefaultTreeModel) querTree.getModel();
118: }
119: final void querTreeReroot( DefaultMutableTreeNode rootNode )
120: {
121: querTreeModel().setRoot( rootNode );
122: }
123:
124: final JLabel querStatus = new JLabel( "ready." );
125: {
126: querStatus.setBorder( new SoftBevelBorder( BevelBorder.LOWERED ) );
127: }
128: final JButton pausButton = new JButton( "Pause!" );
129: final JButton aborButton = new JButton( "Abort!" );
130: {
131: pausButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
132: pausButton.setEnabled( false );
133: pausButton.addActionListener( new ActionListener() {
134: public void actionPerformed( ActionEvent e )
135: {
136: interpreter.togglePaused();
137: }
138: } );
139: aborButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
140: aborButton.setEnabled( false );
141: aborButton.addActionListener( new ActionListener() {
142: public void actionPerformed( ActionEvent e )
143: {
144: interpreter.abort();
145: }
146: } );
147: }
148: final JButton nextButton = new JButton( "Next Result!" );
149: final JButton omniButton = new JButton( "All Results!" );
150: {
151: nextButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
152: nextButton.setEnabled( false );
153: nextButton.addActionListener( new ActionListener() {
154: public void actionPerformed( ActionEvent e )
155: {
156: interpreter.next();
157: }
158: } );
159: omniButton.setBorder( new SoftBevelBorder( BevelBorder.RAISED ) );
160: omniButton.setEnabled( false );
161: omniButton.addActionListener( new ActionListener() {
162: public void actionPerformed( ActionEvent e )
163: {
164: interpreter.omni();
165: }
166: } );
167: }
168:
169: final void guiStatus( String state, boolean q, boolean p, boolean r, boolean a, boolean n )
170: {
171: querStatus.setText( state );
172: querButton.setEnabled( q );
173: pausButton.setEnabled( p );
174: if( r ) pausButton.setText( "Resume!" );
175: else pausButton.setText( "Pause!" );
176: aborButton.setEnabled( a );
177: nextButton.setEnabled( n );
178: omniButton.setEnabled( n );
179: }
180:
181: {
182: final JSplitPane centerPanel = new JSplitPane();
183: centerPanel.setResizeWeight( 0.5 );
184: centerPanel.setOneTouchExpandable( true );
185: centerPanel.setContinuousLayout( true );
186: {
187: final JPanel dictPanel = new JPanel();
188:
189: dictPanel.setLayout( new BorderLayout() );
190: dictPanel.add( new JLabel( "Dictionary:" ), BorderLayout.NORTH );
191: dictPanel.add( new JScrollPane( dictTree ), BorderLayout.CENTER );
192: centerPanel.setLeftComponent( dictPanel );
193: }
194: {
195: final JPanel querPanel = new JPanel();
196:
197: querPanel.setLayout( new BorderLayout() );
198: querPanel.add( new JLabel( "Result of Query:" ), BorderLayout.NORTH );
199: querPanel.add( new JScrollPane( querTree ), BorderLayout.CENTER );
200: {
201: final Box querControls = Box.createHorizontalBox();
202: querControls.add( Box.createGlue() );
203: querControls.add( nextButton );
204: querControls.add( omniButton );
205: querPanel.add( querControls, BorderLayout.SOUTH );
206: }
207: centerPanel.setRightComponent( querPanel );
208: }
209: mainPanel.add( centerPanel, BorderLayout.CENTER );
210: }
211:
212: {
213: final Box statPanel = Box.createHorizontalBox();
214: statPanel.add( new JLabel( "Interpreter:" ) );
215: statPanel.add( querStatus );
216: statPanel.add( Box.createGlue() );
217: statPanel.add( pausButton );
218: statPanel.add( aborButton );
219: mainPanel.add( statPanel, BorderLayout.SOUTH );
220: }
221:
222:
223: final void mainLoop( java.io.FileReader ginDefault, java.io.FileReader dinDefault )
224: {
225: try {
226: Parse.database( dinDefault, interpreter.database );
227: }
228: catch( IllegalArgumentException x ) {
229: }
230: ( (DefaultTreeModel) dictTree.getModel() ).setRoot( interpreter.database.viewDatabase() );
231: expandALevel( dictTree );
232: interpreter.queryGoal( ginDefault );
233: mainFrame.setVisible( true );
234: interpreter.mainLoop();
235: }
236:
237:
238:
239: final class Inter {
240:
241:
242: final GUIDatabase database = new GUIDatabase();
243:
244:
245: Sentence runningQuery = null;
246:
247:
248: boolean shortcircuited = false;
249:
250:
251: int userState = READY;
252:
253: static final int READY = 0;
254: static final int RUNNING = 1;
255: static final int WAITING = 2;
256: static final int PAUSED = 3;
257:
258: int runningState = READY;
259:
260:
261: DefaultMutableTreeNode successNode = null;
262:
263:
264:
265:
266: final Timer guiPolling = new Timer( 100, new ActionListener() {
267: public void actionPerformed( final ActionEvent e )
268: {
269: if( runningQuery == null ) guiPolling.stop();
270:
271:
272: if( successNode != null ) {
273: final DefaultTreeModel qM = querTreeModel();
274: final DefaultMutableTreeNode qR = (DefaultMutableTreeNode) qM.getRoot();
275: qM.insertNodeInto( successNode, qR, qR.getChildCount() );
276: querTree.expandPath( new TreePath( successNode.getPath() ) );
277: successNode = null;
278: synchronized( Inter.this ) {
279: Inter.this.notifyAll();
280: }
281: guiPolling.restart();
282: }
283:
284: if( runningState != oldRunningState ) {
285: guiState( runningState );
286: oldRunningState = runningState;
287: ticker = 0;
288: }
289: else if( runningState == RUNNING && ++ticker > 9 ) {
290: querStatus.setText( querStatus.getText() + "." );
291: ticker = 0;
292: }
293: }
294: int oldRunningState = -1;
295: int ticker = 0;
296: } );
297: {
298: guiPolling.setInitialDelay( 50 );
299: }
300:
301:
302:
303: final void queryGoal( final String g )
304: {
305: queryGoal( new java.io.StringReader( g ) );
306: }
307: final void queryGoal( final java.io.Reader gin )
308: {
309: try {
310: final Sentence query = Parse.goal( gin );
311: goalText.setText( query.toString() );
312: queryGoal( query );
313: }
314: catch( IllegalArgumentException x ) {
315: }
316: }
317: final synchronized void queryGoal( final Sentence query )
318: {
319: if( runningQuery == null ) {
320: final DefaultMutableTreeNode qR = new DefaultMutableTreeNode();
321: qR.add( new DefaultMutableTreeNode( query.toString(), false ) );
322: querTreeReroot( qR );
323: userState = RUNNING;
324: runningQuery = query;
325: notifyAll();
326: guiPolling.start();
327: }
328:
329: }
330: final synchronized void togglePaused()
331: {
332: if( runningState == RUNNING ) {
333: userState = PAUSED;
334: }
335: else if( runningState == PAUSED ) {
336: userState = RUNNING;
337: notifyAll();
338: }
339: }
340: final synchronized void abort()
341: {
342: userState = READY;
343: notifyAll();
344: }
345: final synchronized void next()
346: {
347: userState = RUNNING;
348: notifyAll();
349: }
350: final synchronized void omni()
351: {
352: userState = RUNNING;
353: shortcircuited = true;
354: notifyAll();
355: }
356: final void guiState( int state )
357: {
358: switch( state ) {
359: case READY:
360: guiStatus( "ready.", true, false, false, false, false );
361: return;
362: case RUNNING:
363: guiStatus( "running.", false, true, false, true, false );
364: return;
365: case WAITING:
366: guiStatus( "waiting.", false, false, false, true, true );
367: return;
368: case PAUSED:
369: guiStatus( "paused.", false, true, true, true, false );
370: return;
371: }
372: }
373:
374:
375:
376: final void mainLoop()
377: {
378: mainloop: for(;;) {
379: synchronized( this ) {
380: while( runningQuery == null ) uwait();
381: runningState = RUNNING;
382: shortcircuited = false;
383: }
384: database.viewableQuery( runningQuery, database.new GUISuccession() {
385:
386: void out( final int s, final DefaultMutableTreeNode snode )
387: {
388:
389: synchronized( Inter.this ) {
390: while( successNode != null ) Inter.this.uwait();
391: }
392: successNode = snode;
393: }
394:
395: void next()
396: {
397: if( ! shortcircuited )
398: synchronized( Inter.this ) {
399: if( userState != READY ) {
400: userState = runningState = WAITING;
401: while( userState == WAITING ) Inter.this.uwait();
402: }
403: }
404: monitor();
405: }
406:
407: void monitor()
408: {
409: Thread.yield();
410: if( userState == PAUSED ) {
411: synchronized( Inter.this ) {
412: runningState = PAUSED;
413: while( userState == PAUSED ) Inter.this.uwait();
414: }
415: }
416: if( userState == READY ) throw new MonitorException();
417: runningState = RUNNING;
418: }
419: } );
420: synchronized( this ) {
421: userState = runningState = READY;
422: runningQuery = null;
423: shortcircuited = false;
424: }
425: }
426:
427: }
428:
429: final void uwait()
430: {
431: try {
432: wait();
433: }
434: catch( InterruptedException x ) {
435: throw new RuntimeException( "Annoying InterruptedException" );
436: }
437: }
438: }
439:
440:
441:
442: static void expandALevel( final JTree tree )
443: {
444: final DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot();
445: for( int i = 0, n = root.getChildCount(); i < n; ++i ) {
446:
447:
448:
449: }
450: }
451: }
452:
453:
Prolog in Java
A trivial prolog interpreter written in java.
Copyright 2004, M.E.J.Draisey
This file is part of tprologinjava.
tprologinjava 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.
tprologinjava 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 tprologinjava; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Formatted with
GNU source-highlight:
http:// www.gnu.org/ software/ src-highlite