diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dd50574 --- /dev/null +++ b/.gitignore @@ -0,0 +1,204 @@ +*.tmp +pan.* + +*.iml +gen/ +.idea/ +*.ipr +*.iws +/out/ +.idea_modules/ +atlassian-ide-plugin.xml +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties + +## Core latex/pdflatex auxiliary files: +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.fmt +*.fot +*.cb +*.cb2 + +## Intermediate documents: +*.dvi +*-converted-to.* +# these rules might exclude image files for figures etc. +# *.ps +# *.eps +# *.pdf + +## Bibliography auxiliary files (bibtex/biblatex/biber): +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.brf +*.run.xml + +## Build tool auxiliary files: +*.fdb_latexmk +*.synctex +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync + +## Auxiliary and intermediate files from other packages: +# algorithms +*.alg +*.loa + +# achemso +acs-*.bib + +# amsthm +*.thm + +# beamer +*.nav +*.snm +*.vrb + +# cprotect +*.cpt + +# fixme +*.lox + +#(r)(e)ledmac/(r)(e)ledpar +*.end +*.?end +*.[1-9] +*.[1-9][0-9] +*.[1-9][0-9][0-9] +*.[1-9]R +*.[1-9][0-9]R +*.[1-9][0-9][0-9]R +*.eledsec[1-9] +*.eledsec[1-9]R +*.eledsec[1-9][0-9] +*.eledsec[1-9][0-9]R +*.eledsec[1-9][0-9][0-9] +*.eledsec[1-9][0-9][0-9]R + +# glossaries +*.acn +*.acr +*.glg +*.glo +*.gls +*.glsdefs + +# gnuplottex +*-gnuplottex-* + +# hyperref +*.brf + +# knitr +*-concordance.tex +# TODO Comment the next line if you want to keep your tikz graphics files +*.tikz +*-tikzDictionary + +# listings +*.lol + +# makeidx +*.idx +*.ilg +*.ind +*.ist + +# minitoc +*.maf +*.mlf +*.mlt +*.mtc +*.mtc[0-9] +*.mtc[1-9][0-9] + +# minted +_minted* +*.pyg + +# morewrites +*.mw + +# mylatexformat +*.fmt + +# nomencl +*.nlo + +# sagetex +*.sagetex.sage +*.sagetex.py +*.sagetex.scmd + +# sympy +*.sout +*.sympy +sympy-plots-for-*.tex/ + +# pdfcomment +*.upa +*.upb + +# pythontex +*.pytxcode +pythontex-files-*/ + +# thmtools +*.loe + +# TikZ & PGF +*.dpth +*.md5 +*.auxlock + +# todonotes +*.tdo + +# xindy +*.xdy + +# xypic precompiled matrices +*.xyc + +# endfloat +*.ttt +*.fff + +# Latexian +TSWLatexianTemp* + +## Editors: +# WinEdt +*.bak +*.sav + +# Texpad +.texpadtmp + +# Kile +*.backup + +# KBibTeX +*~[0-9]* \ No newline at end of file diff --git a/docs/jspin-release.html b/docs/jspin-release.html index 676106b..485ae4f 100644 --- a/docs/jspin-release.html +++ b/docs/jspin-release.html @@ -1,63 +1,63 @@ - - - -jSpin - Release Notes - - - -
jSpin - Release Notes
- -

Version 5.0 (12.12.10)
-  Adapted for Spin Version 6: -different output format and internal LTL formulas. - -

Version 4.7 (05.03.10)
-  Add menu entry Settings/Negate LTL -and the associated configuration file option NEGATE_LTL which -controls whether LTL formulas are automatically negated or not.
-  Changed the button Trail to Guided to be consistent: -random simulation, interactive simulation, guided simulation. - -

Version 4.6
-The divider locations and the width of the interactive select -buttons can be saved in the configuration file after changing them -interactively. STATEMENT_WIDTH can be changed interactively. -The installation directory may have spaces. - -

Version 4.5.1
Fix a bug when an LTL formula contains spaces. - -

Version 4.5
Improvements to interactive simulation. - -

Version 4.4
Configuration file can be in current or installation -directory. - -

Version 4.3.1
Fixes a serious bug introduced in 4.3. - -

Version 4.3
Standalone filter program. Integration of user manuals. - -

Version 4.2.2
Self-installing archive and relative path names. - -

Version 4.2.1
For random simulation the seed can be set. - -

Version 4.2
New Version of SpinSpider for graphically -displaying the Promela source as automata. Help, About and raw files now -displayed in the right text area. - -

Version 4.1.3
Minor fixes: The full error line from a -verification is displayed. The fonts on option panes are fixed. - -

Version 4.1.2
The default configuration values are changed -to point to the bin subdirectory for installing minimal binaries for -Spin and dot. For non-Windows systems such as Mac OS X: the compilation -target is specified as Java 1.5. The SINGLE_QUOTE option -enables the use of single quotes when translating an LTL formula. - -

Version 4.1.1
Not released. - -

Version 4.1
Lines numbers appear in the filtered simulation output. - -

Version 4.0
Includes the new SpinSpider and an improved -interface for running it. - - + + + +jSpin - Release Notes + + + +

jSpin - Release Notes
+ +

Version 5.0 (12.12.10)
+  Adapted for Spin Version 6: +different output format and internal LTL formulas. + +

Version 4.7 (05.03.10)
+  Add menu entry Settings/Negate LTL +and the associated configuration file option NEGATE_LTL which +controls whether LTL formulas are automatically negated or not.
+  Changed the button Trail to Guided to be consistent: +random simulation, interactive simulation, guided simulation. + +

Version 4.6
+The divider locations and the width of the interactive select +buttons can be saved in the configuration file after changing them +interactively. STATEMENT_WIDTH can be changed interactively. +The installation directory may have spaces. + +

Version 4.5.1
Fix a bug when an LTL formula contains spaces. + +

Version 4.5
Improvements to interactive simulation. + +

Version 4.4
Configuration file can be in current or installation +directory. + +

Version 4.3.1
Fixes a serious bug introduced in 4.3. + +

Version 4.3
Standalone filter program. Integration of user manuals. + +

Version 4.2.2
Self-installing archive and relative path names. + +

Version 4.2.1
For random simulation the seed can be set. + +

Version 4.2
New Version of SpinSpider for graphically +displaying the Promela source as automata. Help, About and raw files now +displayed in the right text area. + +

Version 4.1.3
Minor fixes: The full error line from a +verification is displayed. The fonts on option panes are fixed. + +

Version 4.1.2
The default configuration values are changed +to point to the bin subdirectory for installing minimal binaries for +Spin and dot. For non-Windows systems such as Mac OS X: the compilation +target is specified as Java 1.5. The SINGLE_QUOTE option +enables the use of single quotes when translating an LTL formula. + +

Version 4.1.1
Not released. + +

Version 4.1
Lines numbers appear in the filtered simulation output. + +

Version 4.0
Includes the new SpinSpider and an improved +interface for running it. + + \ No newline at end of file diff --git a/docs/jspin-user.tex b/docs/jspin-user.tex index 74a0d6d..de841f1 100644 --- a/docs/jspin-user.tex +++ b/docs/jspin-user.tex @@ -1,1003 +1,1003 @@ -\documentclass[11pt]{article} -\usepackage{mathpazo} -\usepackage{url} -\usepackage{graphicx} -\usepackage{verbatim} - -\newcommand{\spn}{\textsc{Spin}} -\newcommand{\prm}{\textsc{Promela}} -\newcommand{\js}{\textsc{jSpin}} -\newcommand{\spd}{\textsc{SpinSpider}} -\newcommand{\fil}{\textsc{FilterSpin}} -\newcommand{\dt}{\textsc{dot}} -\newcommand{\dtf}{\texttt{dot}} -\newcommand{\fsm}{\texttt{fsm}} -\newcommand{\p}[1]{\texttt{#1}} -\newcommand{\bu}[1]{\textsf{#1}} - -\textwidth=15cm -\textheight=22cm -\topmargin=0pt -\headheight=0pt -\oddsidemargin=1cm -\headsep=0pt -\renewcommand{\baselinestretch}{1.1} -\setlength{\parskip}{0.20\baselineskip plus 1pt minus 1pt} -\parindent=0pt - -\title{\js{} - Java GUI for \spn{}\\User's Guide\\\mbox{}\\\large{Version 5.0}} -\author{Mordechai (Moti) Ben-Ari\\ -Department of Science Teaching\\ -Weizmann Institute of Science\\ -Rehovot 76100 Israel\\ -\textsf{http://stwww.weizmann.ac.il/g-cs/benari/}} -%\date{} -\begin{document} -\maketitle -\thispagestyle{empty} - -\vfill - -\begin{center} -Copyright (c) 2003-10 by Mordechai (Moti) Ben-Ari. -\end{center} -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.2 -or any later version published by the Free Software Foundation; -with Invariant Section ``Introduction,'' no Front-Cover Texts, and no -Back-Cover Texts. A copy of the license is included in the file -\p{fdl.txt} included in this archive. -\newpage - -\section{Introduction} - -\subsection{\js{}} -\js{} is a graphical user interface for the \spn{} Model Checker that is -used for verifying concurrent and distributed programs. It is an -alternative to the \textsc{XSpin} GUI and was developed primarily for -pedagogical purposes. \js{} is written in Java, because the Java -platform is both portable and widely used in computer science education. -The user interface of \js{} is simple, consisting of a single window -with menus, a toolbar and three adjustable text areas. \spn{} option -strings are automatically supplied and the \spn{} output is filtered and -formatted. All aspects of \js{} are configurable: some at compile time, -some at initialization through a configuration file and some at runtime. -The filtering algorithm in \js{} can also be run as a standalone -program. - -\subsection{\spd{}} -\js{} includes the \spd{} tool for creating a graphical representation for -the state diagram of a \prm{} program by postprocessor the \spn{} output. -\spd{} is integrated into \js{}, but it can also be run as a standalone program. - -\spd{} generates the complete state diagram of a \prm{} program; the -diagrams are useful for demonstrating properties of concurrent programming. -Consider the \emph{third attempt} at solving the critical section problem (line -numbers added): -\begin{verbatim} -1. bool wantp = false, wantq = false; -2. -3. active proctype p() { -4. do :: wantp = true; -5. !wantq; -6. wantp = false; -7. od -8. } -9. -10. active proctype q() { -11. do :: wantq = true; -12. !wantp; -13. wantq = false; -14. od -15. } -\end{verbatim} -The processes \p{p} and \p{q} are in their critical sections if they are at -lines~6 and~13, respectively. The figure on the next page shows the state -diagram for this program. Each node contains the source code lines (and line -numbers) for the two processes and the values of the variables \p{wantp} and -\p{wantq}. The arrows show the possible transitions between states. Since no -state has the processes together at lines~6 and~13 mutual exclusion is -achieved. It is easy to see there is a computation that leads to deadlock in -the state with \p{p} at line~5 and \p{q} at line~15. -\begin{figure}[!htb] -\begin{center} -\includegraphics[width=6cm,keepaspectratio=true]{third.png} -\end{center} -\end{figure} - -\spd{} processes output of the \p{pan} verifier in order to create the full -state diagram of a program. The diagram is produced in \dtf{} format and -(optionally) the \dt{} program can be run to produce a graphics file. -\spd{} can also produce state diagrams in \fsm{} format used by visualization -tools developed at the Technische Universiteit Eindhoven (see the URLs below). - -\subsection{References} -\begin{itemize} -\item M. Ben-Ari. \textit{Principles of the Spin Model Checker}. Springer, 2008. -\item M. Ben-Ari. \textit{Principles of Concurrent and Distributed Programming (Second -Edition)}. Addison-Wesley, 2006. -\item Gerard J. Holzmann. \textit{The Spin Model Checker: Primer -and Reference Manual}.\\Addison-Wesley, 2004. -\end{itemize} - -\subsection{URLs} - -\begin{tabular}{l@{\hspace{3em}}l} -\hline -\fsm{} & \url{http://www.win.tue.nl/~fvham/fsm/}\\ - & \url{http://www.mcrl2.org/}\\ -\textsc{Graphviz (dot)} & \url{http://www.graphviz.org/}\\ -\js{} & \url{http://stwww.weizmann.ac.il/g-cs/benari/jspin/}\\ -\textsc{MinGW} & \url{http://mingw.org/}\\ -\spn{} & \url{http://spinroot.com/}\\ -\hline -\end{tabular} - -\subsection{Acknowledgement} -I would like to thank Gerard J. Holzmann for his generous assistance throughout the -development of this project. - -\section{Installation and execution} - -\subsection{Requirements} -\begin{itemize} - -\item \js{} requires that the Java SDK or JRE (at least version 1.5) be -installed.\footnote{The default font for \js{} is \p{Lucida Sans -Typewriter}. This font may no longer be available in the JRE you use. If -you have the fonts from a previous version you can copy them to the -\p{lib/fonts} directory as explained in -\url{http://java.sun.com/j2se/1.5.0/docs/guide/intl/font.html}. -Alternatively, you can change the configuration file to use a monospaced -font such as \p{Courier} that is installed by default.} - -\end{itemize} - -\subsection{Installation} -This section describes installation on a Windows system; -for custom installation and for other systems, see Appendix~\ref{a.install}. - -\begin{itemize} -\item Download the \js{} installation file called \p{jspin-N.exe}, -where \p{N} is the version number. -Execute the installation file. -\item Create a directory \verb=c:\mingw= and download the C -compiler archive \p{mingw.exe} into that directory. Execute this self-extracting file. -\end{itemize} - -\subsection{Configuring and running \js{}} -\begin{itemize} -\item The installation will create the following subdirectories: \p{docs} for the -documentation, \p{jspin} and \p{spinSpider} for the source files, -\p{txts} for the text files -(help, about and copyright), and \p{jspin-examples} and \p{spider-examples} -for example programs. -\item To run \js{}, execute the command \p{javaw -jar jSpin.jar}. -An optional argument names the \prm{} file to be opened initially. -A batch file \p{run.bat} is supplied which contains this command. -\item Configuration data (Appendix~\ref{a.cfg}) is in the file -\p{config.cfg}. -\textbf{When upgrading \js{}, erase the configuration file before installing -a new version, so that new configuration options will be recognized.} -\item \js{} searches for the configuration file in the current -directory; if it is not found, \js{} searches for it in the directory -where the jar file is installed; if it is not found there, a new file -with default values is written. -\end{itemize} - -\subsection{Running \spd{} without \js{}*} -If you want to run \spd{} without \js{}, create a configuration file -with entries for the \p{SPIN}, \p{C\_COMPILER}, \p{PAN} and \p{DOT} -commands. The prologues for the \dtf{} file can be changed in -\p{Config.java} in the package \p{spinSpider}. - -The \p{SpinSpider} class has a main method that can be invoked from a command -line: -\begin{verbatim} -java -cp jSpin.jar spinSpider.SpinSpider arguments filename -\end{verbatim} -\p{filename} is the source file name. The arguments are: - -\hspace*{1cm} -\begin{tabular}{ll} -\p{-pn} & The number of processes \p{n};\\ -\p{-vname} & One parameter for each variable \p{name};\\ -\p{-dot} & \dtf{} format;\\ -\p{-Txxx} & \dtf{} format followed by conversion to \p{xxx} format,\\ -& the default is \p{png};\\ -\p{-fsm} & \fsm{} format;\\ -\p{-t1} & Emphasize trail;\\ -\p{-t2} & Display the trail only;\\ -\p{-a} & Display automata for \prm{} source;\\ -\p{-small} & Small size for states; if absent, large size is used;\\ -\p{-bold} & Bold for emphasis; if absent, color is used.\\ -\p{-debug} & Write debug file;\\ -\end{tabular}\\ -\noindent{}The \p{-p} and \p{-v} arguments must be given (unless \p{-a} is selected). - -\subsection{Running \fil{} without \js{}*} -To run \fil{} from the command line, first create a file with the output -of a (random or guided) simulation: -\begin{verbatim} - spin -p -l -g -r -s -X src.pml > src.raw -\end{verbatim} -Next, run \fil{}: -\begin{verbatim} - java -cp jSpin.jar filterSpin.FilterSpin src.raw -\end{verbatim} -There are two optional arguments: \p{-v} to give a list of excluded -variables and \p{-s} to give a list of excluded statements, as described -in Section~\ref{s.filter}. The arguments may be file names or lists of -identifiers separated with a separator string (by default \p{"\#"}, but -it can be changed in \p{Config.java}\footnote{Do not use a backslash or -dollar sign.}). At least one separator must be given so that the -argument is not interpreted as a file name): -\begin{verbatim} - java -cp jSpin.jar filterSpin.FilterSpin -v "temp#i" -s "i+1#" src.raw -\end{verbatim} -The filtered output is sent to standard output and can be piped or -redirected as needed. The configuration file must contain values for the -properties listed in Appendix~\ref{a.cfg} under \emph{filter settings}. - -\section{\js{} Overview} -The user interface includes a menu, a toolbar and three text areas. -Menu and toolbar commands have keyboard mnemonics or accelerators. -These can be easily configured by modifying the file \p{Config.java} and -rebuilding. - -The left text area is used to display \prm{} source files. The bottom -text area is used to display messages from both \spn{} and \js{}. The -right text area is used to display the output from \spn{}: statements -executed, values of variables and results of verifications. The text -areas can be resized by dragging the dividers and an area can be hidden -by clicking on the triangles in the dividers; the initial sizes can be -set in the configuration file. The toolbar button \bu{Maximize} (with -its mnemonic \bu{Alt-M}) toggles between a normal split pane and a -maximized right text area that displays the \spn{} output. - -\begin{figure}[tb] -\begin{center} -\includegraphics[width=140mm]{jspin.png} -\end{center} -\end{figure} - -\begin{description} -\item[\bu{File}] This menu includes selections for \bu{New}, \bu{Open}, -\bu{Save}, \bu{Save As}, and \bu{Exit}. \bu{Switch file} closes the -current file and opens the last file that was edited, if any. This is -useful for working with both a source file and an included file. - -\item[\bu{Edit}] This menu includes selections for \bu{Undo}, \bu{Redo}, -\bu{Copy}, \bu{Cut}, \bu{Paste}, \bu{Find} and \bu{Find again}. - -\item[\bu{Options}] This menu enables you to edit the option strings for -each of the phases of execution of \spn{} and the C compiler. Normally, you -will not need to change the options except for those that are more -conveniently changed in \bu{Options/Common} or \bu{Settings} -(Section~\ref{s.run}). \bu{Default} restores the default -values and \bu{Save} saves the current set of option strings in the -configuration file. In addition, the following configuration items are -automatically saved: -\begin{itemize} -\item \p{SOURCE\_DIRECTORY}: the last directory from which a source file was opened. -\item The current values of the splitpane dividers \p{TB\_DIVIDER} and -\p{LR\_DIVIDER}. -\item The current value of the width \p{SELECT\_BUTTON} for interactive -simulation. -\end{itemize} -The file can be saved -to the \bu{current} or \bu{install} directory. \textbf{Changes in the -\spn{} options can cause the assumptions on the input to \p{filter} to -become falsified. Be careful!} - -\item[\bu{Settings}] This menu sets parameters for the simulation and -verification (Section~\ref{s.run}). - -\item[\bu{Output}] This menu controls the display of the simulation output -in the right text area. \bu{Output/Maximize} toggles the text area to be -maximized, hiding the editing area. \bu{Output/Save output} saves the -contents of the text area in a file with extension \p{.out}. -To debug the filtering algorithm, -select \bu{Output/Raw output} to write a file with extension -\p{.raw} that contains the raw \spn{} output; -\bu{Output/Display raw} will display this file. -The other items in this menu are discussed in Section~\ref{s.run}. - -\item[\bu{SpinSpider}] This menu enables interactive execution of the \spd{} -tool for creating graphical representations for the state diagram of a -\prm{} program. See the separate documentation for this tool. - -\item[\bu{Help}] \bu{Help} displays a short help file and \bu{About} -displays copyright information about the software. -\end{description} - -\section{Running \spn{}}\label{s.run} -In the \bu{Spin} menu (and on the toolbar) are five selections for -running \spn{}. They all use the \prm{} source file that has been opened, -and save the file before execution. -During simulation and verification, -you can select \bu{Stop} to terminate the \spn{} process that has been forked. -\begin{description} -\item[\bu{Check}] Runs a \emph{syntax check}. -\item[\bu{Random}] Runs a \emph{random simulation}. -\item[\bu{Interactive}] Runs an \emph{interactive simulation}. -\item[\bu{Guilded}] Runs a \emph{guided simulation} using the trail -file created by the execution of the analyzer. -\item[\bu{Verify}] Runs an \emph{verification}. -\end{description} -\textbf{If you terminate \js{} while \spn{} is running (for example by entering \bu{ctrl-C} from the -command line), make sure to terminate the \spn{} process as well.}\\ -In Windows this is done by pressing \bu{ctrl-alt-del}, followed by -selecting \bu{Task List} and \bu{Processes}. Select \bu{spin.exe} and -\bu{End Process}. - -\subsection{Simulation}\label{s.sim} -\bu{Check} should be run before any simulation run to ensure better display -of errors. - -\bu{Settings/Max steps} changes the \p{-u} option to limit the number of -simulation steps, and \bu{Settings/Max depth} changes the \p{-m} option -to limit the \p{pan} search depth. - -A nonzero value for \bu{Settings/Seed} will be used as the seed for generating -random numbers, enabling a random simulation to be repeated. - -\subsubsection{Interactive simulation} -During an interactive simulation, a dialog frame will pop up with a list -of statements that can be executed. The list can be displayed either as -a row of buttons, or---if there is not enough room---as a pulldown menu. -The choice of the format is dynamically determined according to the -value of the configuration option \p{SELECT\_MENU}. By setting this -value to an extreme, you can force the list to a certain format. There -are also configuration options for setting the width and height of the -buttons or menu items. - -The dialog can be navigated using the mouse; closing the dialog frame -will terminate interactive simulation. For keyboard navigation: -\begin{description} -\item[Buttons] \bu{Tab} and \bu{Shift-Tab} move through the buttons -and \bu{Space} selects the highlighted button. Press \bu{Esc} to terminate. -\item[Menu] Press down arrow to display the list and to highlight the -item you want; press \bu{Return} to select it. Press \bu{Esc} to terminate. -\end{description} - -\subsubsection{Filtered output}\label{s.filter} -The contents of the \spn{} output can be changed by selecting -\bu{Options/Common}. This pops up a dialog with check boxes to select the -\spn{} output options: statements (\p{-p}), local variables (\p{-l}), -global variables (\p{-g}), messages sent (\p{-s}) and messages received -(\p{-r}). - -Select \bu{Output/Exclude variables} to create a list of strings defining -variables to be \emph{excluded} from the display. Any variable containing -a string from the list is not displayed; for example, \p{:init:} will -exclude all variables of the \p{init} process. If the variable name is -prefixed by \p{+}, it will be included anyway. For exmple, if you have an -array variable \p{test}, then the entries \p{test} and \p{+[1]} will -exclude display of the elements of \p{test} except for \p{test[1]}. The -list is saved on a file with extension \p{.exc}. - -Similarly, a file of excluded statements can be created. The file -extension is \p{.exs} and it may be edited by selecting \bu{Output/Exclude -statements}. \bu{Exclude statements} should \emph{not} be used with -interactive simulation. - -The output strings from \p{printf} statements is displayed normally. Optionally, -you can request that only strings beginning with \p{MSC:} be displayed (\p{MSC=true}). - -\subsection{Verification} -Selecting \bu{Spin/Verify} or the \bu{Verify} button on the tool bar -performs the three steps required to verify a \prm{} program in \spn{}: -\begin{itemize} -\item Run \spn{} to create an analyzer in files \p{pan.*}. -\item Run the C compiler to compile the analyzer \p{pan.c}. -\item Run the analyzer \p{pan.exe}. -\end{itemize} -There are three modes of verification in \spn{}, -one of which must be selected from the combo box on the toolbar -or the radio buttons in the menu \bu{Settings}: -\begin{description} -\item[Safety] Checks basic safety properties such as assertions. -\item[Acceptance] Checks for acceptance cycles. -\item[Non-Progress] Checks that every cycle contains a -\p{progress} label. -\end{description} -See the \spn{} reference manual for descriptions of these modes. -Checking \bu{Weak fairness} in the menu \bu{Settings} -or on the toolbar performs the verification only for executions that are -weakly fair. - -\subsection{LTL formulas}\label{s.ltl} - -A correctness claim specified by a \emph{Linear Temporal Logic (LTL)} -formula must be converted to an automaton written as a \prm{} \p{never} -claim. LTL formulas can be contained within the \prm{} source code or -they can be placed in external files. - -\subsection{Internal formulas} - -An LTL formula can be included in a \prm{} program: -\begin{verbatim} -ltl { []<>csp && []<>csq } -\end{verbatim} -The formula is translated internally by \spn{} into a \p{never} claim. - -A number of \emph{named} formulas can be included within a \prm{} program: -\begin{verbatim} -ltl p0 { [](gate <= 1) } -ltl p1 { []((count == 0) -> (gate == 0)) } -ltl p2 { [](((gate == 0) && notInTest) -> (count == 0)) } -\end{verbatim} -To select which claim will be used in a verification, enter the -\emph{name} in the \bu{LTL formula} text field and select \bu{LTL name}. - -The above examples show that internal LTL formulas can have expressions -and not just names as atomic propositions. - -\textbf{\spn{} automatically negates LTL formulas contained within a -\prm{} program.} - -\subsubsection{External formulas} - -Enter a formula (such as \p{[]p} or \p{<>p}) in the text field labelled -\bu{LTL formula} on the menu bar and select \bu{Translate} from the -toolbar or the \bu{Convert} menu; the formula translated into a -\p{never} claim which will be added to the next \spn{} verification. The -\p{never} claim is stored in a file with extension \p{.ltl}. The formula -is not automatically translated, so whatever \p{never} claim exists, if -any, will continue to be used until \bu{Translate} is invoked again. - -\textbf{Before the formula is translated it is negated by \js}. This is -done so that the LTL formula as displayed represents the correctness -property being checked and not the negated formula which if satisfied -represents a counterexample. Should you wish to enter negations yourself -as in \spn{}, you can change the configuration file option -\p{NEGATE\_LTL} to false; this can also be done by toggling -\bu{Settings/Negate LTL}. - -LTL formulas are saved in \emph{property files} with extension \p{.prp}. -By default, when you open a \prm{} file, -\js{} opens and loads a \p{.prp} file of the same name. -You can also load a different file by selecting \bu{Load} from -the toolbar or the \bu{Convert} menu; -the file name will be displayed on the toolbar. -If the file does not exist, -the text field is cleared and the new name is used when you \bu{Translate} the formula -you enter. - -The property file is saved whenever the source file is -and also before translation. - -\bu{Convert/Clear} not only to clears the text field, but ensures that -no LTL formula will be used in the next verification. After selecting -\bu{Convert/Clear} an empty file will not be saved. Note: In earlier -versions of \js{}, a button \bu{Clear} was available on the toolbar; -this has now been removed and the menu selection must be used. - -\section{\spd{}} -Open a \prm{} program. If you wish to emphasize or draw the computation -described by a \p{trail} file, execute \spn{} in verification mode with -appropriate assertions or LTL formulas to create the trail file for a counterexample. - -Select \bu{SpinSpider/SpinSpider} (\bu{ctrl-D}) from the menu or \bu{SpinSpider} -from the toolbar and the following frame will appear: -\begin{center} -\includegraphics[width=9cm,keepaspectratio=true]{spd.png} -\end{center} -\begin{description} -\item[\bu{Format}] The output format, normally \bu{dot} or one of the formats -such as \bu{png} that can be obtained by running \dt{}. The \bu{fsm} format is -experimental and the processing of the trail file is not done for this format. -\textbf{If \p{png} is selected as the format, the state diagram will be displayed in a -separate frame when \spd{} has terminated.} -\item[\bu{Processes}] The number of processes in the program (for generation of -the \p{never} claim). -\item[\bu{Variables}] A list of the variables in the program (for generation of -the \p{never} claim). -\item[\bu{No trail}, \bu{Emphasize trail}, \bu{Only trail}] If the first option -is selected, the entire state diagram is created. The second option colors nodes -and edges in the state diagram that are part of the trail. The third option -creates a diagram containing only those states and nodes that are part of the -trail. -\item[\bu{Automata}] This displays the source of the \prm{} program as a set -of automata, one for each \p{proctype}; for the \emph{third attempt}, this is: -\begin{center} -\includegraphics[width=7cm,keepaspectratio=true]{third-automata.png} -\end{center} -The states are labeled with the source code line numbers and the edges with -the statements associated with each transition. \p{atomic} transitions -are emphasized. -\item[\bu{Dot size}] Chooses between two prologues for the \dtf{} file. The small -option works better for display within \js{}. -\item[\bu{Trail style}] Chooses between two ways of emphasizing the trail in a -computation: in color or bold. The latter is useful for including the diagram in -a document or for users with difficulty seeing colors. -\item[\bu{Debug}] Writes a file (extension \p{.dbg}) with the internal data -structures as collected from the execution of \spn{}: states, transitions, -statements and the trail. -(The file is automatically generated if \bu{Automata} is selected.) -This file can be displayed by selecting -\bu{SpinSpider/Display debug} from the \js{} menu. -\item[\bu{Run}] Saves the current parameters in a file with the same name as the -source file and with extension \p{.spd}. Then \spd{} is run. -\item[\bu{Cancel}] Returns without saving the parameters or running \spd{}. -\end{description} - -\subsection{\prm{} programs for \spd{}} -The directory \bu{spider-examples} contains concurrent programs that demonstrate -the use of \spd{}. - -To reduce the size of the diagrams, use \emph{remote references} rather than -ghost variables in the specification of correctness properties. For example, to -prover that mutual exclusion holds in the third attempt (\p{third.pml}), declare -labels \p{cs:} at the two critical sections and then define the symbol: -\begin{verbatim} -#define notmutex (p@cs && q@cs) -\end{verbatim} -Mutual exclusion can shown by doing a verification in \bu{Safety} mode -with the LTL formula: -\begin{verbatim} -!<>notmutex -\end{verbatim} -Recall that \spn{} finds the \emph{first} counterexample in a depth-first -search, not the shortest one. The trail for the program for the fourth -attempt (\p{fourth.pml}) was created by running \p{pan} with the \p{-i} -parameter to do an iterative search for a short counterexample. - -The line numbers will be accurate if the first alternative of a \p{do}- or -\p{if}-statement is written on the same line as the keyword. Note that all -alternatives are considered to belong to the line containing the keyword. - -%\newpage - -\section{Troubleshooting} -\begin{description} -\item[\spn{} won't execute] Check the configuration items -for \spn{} and the C compiler. -It is recommended that they be in your path. -\item[Exceptions in Filter] Your own output might be -interfering with the filtering algorithm. -If configuration option \p{MSC} is selected, use \p{printf} only with strings -prefixed by \p{MSC:} and terminated by a newline. -\item[Verification doesn't seem to work] -Make sure that you have selected the appropriate mode -from the \bu{Settings} menu: -\bu{Safety}, \bu{Acceptance}, \bu{Non-progress}. -If you are using an LTL formula, -\bu{Translate} it before verifying. -\item[Your computer works slowly] Forked processes for \spn{} are still executing. -Terminate them from the operating system. -\item[Settings, options and the directory aren't remembered] -You must select \bu{Options/Save} before exiting \spn{}. -\item[Preprocessing failed] Simple preprocessing like the use of \verb=#define= -is done internally by \spn{}. For more complicated processing, \spn{} calls the -C compiler's preprocessor. This error message can result if there is a problem -with the installation; check also that the C compiler is in the path. -To debug preprocessing, execute \spn{} with the argument \p{-I}; -this will perform preprocessing only on the \prm{} file and display the result. -\end{description} - -\newpage - -\section{Software structure*} -The software is divided into three Java packages. - -\subsection{Package \p{jspin}} -\p{jSpin} is the main class and contains declarations -of the GUI components and instances -of the classes \p{Editor} and \p{RunSpin}. -Method \p{init} and the methods it calls initialize the GUI. -Method \p{action\-Per\-formed} is the event handler for all the menu items -and buttons; it calls the appropriate methods for handling each event. -The \bu{About} and \bu{Help} options are implemented by reading files -\p{copyright.txt} and \p{help.txt}, respectively, and displaying -them in a \p{JFrame} with a scrollable \p{JTextArea}. - -\p{JSpinFileFilter} is used with a \p{JFileChooser} -when opening and saving files: \prm{} source files, -LTL property files and \spn{} display output files. - -\p{Options} is the dialog frame with check boxes for -changing the \spn{} display options. - -\p{Exclude} is the dialog frame for editing the list -of variable strings to be excluded from the display. - -\p{Config} contains declarations of compile time configuration items. -Method \p{init} calls \p{set\-Default\-Properties} to initialize the instance -of \p{Properties} with the default values of the dynamic configuration -items; it then attempts to load the configuration file, and if unsuccessful, -the default properties are written to a new file. - -\p{Editor} implements an editor using operations on a -\p{JTextArea}. It implements the interface \p{Document\-Listener} to flag -when the source has been modified. The class is also responsible -for the LTL formula \p{JTextField}. \p{jSpin} calls method \p{writeFile} -to write \p{ltl} and \p{out} files, and method \p{readFile} to read -the text files to be displayed. - -\p{LineNumbers} extends a \p{JComponent} to create line numbers -for the \p{RowHeaderView} of the editor \p{JScrollPane} -(thanks to Niko Myller for this code). - -\p{UndoRedo} was extracted from an example on the Java web site. - -The event handler in \p{jSpin} calls \p{run} in class \p{RunSpin} -to execute \spn{}, the C compiler and the analyzer \p{pan}. -\p{run} creates a thread of class \p{RunThread}, -and uses \p{ProcessBuilder} to set up the -command, directory, merge the output and error streams, -and set up streams for I/O. -The call \p{runAndWait} is used for short calls like \bu{Check} -and the creation and compilation of a model; -this call does not return until the completion of the subprocess. -The call \p{run} will return immediately after it has created the thread. -In this case, the event handler in \p{jSpin} calls \p{isSpinRunning} -to create a thread to poll for termination of \spn{}; -by creating a separate thread, the event handler is freed to accept -a selection of \bu{Stop}. - -When \p{Select a statement} is received during an interactive simulation, -method \p{select} is called. -This method displays the choices in the bottom text area and pops up a -dialog to enable the user to make a selection. -A \p{JFrame} is created in a new thread of the inner class \p{SelectDialog} to wait -for the selection. -\p{select} polls \p{selectedValue} which is set with the selected button -value or zero if the frame is closed or \bu{Esc} pressed. -In that case, \p{q} is sent to \spn{} to terminate the simulation. - -\js{} contains source code for interactively invoking \spd{}. -The class \p{SpiderOptions} pops up frame where parameters can be entered and -\spd{} invoked. Each \prm{} file can have its own set of parameters; these are stored -in property files with extension \p{.spd} and managed by \p{SpiderFile}. -If the diagram is created in \bu{PNG} format, it is displayed interactively: -\p{DisplayImage} creates a frame and -the image is loaded into an instance of \p{ImagePanel}. - -\subsection{Package \p{filterSpin}} - -The output filtering is encapsulated in class \p{Filter}. -For each line received from the output stream, \p{run} -(of \p{RunThread}) calls \p{filter} -which modifies the string; the modified string is displayed in the -appropriate text area. -A \p{TreeMap} is maintained for mapping variable names into value strings. -Each new variable is checked against the list of excluded strings before -it is entered in the map. -For standalone filtering, the package -contains a \p{Config} class and a class \p{FilterSpin} with a main method. - -\subsection{Package \p{spinSpider}} - -Most of the processing of the \spd{} program is done -in the class \p{SpinSpider}. -Static data like strings and the prologue for the \dtf{} file are -contained in the class \p{Config}. - -Four classes are used for -objects containing information extracted from the files: -\begin{itemize} -\item \p{State} contains the program counter values and the variables names -and values that are extracted from the output of the \p{never} claim in the -\p{.chk} file. -\item \p{Transition} contains the transitions and is obtained by following -the \p{New}, \p{Old}, \p{Up} and \p{Down} debugging trace in the \p{.chk} file. -A stack is used to simulate the depth-first search of \spn{}. -\item \p{Statement} contains the states, line numbers and source statements -from the \p{.d} file. -\item \p{Trail} contains the \p{id} of an entry in the trail file. -\end{itemize} -The processing sequence is invoked from the method \p{runSpider}. -\p{runProcess} is called several times to fork processes as described in -Section~\ref{s.how}. The \p{.d} file is analyzed in \p{createStatements}, -and the \p{.chk} file is analyzed in \p{readCheckFile} of class \p{Read}. -If requested, these data structures are written to a file in method -\p{writeDebug} of class \p{Write}. - -The class \p{SetTrail} traverses the state diagram according to the trail and -marks states and transitions that are part of the trail. - -The data structures are used to write the files in class \p{Write}. -See the description of the \fsm{} format to understand \p{writeFSMGraph}. -In \p{writeDOTGraph}, the \p{states} array is traversed sequentially -writing out numbered nodes including labels for each node. The -elements of this array store the program counters of each process in the -state; these are used to search the \p{statements} array for \emph{all} -statements that start from the program counter. The line numbers and -source code of the statements are appended to the label. The variable -values are also obtained from the \p{states} array. The transitions are -taken directly from the \p{transitions} array. Finally, \dt{} is called, if -requested. - -The class \p{DrawAutomata} uses the information in the \p{.d} file -to write a \dtf{} file and then calls \dt{}. - -\subsection{How \spd{} works}\label{s.how} - -\spd{} works with numerous files: -\begin{itemize} -\item The source file with extension \p{.pml}. -\item A \p{never} claim file with extension \p{.nvr} as described below; -this is normally generated automatically. -\item The file with extension \p{.chk} obtained by running a verification of -the program with the \p{-DCHECK} option and with the \p{never} claim that -prints out the program counters and variable values. -\item The statement file with extension \p{.d} obtained by running a verification -with the \p{-d} option. -\item A file with extension \p{.spd} that is used by \js{} to save \spd{} parameters. -\item A debug file with extension \p{.dbg}. -\end{itemize} - -\spd{} runs the following commands in subprocesses (\p{prog.pml} is the source file): - -\hspace*{1cm}\p{spin -a prog.pml}\\ -\hspace*{1cm}\p{gcc -DCHECK -DSAFETY -DPRINTF -o pan pan.c}\\ -\hspace*{1cm}\p{pan > prog.chk}\\ -\hspace*{1cm}\p{pan -d > prog.d} - -Then it runs its own algorithm to create a \dtf{} file. Finally, \dt{} is -optionally run to create a display file in some format like \p{png}. - -A \prm{} program must be modified by giving a special \p{never} claim; this is -generated automatically and included using the \p{-N} argument to \spn{}. - -The \p{never} claim contains a single \p{printf} statement in a loop, which is -executed with every step of the verifier. The statement prints the -following tokens separated by spaces: -\begin{itemize} -\item The string \p{*spd*}; -\item The number of processes, followed by the values of \p{pc\_value} -for each process; -\item The number of variables, followed by their names and values. -\end{itemize} -For the algorithm shown in the introduction the \p{never} claim is: -\begin{verbatim} -never { - do :: printf("*spd* 2 %d %d 2 wantp %d wantq %d \n", - pc_value(0), pc_value(1), wantp, wantq) - od -} -\end{verbatim} - -\newpage - -\appendix - -\section{Installation}\label{a.install} - -\subsection{\spn{} version} - -Version 6.0.0 of \spn{} changed its output format; starting with version -5.0, \js{} expects this format. You can still run \js{} with earlier -versions of \spn{} (for example, 4.30): set the configuration option -\p{VERSION} to a number less than 6 before you run \js{} and ensure that -the option \p{SPIN} names the earlier version of the \spn{} executable -(or copy the file over the later version). - -\subsection{Custom installation of \js{}} -\begin{itemize} -\item Download the \js{} distribution file called \p{jspin-N.zip}, -where \p{N} is the version number. -Extract the files into a clean directory. -%\textbf{Do not} install to a directory with spaces like \verb=c:\Program Files=. - -\item Install \spn{} and \textsc{dot} (\textsc{dot} is only needed for -\textsc{SpinSpider}). - -\item Install an ANSI C compiler. - -\item Modify the configuration file \p{config.cfg} to reflect the -locations of the programs. -\end{itemize} - -\subsection{Building \js{}} - -To rebuild \js{}, execute \p{build.bat}, which will compile all the source -files and create the file \p{jSpin.jar} with the manifest file. - -\subsection{Installing a C compiler}\label{a.c} -The \p{gcc} compiler is normally used with \spn{}. On Windows, there are -two distributions: Cygwin (\url{http://cygwin.com}) is a comprehensive -Linux-like environment, and a smaller distribution called MinGW -(\url{http://mingw.org/}). To install MinGW, download the following archives and -open them in directory \verb=c:\mingw= \emph{in the following order}: -\begin{quote} -\p{binutils-V.tar.gz}\\ -\p{gcc-core-V.tar.gz}\\ -\p{mingw-runtime-V.tar.gz}\\ -\p{w32api-V.tar.gz} -\end{quote} -where V is the version and build number. -It is OK if some files are overwritten when opening the archive. - -Set the path in -\begin{quote} -\p{Start/Control Panel/System/Advanced/Environment Variables/PATH} -\end{quote} -to include \verb=c:\mingw\bin=. - -\subsection{Installing \js{} on \textsc{Mac OS X}}\label{a.mac} - -Thanks to Christiaan Ottow for providing this material. - -Currently, there is no precompiled version of \spn{}, so you will have to -compile it from the source code. Instructions for doing this are given -in Section~2c of the webpage: -\begin{quote} -\url{http://spinroot.com/spin/Man/README.html} -\end{quote} -An alternative approach is change the location of the preprocessor specified in -lines 75--88 of \p{main.c} from \p{/lib/cpp} to \p{/usr/bin/cpp}. - -\js{} is compiled with \p{-target 1.5} to conform with the \textsc{Java} -version currently available on the \textsc{Mac}. - -To install \js{}: -\begin{itemize} -\item Unzip the file \p{jspin-V-V.zip}. -\item Download \textsc{Graphviz} from -\begin{quote} -\url{http://www.pixelglow.com/graphviz/download} -\end{quote} -Open the \p{dmg} file you downloaded and copy the \textsc{Graphviz} -application to the Applications folder. -\item Open the configuration file \p{config.cfg} in a text editor and change the -values of the following properties: -\begin{itemize} -\item \p{SPIN} to the directory with the compiled \spn{}; -\item \p{SOURCE\_DIRECTORY} to the subdirectory \p{jspin-examples} of the directory -where you unpacked \js{}; -\item \p{C\_COMPILER} to directory containing \p{gcc}, -usually \p{/usr/bin/gcc}. You can verify this by issuing the command \p{which gcc}; -\item \p{PAN} to \p{pan}; -\item \p{DOT} to \p{/Applications/Graphviz.app/Contents/MacOS/dot}. -\end{itemize} -\end{itemize} - -\js{} can now be run by using the \p{Terminal} to execute the following command -in the \p{jspin} directory: -\begin{quote} -\p{java jspin.jSpin} -\end{quote} - -\subsection{Installing \js{} on \textsc{Linux}}\label{a.linux} - -Thanks to Vsevolod Krishchenko for providing this material. - -\begin{itemize} - -\item Install gcc, C preprocessor, dot, java. For Debian/Ubuntu: -\begin{verbatim} - sudo apt-get install gcc cpp graphviz sun-java6-jre -\end{verbatim} -\item Install spin as described above. -\item Make the following changes in \p{config.cfg}: -\begin{verbatim} - C_COMPILER=gcc - DOT=dot -\end{verbatim} -You many need to set \p{SINGLE\_QUOTE} to \p{true}. -\item Create a shell file with: -\begin{verbatim} - #!/bin/sh - java -jar jSpin.jar -\end{verbatim} -\end{itemize} - -\section{Configuration file}\label{a.cfg} - -These tables give the properties in the configuration file and their -default values. - -\begin{center} - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Version of \spn{}}\\ \hline -\textsc{\ttfamily VERSION} &\verb+6+\\\hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Directories for source and compilers}\\ \hline -\textsc{\ttfamily SOURCE\_DIRECTORY} & \verb+"jspin-examples"+ \\ -\textsc{\ttfamily C\_COMPILER} &\verb+"c:\\mingw\\bin\\gcc.exe"+ \\ -\textsc{\ttfamily SPIN} &\verb+"bin\\spin.exe"+ \\ -\textsc{\ttfamily DOT} &\verb+"bin\\dot.exe"+ \\ -\textsc{\ttfamily PAN} &\verb+"pan"+ \\ \hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Options for executing \spn{}}\\ \hline -\textsc{\ttfamily COMMON\_OPTIONS} &\verb+"-g -l -p -r -s"+\\ -\textsc{\ttfamily CHECK\_OPTIONS} &\verb+"-a -v"+\\ -\textsc{\ttfamily RANDOM\_OPTIONS} &\verb+"-X"+\\ -\textsc{\ttfamily INTERACTIVE\_OPTIONS} &\verb+"-i -X"+\\ -\textsc{\ttfamily VERIFY\_OPTIONS} &\verb+"-a"+\\ -\textsc{\ttfamily C\_COMPILER\_OPTIONS} &\verb+"-o pan pan.c"+\\ -\textsc{\ttfamily PAN\_OPTIONS} &\verb+"-X"+\\ -\textsc{\ttfamily TRAIL\_OPTIONS} &\verb+"-t -X"+\\ -\textsc{\ttfamily TRANSLATE\_OPTIONS} &\verb+"-f"+\\ -\textsc{\ttfamily MAX\_STEPS} {\ttfamily (-u)} & \verb+250+\\ -\textsc{\ttfamily MAX\_DEPTH} {\ttfamily (-m)} & \verb+2000+\\ -\textsc{\ttfamily SEED} {\ttfamily (-n)} & \verb+0+\\ -\textsc{\ttfamily FAIRNESS} & \verb+true+\\ -\textsc{\ttfamily RAW} & \verb+false+\\ -\textsc{\ttfamily SINGLE\_QUOTE} & \verb+false+\\ -\textsc{\ttfamily NEGATE\_LTL} & \verb+true+\\ -\textsc{\ttfamily VERIFY\_MODE} & \verb+"Safety"+\\\hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Filter settings}\\ \hline -\textsc{\ttfamily PROCESS\_TITLE} & \verb+Process +\\ -\textsc{\ttfamily PROCESS\_WIDTH} & \verb+7+\\ -\textsc{\ttfamily STATEMENT\_TITLE} & \verb+Statement +\\ -\textsc{\ttfamily STATEMENT\_WIDTH} & \verb+18+\\ -\textsc{\ttfamily VARIABLE\_WIDTH} &\verb+10+\\ -\textsc{\ttfamily LINES\_PER\_TITLE} &\verb+20+\\ -\textsc{\ttfamily MSC} &\verb+false+\\ -\hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Text settings}\\ \hline -\textsc{\ttfamily WRAP} &\verb+true+\\ -\textsc{\ttfamily TAB\_SIZE} &\verb+4+\\ -\textsc{\ttfamily FONT\_FAMILY} & \verb+"Lucida Sans Typewriter"+\\ -\textsc{\ttfamily FONT\_STYLE} & \verb+java.awt.Font.PLAIN+\\ -\textsc{\ttfamily FONT\_SIZE} & \verb+14+\\\hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Frame size}\\ \hline -\textsc{\ttfamily WIDTH} &\verb+1000+\\ -\textsc{\ttfamily HEIGHT} &\verb+700+\\\hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Interactive dialog settings}\\ \hline -\textsc{\ttfamily SELECT\_BUTTON} &\verb+120+\\ -\textsc{\ttfamily SELECT\_HEIGHT} &\verb+70+\\ -\textsc{\ttfamily SELECT\_MENU} &\verb+5+\\\hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Location of dividers}\\ \hline -\textsc{\ttfamily LR\_DIVIDER} &\verb+400+\\ -\textsc{\ttfamily TB\_DIVIDER} &\verb+500+\\ -\textsc{\ttfamily MIN\_DIVIDER} &\verb+50+\\\hline -\end{tabular} - -\bigskip - -\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} -\hline -\multicolumn{2}{|c|}{Delay while waiting for user input}\\ \hline -\textsc{\ttfamily POLLING\_DELAY} &\verb+200+\\\hline -\end{tabular} - -\end{center} - -\end{document} +\documentclass[11pt]{article} +\usepackage{mathpazo} +\usepackage{url} +\usepackage{graphicx} +\usepackage{verbatim} + +\newcommand{\spn}{\textsc{Spin}} +\newcommand{\prm}{\textsc{Promela}} +\newcommand{\js}{\textsc{jSpin}} +\newcommand{\spd}{\textsc{SpinSpider}} +\newcommand{\fil}{\textsc{FilterSpin}} +\newcommand{\dt}{\textsc{dot}} +\newcommand{\dtf}{\texttt{dot}} +\newcommand{\fsm}{\texttt{fsm}} +\newcommand{\p}[1]{\texttt{#1}} +\newcommand{\bu}[1]{\textsf{#1}} + +\textwidth=15cm +\textheight=22cm +\topmargin=0pt +\headheight=0pt +\oddsidemargin=1cm +\headsep=0pt +\renewcommand{\baselinestretch}{1.1} +\setlength{\parskip}{0.20\baselineskip plus 1pt minus 1pt} +\parindent=0pt + +\title{\js{} - Java GUI for \spn{}\\User's Guide\\\mbox{}\\\large{Version 5.0}} +\author{Mordechai (Moti) Ben-Ari\\ +Department of Science Teaching\\ +Weizmann Institute of Science\\ +Rehovot 76100 Israel\\ +\textsf{http://stwww.weizmann.ac.il/g-cs/benari/}} +%\date{} +\begin{document} +\maketitle +\thispagestyle{empty} + +\vfill + +\begin{center} +Copyright (c) 2003-10 by Mordechai (Moti) Ben-Ari. +\end{center} +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.2 +or any later version published by the Free Software Foundation; +with Invariant Section ``Introduction,'' no Front-Cover Texts, and no +Back-Cover Texts. A copy of the license is included in the file +\p{fdl.txt} included in this archive. +\newpage + +\section{Introduction} + +\subsection{\js{}} +\js{} is a graphical user interface for the \spn{} Model Checker that is +used for verifying concurrent and distributed programs. It is an +alternative to the \textsc{XSpin} GUI and was developed primarily for +pedagogical purposes. \js{} is written in Java, because the Java +platform is both portable and widely used in computer science education. +The user interface of \js{} is simple, consisting of a single window +with menus, a toolbar and three adjustable text areas. \spn{} option +strings are automatically supplied and the \spn{} output is filtered and +formatted. All aspects of \js{} are configurable: some at compile time, +some at initialization through a configuration file and some at runtime. +The filtering algorithm in \js{} can also be run as a standalone +program. + +\subsection{\spd{}} +\js{} includes the \spd{} tool for creating a graphical representation for +the state diagram of a \prm{} program by postprocessor the \spn{} output. +\spd{} is integrated into \js{}, but it can also be run as a standalone program. + +\spd{} generates the complete state diagram of a \prm{} program; the +diagrams are useful for demonstrating properties of concurrent programming. +Consider the \emph{third attempt} at solving the critical section problem (line +numbers added): +\begin{verbatim} +1. bool wantp = false, wantq = false; +2. +3. active proctype p() { +4. do :: wantp = true; +5. !wantq; +6. wantp = false; +7. od +8. } +9. +10. active proctype q() { +11. do :: wantq = true; +12. !wantp; +13. wantq = false; +14. od +15. } +\end{verbatim} +The processes \p{p} and \p{q} are in their critical sections if they are at +lines~6 and~13, respectively. The figure on the next page shows the state +diagram for this program. Each node contains the source code lines (and line +numbers) for the two processes and the values of the variables \p{wantp} and +\p{wantq}. The arrows show the possible transitions between states. Since no +state has the processes together at lines~6 and~13 mutual exclusion is +achieved. It is easy to see there is a computation that leads to deadlock in +the state with \p{p} at line~5 and \p{q} at line~15. +\begin{figure}[!htb] +\begin{center} +\includegraphics[width=6cm,keepaspectratio=true]{third.png} +\end{center} +\end{figure} + +\spd{} processes output of the \p{pan} verifier in order to create the full +state diagram of a program. The diagram is produced in \dtf{} format and +(optionally) the \dt{} program can be run to produce a graphics file. +\spd{} can also produce state diagrams in \fsm{} format used by visualization +tools developed at the Technische Universiteit Eindhoven (see the URLs below). + +\subsection{References} +\begin{itemize} +\item M. Ben-Ari. \textit{Principles of the Spin Model Checker}. Springer, 2008. +\item M. Ben-Ari. \textit{Principles of Concurrent and Distributed Programming (Second +Edition)}. Addison-Wesley, 2006. +\item Gerard J. Holzmann. \textit{The Spin Model Checker: Primer +and Reference Manual}.\\Addison-Wesley, 2004. +\end{itemize} + +\subsection{URLs} + +\begin{tabular}{l@{\hspace{3em}}l} +\hline +\fsm{} & \url{http://www.win.tue.nl/~fvham/fsm/}\\ + & \url{http://www.mcrl2.org/}\\ +\textsc{Graphviz (dot)} & \url{http://www.graphviz.org/}\\ +\js{} & \url{http://stwww.weizmann.ac.il/g-cs/benari/com.spinroot.jspin/}\\ +\textsc{MinGW} & \url{http://mingw.org/}\\ +\spn{} & \url{http://spinroot.com/}\\ +\hline +\end{tabular} + +\subsection{Acknowledgement} +I would like to thank Gerard J. Holzmann for his generous assistance throughout the +development of this project. + +\section{Installation and execution} + +\subsection{Requirements} +\begin{itemize} + +\item \js{} requires that the Java SDK or JRE (at least version 1.5) be +installed.\footnote{The default font for \js{} is \p{Lucida Sans +Typewriter}. This font may no longer be available in the JRE you use. If +you have the fonts from a previous version you can copy them to the +\p{lib/fonts} directory as explained in +\url{http://java.sun.com/j2se/1.5.0/docs/guide/intl/font.html}. +Alternatively, you can change the configuration file to use a monospaced +font such as \p{Courier} that is installed by default.} + +\end{itemize} + +\subsection{Installation} +This section describes installation on a Windows system; +for custom installation and for other systems, see Appendix~\ref{a.install}. + +\begin{itemize} +\item Download the \js{} installation file called \p{com.spinroot.jspin-N.exe}, +where \p{N} is the version number. +Execute the installation file. +\item Create a directory \verb=c:\mingw= and download the C +compiler archive \p{mingw.exe} into that directory. Execute this self-extracting file. +\end{itemize} + +\subsection{Configuring and running \js{}} +\begin{itemize} +\item The installation will create the following subdirectories: \p{docs} for the +documentation, \p{com.spinroot.jspin} and \p{com.spinroot.spinSpider} for the source files, +\p{txts} for the text files +(help, about and copyright), and \p{com.spinroot.jspin-examples} and \p{spider-examples} +for example programs. +\item To run \js{}, execute the command \p{javaw -jar jSpin.jar}. +An optional argument names the \prm{} file to be opened initially. +A batch file \p{run.bat} is supplied which contains this command. +\item Configuration data (Appendix~\ref{a.cfg}) is in the file +\p{config.cfg}. +\textbf{When upgrading \js{}, erase the configuration file before installing +a new version, so that new configuration options will be recognized.} +\item \js{} searches for the configuration file in the current +directory; if it is not found, \js{} searches for it in the directory +where the jar file is installed; if it is not found there, a new file +with default values is written. +\end{itemize} + +\subsection{Running \spd{} without \js{}*} +If you want to run \spd{} without \js{}, create a configuration file +with entries for the \p{SPIN}, \p{C\_COMPILER}, \p{PAN} and \p{DOT} +commands. The prologues for the \dtf{} file can be changed in +\p{Config.java} in the package \p{com.spinroot.spinSpider}. + +The \p{SpinSpider} class has a main method that can be invoked from a command +line: +\begin{verbatim} +java -cp jSpin.jar com.spinroot.spinSpider.SpinSpider arguments filename +\end{verbatim} +\p{filename} is the source file name. The arguments are: + +\hspace*{1cm} +\begin{tabular}{ll} +\p{-pn} & The number of processes \p{n};\\ +\p{-vname} & One parameter for each variable \p{name};\\ +\p{-dot} & \dtf{} format;\\ +\p{-Txxx} & \dtf{} format followed by conversion to \p{xxx} format,\\ +& the default is \p{png};\\ +\p{-fsm} & \fsm{} format;\\ +\p{-t1} & Emphasize trail;\\ +\p{-t2} & Display the trail only;\\ +\p{-a} & Display automata for \prm{} source;\\ +\p{-small} & Small size for states; if absent, large size is used;\\ +\p{-bold} & Bold for emphasis; if absent, color is used.\\ +\p{-debug} & Write debug file;\\ +\end{tabular}\\ +\noindent{}The \p{-p} and \p{-v} arguments must be given (unless \p{-a} is selected). + +\subsection{Running \fil{} without \js{}*} +To run \fil{} from the command line, first create a file with the output +of a (random or guided) simulation: +\begin{verbatim} + spin -p -l -g -r -s -X src.pml > src.raw +\end{verbatim} +Next, run \fil{}: +\begin{verbatim} + java -cp jSpin.jar com.spinroot.filterSpin.FilterSpin src.raw +\end{verbatim} +There are two optional arguments: \p{-v} to give a list of excluded +variables and \p{-s} to give a list of excluded statements, as described +in Section~\ref{s.filter}. The arguments may be file names or lists of +identifiers separated with a separator string (by default \p{"\#"}, but +it can be changed in \p{Config.java}\footnote{Do not use a backslash or +dollar sign.}). At least one separator must be given so that the +argument is not interpreted as a file name): +\begin{verbatim} + java -cp jSpin.jar com.spinroot.filterSpin.FilterSpin -v "temp#i" -s "i+1#" src.raw +\end{verbatim} +The filtered output is sent to standard output and can be piped or +redirected as needed. The configuration file must contain values for the +properties listed in Appendix~\ref{a.cfg} under \emph{filter settings}. + +\section{\js{} Overview} +The user interface includes a menu, a toolbar and three text areas. +Menu and toolbar commands have keyboard mnemonics or accelerators. +These can be easily configured by modifying the file \p{Config.java} and +rebuilding. + +The left text area is used to display \prm{} source files. The bottom +text area is used to display messages from both \spn{} and \js{}. The +right text area is used to display the output from \spn{}: statements +executed, values of variables and results of verifications. The text +areas can be resized by dragging the dividers and an area can be hidden +by clicking on the triangles in the dividers; the initial sizes can be +set in the configuration file. The toolbar button \bu{Maximize} (with +its mnemonic \bu{Alt-M}) toggles between a normal split pane and a +maximized right text area that displays the \spn{} output. + +\begin{figure}[tb] +\begin{center} +\includegraphics[width=140mm]{com.spinroot.jspin.png} +\end{center} +\end{figure} + +\begin{description} +\item[\bu{File}] This menu includes selections for \bu{New}, \bu{Open}, +\bu{Save}, \bu{Save As}, and \bu{Exit}. \bu{Switch file} closes the +current file and opens the last file that was edited, if any. This is +useful for working with both a source file and an included file. + +\item[\bu{Edit}] This menu includes selections for \bu{Undo}, \bu{Redo}, +\bu{Copy}, \bu{Cut}, \bu{Paste}, \bu{Find} and \bu{Find again}. + +\item[\bu{Options}] This menu enables you to edit the option strings for +each of the phases of execution of \spn{} and the C compiler. Normally, you +will not need to change the options except for those that are more +conveniently changed in \bu{Options/Common} or \bu{Settings} +(Section~\ref{s.run}). \bu{Default} restores the default +values and \bu{Save} saves the current set of option strings in the +configuration file. In addition, the following configuration items are +automatically saved: +\begin{itemize} +\item \p{SOURCE\_DIRECTORY}: the last directory from which a source file was opened. +\item The current values of the splitpane dividers \p{TB\_DIVIDER} and +\p{LR\_DIVIDER}. +\item The current value of the width \p{SELECT\_BUTTON} for interactive +simulation. +\end{itemize} +The file can be saved +to the \bu{current} or \bu{install} directory. \textbf{Changes in the +\spn{} options can cause the assumptions on the input to \p{filter} to +become falsified. Be careful!} + +\item[\bu{Settings}] This menu sets parameters for the simulation and +verification (Section~\ref{s.run}). + +\item[\bu{Output}] This menu controls the display of the simulation output +in the right text area. \bu{Output/Maximize} toggles the text area to be +maximized, hiding the editing area. \bu{Output/Save output} saves the +contents of the text area in a file with extension \p{.out}. +To debug the filtering algorithm, +select \bu{Output/Raw output} to write a file with extension +\p{.raw} that contains the raw \spn{} output; +\bu{Output/Display raw} will display this file. +The other items in this menu are discussed in Section~\ref{s.run}. + +\item[\bu{SpinSpider}] This menu enables interactive execution of the \spd{} +tool for creating graphical representations for the state diagram of a +\prm{} program. See the separate documentation for this tool. + +\item[\bu{Help}] \bu{Help} displays a short help file and \bu{About} +displays copyright information about the software. +\end{description} + +\section{Running \spn{}}\label{s.run} +In the \bu{Spin} menu (and on the toolbar) are five selections for +running \spn{}. They all use the \prm{} source file that has been opened, +and save the file before execution. +During simulation and verification, +you can select \bu{Stop} to terminate the \spn{} process that has been forked. +\begin{description} +\item[\bu{Check}] Runs a \emph{syntax check}. +\item[\bu{Random}] Runs a \emph{random simulation}. +\item[\bu{Interactive}] Runs an \emph{interactive simulation}. +\item[\bu{Guilded}] Runs a \emph{guided simulation} using the trail +file created by the execution of the analyzer. +\item[\bu{Verify}] Runs an \emph{verification}. +\end{description} +\textbf{If you terminate \js{} while \spn{} is running (for example by entering \bu{ctrl-C} from the +command line), make sure to terminate the \spn{} process as well.}\\ +In Windows this is done by pressing \bu{ctrl-alt-del}, followed by +selecting \bu{Task List} and \bu{Processes}. Select \bu{spin.exe} and +\bu{End Process}. + +\subsection{Simulation}\label{s.sim} +\bu{Check} should be run before any simulation run to ensure better display +of errors. + +\bu{Settings/Max steps} changes the \p{-u} option to limit the number of +simulation steps, and \bu{Settings/Max depth} changes the \p{-m} option +to limit the \p{pan} search depth. + +A nonzero value for \bu{Settings/Seed} will be used as the seed for generating +random numbers, enabling a random simulation to be repeated. + +\subsubsection{Interactive simulation} +During an interactive simulation, a dialog frame will pop up with a list +of statements that can be executed. The list can be displayed either as +a row of buttons, or---if there is not enough room---as a pulldown menu. +The choice of the format is dynamically determined according to the +value of the configuration option \p{SELECT\_MENU}. By setting this +value to an extreme, you can force the list to a certain format. There +are also configuration options for setting the width and height of the +buttons or menu items. + +The dialog can be navigated using the mouse; closing the dialog frame +will terminate interactive simulation. For keyboard navigation: +\begin{description} +\item[Buttons] \bu{Tab} and \bu{Shift-Tab} move through the buttons +and \bu{Space} selects the highlighted button. Press \bu{Esc} to terminate. +\item[Menu] Press down arrow to display the list and to highlight the +item you want; press \bu{Return} to select it. Press \bu{Esc} to terminate. +\end{description} + +\subsubsection{Filtered output}\label{s.filter} +The contents of the \spn{} output can be changed by selecting +\bu{Options/Common}. This pops up a dialog with check boxes to select the +\spn{} output options: statements (\p{-p}), local variables (\p{-l}), +global variables (\p{-g}), messages sent (\p{-s}) and messages received +(\p{-r}). + +Select \bu{Output/Exclude variables} to create a list of strings defining +variables to be \emph{excluded} from the display. Any variable containing +a string from the list is not displayed; for example, \p{:init:} will +exclude all variables of the \p{init} process. If the variable name is +prefixed by \p{+}, it will be included anyway. For exmple, if you have an +array variable \p{test}, then the entries \p{test} and \p{+[1]} will +exclude display of the elements of \p{test} except for \p{test[1]}. The +list is saved on a file with extension \p{.exc}. + +Similarly, a file of excluded statements can be created. The file +extension is \p{.exs} and it may be edited by selecting \bu{Output/Exclude +statements}. \bu{Exclude statements} should \emph{not} be used with +interactive simulation. + +The output strings from \p{printf} statements is displayed normally. Optionally, +you can request that only strings beginning with \p{MSC:} be displayed (\p{MSC=true}). + +\subsection{Verification} +Selecting \bu{Spin/Verify} or the \bu{Verify} button on the tool bar +performs the three steps required to verify a \prm{} program in \spn{}: +\begin{itemize} +\item Run \spn{} to create an analyzer in files \p{pan.*}. +\item Run the C compiler to compile the analyzer \p{pan.c}. +\item Run the analyzer \p{pan.exe}. +\end{itemize} +There are three modes of verification in \spn{}, +one of which must be selected from the combo box on the toolbar +or the radio buttons in the menu \bu{Settings}: +\begin{description} +\item[Safety] Checks basic safety properties such as assertions. +\item[Acceptance] Checks for acceptance cycles. +\item[Non-Progress] Checks that every cycle contains a +\p{progress} label. +\end{description} +See the \spn{} reference manual for descriptions of these modes. +Checking \bu{Weak fairness} in the menu \bu{Settings} +or on the toolbar performs the verification only for executions that are +weakly fair. + +\subsection{LTL formulas}\label{s.ltl} + +A correctness claim specified by a \emph{Linear Temporal Logic (LTL)} +formula must be converted to an automaton written as a \prm{} \p{never} +claim. LTL formulas can be contained within the \prm{} source code or +they can be placed in external files. + +\subsection{Internal formulas} + +An LTL formula can be included in a \prm{} program: +\begin{verbatim} +ltl { []<>csp && []<>csq } +\end{verbatim} +The formula is translated internally by \spn{} into a \p{never} claim. + +A number of \emph{named} formulas can be included within a \prm{} program: +\begin{verbatim} +ltl p0 { [](gate <= 1) } +ltl p1 { []((count == 0) -> (gate == 0)) } +ltl p2 { [](((gate == 0) && notInTest) -> (count == 0)) } +\end{verbatim} +To select which claim will be used in a verification, enter the +\emph{name} in the \bu{LTL formula} text field and select \bu{LTL name}. + +The above examples show that internal LTL formulas can have expressions +and not just names as atomic propositions. + +\textbf{\spn{} automatically negates LTL formulas contained within a +\prm{} program.} + +\subsubsection{External formulas} + +Enter a formula (such as \p{[]p} or \p{<>p}) in the text field labelled +\bu{LTL formula} on the menu bar and select \bu{Translate} from the +toolbar or the \bu{Convert} menu; the formula translated into a +\p{never} claim which will be added to the next \spn{} verification. The +\p{never} claim is stored in a file with extension \p{.ltl}. The formula +is not automatically translated, so whatever \p{never} claim exists, if +any, will continue to be used until \bu{Translate} is invoked again. + +\textbf{Before the formula is translated it is negated by \js}. This is +done so that the LTL formula as displayed represents the correctness +property being checked and not the negated formula which if satisfied +represents a counterexample. Should you wish to enter negations yourself +as in \spn{}, you can change the configuration file option +\p{NEGATE\_LTL} to false; this can also be done by toggling +\bu{Settings/Negate LTL}. + +LTL formulas are saved in \emph{property files} with extension \p{.prp}. +By default, when you open a \prm{} file, +\js{} opens and loads a \p{.prp} file of the same name. +You can also load a different file by selecting \bu{Load} from +the toolbar or the \bu{Convert} menu; +the file name will be displayed on the toolbar. +If the file does not exist, +the text field is cleared and the new name is used when you \bu{Translate} the formula +you enter. + +The property file is saved whenever the source file is +and also before translation. + +\bu{Convert/Clear} not only to clears the text field, but ensures that +no LTL formula will be used in the next verification. After selecting +\bu{Convert/Clear} an empty file will not be saved. Note: In earlier +versions of \js{}, a button \bu{Clear} was available on the toolbar; +this has now been removed and the menu selection must be used. + +\section{\spd{}} +Open a \prm{} program. If you wish to emphasize or draw the computation +described by a \p{trail} file, execute \spn{} in verification mode with +appropriate assertions or LTL formulas to create the trail file for a counterexample. + +Select \bu{SpinSpider/SpinSpider} (\bu{ctrl-D}) from the menu or \bu{SpinSpider} +from the toolbar and the following frame will appear: +\begin{center} +\includegraphics[width=9cm,keepaspectratio=true]{spd.png} +\end{center} +\begin{description} +\item[\bu{Format}] The output format, normally \bu{dot} or one of the formats +such as \bu{png} that can be obtained by running \dt{}. The \bu{fsm} format is +experimental and the processing of the trail file is not done for this format. +\textbf{If \p{png} is selected as the format, the state diagram will be displayed in a +separate frame when \spd{} has terminated.} +\item[\bu{Processes}] The number of processes in the program (for generation of +the \p{never} claim). +\item[\bu{Variables}] A list of the variables in the program (for generation of +the \p{never} claim). +\item[\bu{No trail}, \bu{Emphasize trail}, \bu{Only trail}] If the first option +is selected, the entire state diagram is created. The second option colors nodes +and edges in the state diagram that are part of the trail. The third option +creates a diagram containing only those states and nodes that are part of the +trail. +\item[\bu{Automata}] This displays the source of the \prm{} program as a set +of automata, one for each \p{proctype}; for the \emph{third attempt}, this is: +\begin{center} +\includegraphics[width=7cm,keepaspectratio=true]{third-automata.png} +\end{center} +The states are labeled with the source code line numbers and the edges with +the statements associated with each transition. \p{atomic} transitions +are emphasized. +\item[\bu{Dot size}] Chooses between two prologues for the \dtf{} file. The small +option works better for display within \js{}. +\item[\bu{Trail style}] Chooses between two ways of emphasizing the trail in a +computation: in color or bold. The latter is useful for including the diagram in +a document or for users with difficulty seeing colors. +\item[\bu{Debug}] Writes a file (extension \p{.dbg}) with the internal data +structures as collected from the execution of \spn{}: states, transitions, +statements and the trail. +(The file is automatically generated if \bu{Automata} is selected.) +This file can be displayed by selecting +\bu{SpinSpider/Display debug} from the \js{} menu. +\item[\bu{Run}] Saves the current parameters in a file with the same name as the +source file and with extension \p{.spd}. Then \spd{} is run. +\item[\bu{Cancel}] Returns without saving the parameters or running \spd{}. +\end{description} + +\subsection{\prm{} programs for \spd{}} +The directory \bu{spider-examples} contains concurrent programs that demonstrate +the use of \spd{}. + +To reduce the size of the diagrams, use \emph{remote references} rather than +ghost variables in the specification of correctness properties. For example, to +prover that mutual exclusion holds in the third attempt (\p{third.pml}), declare +labels \p{cs:} at the two critical sections and then define the symbol: +\begin{verbatim} +#define notmutex (p@cs && q@cs) +\end{verbatim} +Mutual exclusion can shown by doing a verification in \bu{Safety} mode +with the LTL formula: +\begin{verbatim} +!<>notmutex +\end{verbatim} +Recall that \spn{} finds the \emph{first} counterexample in a depth-first +search, not the shortest one. The trail for the program for the fourth +attempt (\p{fourth.pml}) was created by running \p{pan} with the \p{-i} +parameter to do an iterative search for a short counterexample. + +The line numbers will be accurate if the first alternative of a \p{do}- or +\p{if}-statement is written on the same line as the keyword. Note that all +alternatives are considered to belong to the line containing the keyword. + +%\newpage + +\section{Troubleshooting} +\begin{description} +\item[\spn{} won't execute] Check the configuration items +for \spn{} and the C compiler. +It is recommended that they be in your path. +\item[Exceptions in Filter] Your own output might be +interfering with the filtering algorithm. +If configuration option \p{MSC} is selected, use \p{printf} only with strings +prefixed by \p{MSC:} and terminated by a newline. +\item[Verification doesn't seem to work] +Make sure that you have selected the appropriate mode +from the \bu{Settings} menu: +\bu{Safety}, \bu{Acceptance}, \bu{Non-progress}. +If you are using an LTL formula, +\bu{Translate} it before verifying. +\item[Your computer works slowly] Forked processes for \spn{} are still executing. +Terminate them from the operating system. +\item[Settings, options and the directory aren't remembered] +You must select \bu{Options/Save} before exiting \spn{}. +\item[Preprocessing failed] Simple preprocessing like the use of \verb=#define= +is done internally by \spn{}. For more complicated processing, \spn{} calls the +C compiler's preprocessor. This error message can result if there is a problem +with the installation; check also that the C compiler is in the path. +To debug preprocessing, execute \spn{} with the argument \p{-I}; +this will perform preprocessing only on the \prm{} file and display the result. +\end{description} + +\newpage + +\section{Software structure*} +The software is divided into three Java packages. + +\subsection{Package \p{com.spinroot.jspin}} +\p{jSpin} is the main class and contains declarations +of the GUI components and instances +of the classes \p{Editor} and \p{RunSpin}. +Method \p{init} and the methods it calls initialize the GUI. +Method \p{action\-Per\-formed} is the event handler for all the menu items +and buttons; it calls the appropriate methods for handling each event. +The \bu{About} and \bu{Help} options are implemented by reading files +\p{copyright.txt} and \p{help.txt}, respectively, and displaying +them in a \p{JFrame} with a scrollable \p{JTextArea}. + +\p{JSpinFileFilter} is used with a \p{JFileChooser} +when opening and saving files: \prm{} source files, +LTL property files and \spn{} display output files. + +\p{Options} is the dialog frame with check boxes for +changing the \spn{} display options. + +\p{Exclude} is the dialog frame for editing the list +of variable strings to be excluded from the display. + +\p{Config} contains declarations of compile time configuration items. +Method \p{init} calls \p{set\-Default\-Properties} to initialize the instance +of \p{Properties} with the default values of the dynamic configuration +items; it then attempts to load the configuration file, and if unsuccessful, +the default properties are written to a new file. + +\p{Editor} implements an editor using operations on a +\p{JTextArea}. It implements the interface \p{Document\-Listener} to flag +when the source has been modified. The class is also responsible +for the LTL formula \p{JTextField}. \p{jSpin} calls method \p{writeFile} +to write \p{ltl} and \p{out} files, and method \p{readFile} to read +the text files to be displayed. + +\p{LineNumbers} extends a \p{JComponent} to create line numbers +for the \p{RowHeaderView} of the editor \p{JScrollPane} +(thanks to Niko Myller for this code). + +\p{UndoRedo} was extracted from an example on the Java web site. + +The event handler in \p{jSpin} calls \p{run} in class \p{RunSpin} +to execute \spn{}, the C compiler and the analyzer \p{pan}. +\p{run} creates a thread of class \p{RunThread}, +and uses \p{ProcessBuilder} to set up the +command, directory, merge the output and error streams, +and set up streams for I/O. +The call \p{runAndWait} is used for short calls like \bu{Check} +and the creation and compilation of a model; +this call does not return until the completion of the subprocess. +The call \p{run} will return immediately after it has created the thread. +In this case, the event handler in \p{jSpin} calls \p{isSpinRunning} +to create a thread to poll for termination of \spn{}; +by creating a separate thread, the event handler is freed to accept +a selection of \bu{Stop}. + +When \p{Select a statement} is received during an interactive simulation, +method \p{select} is called. +This method displays the choices in the bottom text area and pops up a +dialog to enable the user to make a selection. +A \p{JFrame} is created in a new thread of the inner class \p{SelectDialog} to wait +for the selection. +\p{select} polls \p{selectedValue} which is set with the selected button +value or zero if the frame is closed or \bu{Esc} pressed. +In that case, \p{q} is sent to \spn{} to terminate the simulation. + +\js{} contains source code for interactively invoking \spd{}. +The class \p{SpiderOptions} pops up frame where parameters can be entered and +\spd{} invoked. Each \prm{} file can have its own set of parameters; these are stored +in property files with extension \p{.spd} and managed by \p{SpiderFile}. +If the diagram is created in \bu{PNG} format, it is displayed interactively: +\p{DisplayImage} creates a frame and +the image is loaded into an instance of \p{ImagePanel}. + +\subsection{Package \p{com.spinroot.filterSpin}} + +The output filtering is encapsulated in class \p{Filter}. +For each line received from the output stream, \p{run} +(of \p{RunThread}) calls \p{filter} +which modifies the string; the modified string is displayed in the +appropriate text area. +A \p{TreeMap} is maintained for mapping variable names into value strings. +Each new variable is checked against the list of excluded strings before +it is entered in the map. +For standalone filtering, the package +contains a \p{Config} class and a class \p{FilterSpin} with a main method. + +\subsection{Package \p{com.spinroot.spinSpider}} + +Most of the processing of the \spd{} program is done +in the class \p{SpinSpider}. +Static data like strings and the prologue for the \dtf{} file are +contained in the class \p{Config}. + +Four classes are used for +objects containing information extracted from the files: +\begin{itemize} +\item \p{State} contains the program counter values and the variables names +and values that are extracted from the output of the \p{never} claim in the +\p{.chk} file. +\item \p{Transition} contains the transitions and is obtained by following +the \p{New}, \p{Old}, \p{Up} and \p{Down} debugging trace in the \p{.chk} file. +A stack is used to simulate the depth-first search of \spn{}. +\item \p{Statement} contains the states, line numbers and source statements +from the \p{.d} file. +\item \p{Trail} contains the \p{id} of an entry in the trail file. +\end{itemize} +The processing sequence is invoked from the method \p{runSpider}. +\p{runProcess} is called several times to fork processes as described in +Section~\ref{s.how}. The \p{.d} file is analyzed in \p{createStatements}, +and the \p{.chk} file is analyzed in \p{readCheckFile} of class \p{Read}. +If requested, these data structures are written to a file in method +\p{writeDebug} of class \p{Write}. + +The class \p{SetTrail} traverses the state diagram according to the trail and +marks states and transitions that are part of the trail. + +The data structures are used to write the files in class \p{Write}. +See the description of the \fsm{} format to understand \p{writeFSMGraph}. +In \p{writeDOTGraph}, the \p{states} array is traversed sequentially +writing out numbered nodes including labels for each node. The +elements of this array store the program counters of each process in the +state; these are used to search the \p{statements} array for \emph{all} +statements that start from the program counter. The line numbers and +source code of the statements are appended to the label. The variable +values are also obtained from the \p{states} array. The transitions are +taken directly from the \p{transitions} array. Finally, \dt{} is called, if +requested. + +The class \p{DrawAutomata} uses the information in the \p{.d} file +to write a \dtf{} file and then calls \dt{}. + +\subsection{How \spd{} works}\label{s.how} + +\spd{} works with numerous files: +\begin{itemize} +\item The source file with extension \p{.pml}. +\item A \p{never} claim file with extension \p{.nvr} as described below; +this is normally generated automatically. +\item The file with extension \p{.chk} obtained by running a verification of +the program with the \p{-DCHECK} option and with the \p{never} claim that +prints out the program counters and variable values. +\item The statement file with extension \p{.d} obtained by running a verification +with the \p{-d} option. +\item A file with extension \p{.spd} that is used by \js{} to save \spd{} parameters. +\item A debug file with extension \p{.dbg}. +\end{itemize} + +\spd{} runs the following commands in subprocesses (\p{prog.pml} is the source file): + +\hspace*{1cm}\p{spin -a prog.pml}\\ +\hspace*{1cm}\p{gcc -DCHECK -DSAFETY -DPRINTF -o pan pan.c}\\ +\hspace*{1cm}\p{pan > prog.chk}\\ +\hspace*{1cm}\p{pan -d > prog.d} + +Then it runs its own algorithm to create a \dtf{} file. Finally, \dt{} is +optionally run to create a display file in some format like \p{png}. + +A \prm{} program must be modified by giving a special \p{never} claim; this is +generated automatically and included using the \p{-N} argument to \spn{}. + +The \p{never} claim contains a single \p{printf} statement in a loop, which is +executed with every step of the verifier. The statement prints the +following tokens separated by spaces: +\begin{itemize} +\item The string \p{*spd*}; +\item The number of processes, followed by the values of \p{pc\_value} +for each process; +\item The number of variables, followed by their names and values. +\end{itemize} +For the algorithm shown in the introduction the \p{never} claim is: +\begin{verbatim} +never { + do :: printf("*spd* 2 %d %d 2 wantp %d wantq %d \n", + pc_value(0), pc_value(1), wantp, wantq) + od +} +\end{verbatim} + +\newpage + +\appendix + +\section{Installation}\label{a.install} + +\subsection{\spn{} version} + +Version 6.0.0 of \spn{} changed its output format; starting with version +5.0, \js{} expects this format. You can still run \js{} with earlier +versions of \spn{} (for example, 4.30): set the configuration option +\p{VERSION} to a number less than 6 before you run \js{} and ensure that +the option \p{SPIN} names the earlier version of the \spn{} executable +(or copy the file over the later version). + +\subsection{Custom installation of \js{}} +\begin{itemize} +\item Download the \js{} distribution file called \p{com.spinroot.jspin-N.zip}, +where \p{N} is the version number. +Extract the files into a clean directory. +%\textbf{Do not} install to a directory with spaces like \verb=c:\Program Files=. + +\item Install \spn{} and \textsc{dot} (\textsc{dot} is only needed for +\textsc{SpinSpider}). + +\item Install an ANSI C compiler. + +\item Modify the configuration file \p{config.cfg} to reflect the +locations of the programs. +\end{itemize} + +\subsection{Building \js{}} + +To rebuild \js{}, execute \p{build.bat}, which will compile all the source +files and create the file \p{jSpin.jar} with the manifest file. + +\subsection{Installing a C compiler}\label{a.c} +The \p{gcc} compiler is normally used with \spn{}. On Windows, there are +two distributions: Cygwin (\url{http://cygwin.com}) is a comprehensive +Linux-like environment, and a smaller distribution called MinGW +(\url{http://mingw.org/}). To install MinGW, download the following archives and +open them in directory \verb=c:\mingw= \emph{in the following order}: +\begin{quote} +\p{binutils-V.tar.gz}\\ +\p{gcc-core-V.tar.gz}\\ +\p{mingw-runtime-V.tar.gz}\\ +\p{w32api-V.tar.gz} +\end{quote} +where V is the version and build number. +It is OK if some files are overwritten when opening the archive. + +Set the path in +\begin{quote} +\p{Start/Control Panel/System/Advanced/Environment Variables/PATH} +\end{quote} +to include \verb=c:\mingw\bin=. + +\subsection{Installing \js{} on \textsc{Mac OS X}}\label{a.mac} + +Thanks to Christiaan Ottow for providing this material. + +Currently, there is no precompiled version of \spn{}, so you will have to +compile it from the source code. Instructions for doing this are given +in Section~2c of the webpage: +\begin{quote} +\url{http://spinroot.com/spin/Man/README.html} +\end{quote} +An alternative approach is change the location of the preprocessor specified in +lines 75--88 of \p{main.c} from \p{/lib/cpp} to \p{/usr/bin/cpp}. + +\js{} is compiled with \p{-target 1.5} to conform with the \textsc{Java} +version currently available on the \textsc{Mac}. + +To install \js{}: +\begin{itemize} +\item Unzip the file \p{com.spinroot.jspin-V-V.zip}. +\item Download \textsc{Graphviz} from +\begin{quote} +\url{http://www.pixelglow.com/graphviz/download} +\end{quote} +Open the \p{dmg} file you downloaded and copy the \textsc{Graphviz} +application to the Applications folder. +\item Open the configuration file \p{config.cfg} in a text editor and change the +values of the following properties: +\begin{itemize} +\item \p{SPIN} to the directory with the compiled \spn{}; +\item \p{SOURCE\_DIRECTORY} to the subdirectory \p{com.spinroot.jspin-examples} of the directory +where you unpacked \js{}; +\item \p{C\_COMPILER} to directory containing \p{gcc}, +usually \p{/usr/bin/gcc}. You can verify this by issuing the command \p{which gcc}; +\item \p{PAN} to \p{pan}; +\item \p{DOT} to \p{/Applications/Graphviz.app/Contents/MacOS/dot}. +\end{itemize} +\end{itemize} + +\js{} can now be run by using the \p{Terminal} to execute the following command +in the \p{com.spinroot.jspin} directory: +\begin{quote} +\p{java com.spinroot.jspin.jSpin} +\end{quote} + +\subsection{Installing \js{} on \textsc{Linux}}\label{a.linux} + +Thanks to Vsevolod Krishchenko for providing this material. + +\begin{itemize} + +\item Install gcc, C preprocessor, dot, java. For Debian/Ubuntu: +\begin{verbatim} + sudo apt-get install gcc cpp graphviz sun-java6-jre +\end{verbatim} +\item Install spin as described above. +\item Make the following changes in \p{config.cfg}: +\begin{verbatim} + C_COMPILER=gcc + DOT=dot +\end{verbatim} +You many need to set \p{SINGLE\_QUOTE} to \p{true}. +\item Create a shell file with: +\begin{verbatim} + #!/bin/sh + java -jar jSpin.jar +\end{verbatim} +\end{itemize} + +\section{Configuration file}\label{a.cfg} + +These tables give the properties in the configuration file and their +default values. + +\begin{center} + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Version of \spn{}}\\ \hline +\textsc{\ttfamily VERSION} &\verb+6+\\\hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Directories for source and compilers}\\ \hline +\textsc{\ttfamily SOURCE\_DIRECTORY} & \verb+"com.spinroot.jspin-examples"+ \\ +\textsc{\ttfamily C\_COMPILER} &\verb+"c:\\mingw\\bin\\gcc.exe"+ \\ +\textsc{\ttfamily SPIN} &\verb+"bin\\spin.exe"+ \\ +\textsc{\ttfamily DOT} &\verb+"bin\\dot.exe"+ \\ +\textsc{\ttfamily PAN} &\verb+"pan"+ \\ \hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Options for executing \spn{}}\\ \hline +\textsc{\ttfamily COMMON\_OPTIONS} &\verb+"-g -l -p -r -s"+\\ +\textsc{\ttfamily CHECK\_OPTIONS} &\verb+"-a -v"+\\ +\textsc{\ttfamily RANDOM\_OPTIONS} &\verb+"-X"+\\ +\textsc{\ttfamily INTERACTIVE\_OPTIONS} &\verb+"-i -X"+\\ +\textsc{\ttfamily VERIFY\_OPTIONS} &\verb+"-a"+\\ +\textsc{\ttfamily C\_COMPILER\_OPTIONS} &\verb+"-o pan pan.c"+\\ +\textsc{\ttfamily PAN\_OPTIONS} &\verb+"-X"+\\ +\textsc{\ttfamily TRAIL\_OPTIONS} &\verb+"-t -X"+\\ +\textsc{\ttfamily TRANSLATE\_OPTIONS} &\verb+"-f"+\\ +\textsc{\ttfamily MAX\_STEPS} {\ttfamily (-u)} & \verb+250+\\ +\textsc{\ttfamily MAX\_DEPTH} {\ttfamily (-m)} & \verb+2000+\\ +\textsc{\ttfamily SEED} {\ttfamily (-n)} & \verb+0+\\ +\textsc{\ttfamily FAIRNESS} & \verb+true+\\ +\textsc{\ttfamily RAW} & \verb+false+\\ +\textsc{\ttfamily SINGLE\_QUOTE} & \verb+false+\\ +\textsc{\ttfamily NEGATE\_LTL} & \verb+true+\\ +\textsc{\ttfamily VERIFY\_MODE} & \verb+"Safety"+\\\hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Filter settings}\\ \hline +\textsc{\ttfamily PROCESS\_TITLE} & \verb+Process +\\ +\textsc{\ttfamily PROCESS\_WIDTH} & \verb+7+\\ +\textsc{\ttfamily STATEMENT\_TITLE} & \verb+Statement +\\ +\textsc{\ttfamily STATEMENT\_WIDTH} & \verb+18+\\ +\textsc{\ttfamily VARIABLE\_WIDTH} &\verb+10+\\ +\textsc{\ttfamily LINES\_PER\_TITLE} &\verb+20+\\ +\textsc{\ttfamily MSC} &\verb+false+\\ +\hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Text settings}\\ \hline +\textsc{\ttfamily WRAP} &\verb+true+\\ +\textsc{\ttfamily TAB\_SIZE} &\verb+4+\\ +\textsc{\ttfamily FONT\_FAMILY} & \verb+"Lucida Sans Typewriter"+\\ +\textsc{\ttfamily FONT\_STYLE} & \verb+java.awt.Font.PLAIN+\\ +\textsc{\ttfamily FONT\_SIZE} & \verb+14+\\\hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Frame size}\\ \hline +\textsc{\ttfamily WIDTH} &\verb+1000+\\ +\textsc{\ttfamily HEIGHT} &\verb+700+\\\hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Interactive dialog settings}\\ \hline +\textsc{\ttfamily SELECT\_BUTTON} &\verb+120+\\ +\textsc{\ttfamily SELECT\_HEIGHT} &\verb+70+\\ +\textsc{\ttfamily SELECT\_MENU} &\verb+5+\\\hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Location of dividers}\\ \hline +\textsc{\ttfamily LR\_DIVIDER} &\verb+400+\\ +\textsc{\ttfamily TB\_DIVIDER} &\verb+500+\\ +\textsc{\ttfamily MIN\_DIVIDER} &\verb+50+\\\hline +\end{tabular} + +\bigskip + +\begin{tabular}{|p{.3\textwidth}|p{.4\textwidth}|} +\hline +\multicolumn{2}{|c|}{Delay while waiting for user input}\\ \hline +\textsc{\ttfamily POLLING\_DELAY} &\verb+200+\\\hline +\end{tabular} + +\end{center} + +\end{document} diff --git a/docs/spin-card.tex b/docs/spin-card.tex index b048e52..60430f7 100644 --- a/docs/spin-card.tex +++ b/docs/spin-card.tex @@ -1,286 +1,286 @@ -% -% Spin Reference Card -% -% Copyright 2007 by Mordechai (Moti) Ben-Ari. -% This work is licensed under the Creative Commons -% Attribution-Noncommercial-ShareAlike 3.0 License. -% To view a copy of this license, -% visit http://creativecommons.org/licenses/by-nc-sa/3.0/; -% or, (b) send a letter to Creative Commons, -% 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. -% -\documentclass{leaflet} -%\documentclass[notumble,nocombine]{leaflet} % One page per column -\usepackage{mathptmx} -\usepackage{url} -\newcommand{\sct}[1]{\subsubsection{#1}\mbox{}\\} -\newcommand{\spc}{\hspace*{1.5em}} -\CutLine*{1}\CutLine*{3}\CutLine*{4}\CutLine*{6} - -\title{\vspace*{-2ex}Spin Reference Card} -\author{\vspace*{-2ex}Mordechai (Moti) Ben-Ari\vspace*{-2ex}} - -\begin{document} -\maketitle -\thispagestyle{empty} -\vspace*{-2ex} -{\scriptsize Copyright 2007 by Mordechai (Moti) Ben-Ari. -This work is licensed under the Creative Commons -Attribution-Noncommercial-ShareAlike 3.0 License. -To view a copy of this license, -visit \url{http://creativecommons.org/licenses/by-nc-sa/3.0/}; -or, (b) send a letter to Creative Commons, -543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.} - -\sct{Datatypes} -\texttt{bit} (1 bit)\\ -\texttt{bool} (1 bit)\\ -\texttt{byte} (8 bits unsigned)\\ -\texttt{short} (16$^{*}$ bits signed)\\ -\texttt{int} (32$^{*}$ bits signed)\\ -\texttt{unsigned} ($\leq$ 32$^{*}$ bits unsigned)\\ -\spc{}$^{*}$ - for a 32-bit machine.\\ -\texttt{pid}\\ -\texttt{chan}\\ -\texttt{mtype} = \{ name, name, ... \} (8 bits) \\ -\texttt{typedef} typename \{ sequence of declarations \}\\ -\\ -Declaration - type var [= initial value]\\ -Default initial values are zero.\\ -Array declaration - type var[N] [= initial value]\\ -Array initial value assigned to all elements. - -\sct{Operators (descending precedence)} -\spc{}\verb+()+ \spc{}\verb+[]+ \spc{}\verb+.+ \\ -\spc{}\verb+!+ \spc{}\verb+~+ \spc{}\verb=++= \spc{}\verb+--+\\ -\spc{}\verb+*+ \spc{}\verb+/+ \spc{}\verb+%+\\ -\spc{}\verb=+= \spc{}\verb+-+ \\ -\spc{}\verb+<<+ \spc{}\verb+>>+ \\ -\spc{}\verb+<+ \spc{}\verb+<=+ \spc{}\verb+>+ \spc{}\verb+>= +\\ -\spc{}\verb+==+ \spc{}\verb+!=+\\ -\spc{}\verb+&+ \\ -\spc{}\verb+^+ \\ -\spc{}\verb=|= \\ -\spc{}\verb+&&+\\ -\spc{}\verb=||=\\ -\spc{}\verb+( ... -> ... : ... )+ conditional expression\\ -\spc{}\verb+=+ - -\sct{Predefined} -Constants - \texttt{true}, \texttt{false}\\ -Variables (read-only except \texttt{\_}):\\ -\spc{}\texttt{\_} - write-only hidden scratch variable\\ -\spc{}\texttt{\_nr\_pr} - number of processes\\ -\spc{}\texttt{\_pid} - instantiation number of executing process\\ -\spc{}\texttt{timeout} - no executable statements in the system? - -\sct{Preprocessor} -\texttt{\#define} name (arguments) string\\ -\texttt{\#undef}, \texttt{\#if}, \texttt{\#ifdef}, \texttt{\#ifndef}, \texttt{\#else}, \texttt{\#endif}\\ -\texttt{\#include} "file name"\\ -\texttt{inline} name (arguments) \{ ... \} - -\sct{Statements} -Assignment - var = expression, var\verb=++=, var\verb=--=\\ -\texttt{assert}(expression)\\ -\\ -\texttt{printf}, \texttt{printm} - print to standard output\\ -\spc{}\verb=%c= (character), \verb=%d= (decimal), \verb=%e= (\texttt{mtype}),\\ -\spc{}\verb=%o= (octal), \verb=%u= (unsigned), \verb=%x= (hex)\\ -\texttt{scanf} - read from standard input in simulation mode\\ -\\ -\texttt{skip} - no operation\\ -\texttt{break} - exit from innermost \texttt{do} loop\\ -\texttt{goto} - jump to label\\ -Label prefixes with a special meaning:\\ -\spc{}\texttt{accept} - accept cycle\\ -\spc{}\texttt{end} - valid end state\\ -\spc{}\texttt{progress} - non-progress cycle\\ -\\ -\texttt{atomic} \{ ... \} - execute without interleaving\\ -\texttt{d\_step} \{ ... \} - execute deterministically (no jumping -in or out; deterministic choice among true guards; only the first -statement can block).\\ -\\ -\{ ... \} \texttt{unless} \{ ... \} - exception handling. - -\sct{Guarded commands} -\texttt{if} :: guard \verb=->= statements :: ... \texttt{fi}\\ -\texttt{do} :: guard \verb=->= statements :: ... \texttt{od}\\ -\texttt{else} guard - executed if all others are false. - -\sct{Processes} -Declaration - \texttt{proctype} procname (parameters) \{ ... \}\\ -Activate with prefixes - \texttt{active} or \texttt{active}[N]\\ -Explicit process activation - \texttt{run} procname (arguments)\\ -Initial process - \texttt{init} \{ ... \}\\ -Declaration suffixes:\\ -\spc{}\texttt{priority} - set simulation priority\\ -\spc{}\texttt{provided} (e) - executable only if expression e is true - -\sct{Channels} -\texttt{chan} ch = [ capacity ] \texttt{of} \{ type, type, ... \}\\ -\\ -\begin{tabular}{@{\hspace*{0pt}}ll} -ch ! args & send\\ -ch !! args & sorted send\\ -\\ -ch ? args & receive and remove if \emph{first} message matches\\ -ch ?? args & receive and remove if \emph{any} message matches\\ -ch ? \verb+<+args\verb+>+ & receive if \emph{first} message matches\\ -ch ?? \verb+<+args\verb+>+ & receive if \emph{any} message matches\\ -ch ? [args] & poll \emph{first} message (side-effect free)\\ -ch ?? [args] & poll \emph{any} message (side-effect free)\\ -\\ -\end{tabular} -Matching in a receive statement: constants and \texttt{mtype} symbols must match; -variables are assigned the values in the message; -\texttt{eval}(expression) forces a match with the current -value of the expression.\\ -\\ -\texttt{len}(ch) - number of messages in a channel\\ -\texttt{empty}(ch) / \texttt{nempty}(ch) - is channel empty / not empty?\\ -\texttt{full}(ch) / \texttt{nfull}(ch) - is channel full / not full?\\ -\\ -Channel use assertions:\\ -\spc{}\texttt{xr} ch - channel ch is receive-only in this process\\ -\spc{}\texttt{xs} ch - channel ch is send-only in this process - -\newpage - -\sct{Temporal logic} - -\vspace*{-2ex}\spc{} -\begin{tabular}{cl} -\verb+!+ & not\\ -\verb+&&+ & and\\ -\verb+||+ & or\\ -\verb+->+ & implies\\ -\verb+<->+ & equivalent to\\ -&\\ -\verb+[]+ & always\\ -\verb+<>+ & eventually\\ -\verb+X+ & next\\ -\verb+U+ & strong until\\ -\verb+V+ & dual of U defined as \verb+pVq <-> !(!pU!q)+ -\end{tabular} - -\sct{Remote references} -Test the control state or the value of a variable:\\ -\spc{}process-name \verb+@+ label-name\\ -\spc{}proctype-name [ expression ] \verb+@+ label-name\\ -\spc{}process-name : label-name\\ -\spc{}proctype-name [ expression ] : label-name - -\sct{Never claim} -\texttt{never} \{ ... \}.\\ -Predefined constructs that can only appear in a never claim:\\ -\spc{}\texttt{\_last} - last process to execute\\ -\spc{}\texttt{enabled}(p) - is process enabled?\\ -\spc{}\texttt{np\_} - true if no process is at a progress label\\ -\spc{}\texttt{pc\_value}(p) - current control state of process\\ -\spc{}remote references\\ -See also \texttt{trace} and \texttt{notrace}. - -\sct{Variable declaration prefixes} -\texttt{hidden} - hide this variable from the system state\\ -\texttt{local} - a global variable is accessed only by one process\\ -\texttt{show} - track variable in Xspin message sequence charts - -\sct{Verification} -Safety:\\ -\spc{}\verb+spin -a file+\\ -\spc{}\verb+gcc -DSAFETY -o pan pan.c+\\ -\spc{}\verb+pan+ or \verb+./pan+\\ -\spc{}\verb+spin -t -p -l -g -r -s file+ - -\newpage - -Liveness:\\ -\spc{}\verb+spin -a file+\\ -\spc{}\verb+gcc -o pan pan.c+\\ -\spc{}\verb+pan -a -f+ or \verb+./pan -a -f+\\ -\spc{}\verb+spin -t -p -l -g -r -s file+ - -\sct{Spin arguments} -\begin{tabular}{ll} -\texttt{-a} & generate verifier and syntax check\\ -\texttt{-i} & interactive simulation\\ -\texttt{-I} & display Promela program after preprocessing\\ -\texttt{-nN} & seed for random simulation\\ -\texttt{-t} & guided simulation with trail\\ -\texttt{-tN} & guided simulation with Nth trail\\ -\texttt{-uN} & maximum number of steps is N\\ -&\\ -\texttt{-f} & translate an LTL formula into a never claim\\ -\texttt{-F} & translate an LTL formula in a file into a never claim\\ -\texttt{-N} & include never claim from a file\\ -&\\ -\texttt{-l} & display local variables\\ -\texttt{-g} & display global variables\\ -\texttt{-p} & display statements\\ -\texttt{-r} & display receive events\\ -\texttt{-s} & display send events -\end{tabular} - -\sct{Compile arguments} -\begin{tabular}{ll} -\texttt{-DBFS} & breadth-first search\\ -\texttt{-DNP} & enable detection of non-progress cycles\\ -\texttt{-DSAFETY} & optimize for safety\\ -\\ -\texttt{-DBITSTATE} & bitstate hashing\\ -\texttt{-DCOLLAPSE} & collapse compression\\ -\texttt{-DHC} & hash-compact compression\\ -\texttt{-DMA=n} & minimized DFA with maximum n bytes\\ -\texttt{-DMEMLIM=N} & use up to N megabytes of memory -\end{tabular} - -\sct{Pan arguments} -\begin{tabular}{ll} -\texttt{-a} & find acceptance cycles\\ -\texttt{-f} & weak fairness\\ -\texttt{-l} & find non-progress cycles -\end{tabular} - -\newpage - -\begin{tabular}{ll} -\texttt{-cN} & stop after Nth error\\ -\texttt{-c0} & report all errors\\ -\texttt{-e} & create trails for all errors\\ -\texttt{-i} & search for shortest path to error\\ -\texttt{-I} & approximate search for shortest path to error\\ -\texttt{-mN} & maximum search depth is N\\ -\texttt{-wN} & $2^{N}$ hash table entries\\ -\\ -\texttt{-A} & suppress reporting of assertion violations\\ -\texttt{-E} & suppress reporting of invalid end states -\end{tabular} - -\sct{Caveats} -\vspace*{-2ex} -\begin{itemize} -\item Expessions must be side-effect free. -\item Local variable declarations always take effect at the beginning of a process. -\item A \texttt{true} guard can always be selected; an \texttt{else} guard is selected only if all others are false. -\item Macros and \texttt{inline} do \emph{not} create a new scope. -\item Place labels before an \texttt{if} or \texttt{do}, \emph{not} before a guard. -\item In an \texttt{if} or \texttt{do} statement, interleaving can occur between a guard and the following statement. -\item Processes are activated and die in LIFO order. -\item Atomic propositions in LTL formulas must be identifiers starting with lowerase letters and must be boolean variables or symbols for boolean-valued expressions. -\item Arrays of \texttt{bit} or \texttt{bool} are stored in bytes. -\item The type of a message field of a channel cannot be an array; -it can be a \texttt{typedef} that contains an array. -\item The functions \texttt{empty} and \texttt{full} cannot be negated. -\end{itemize} - -\sct{References} -\vspace*{-2ex} -\begin{itemize} -\item G. J. Holzmann. \textit{The Spin Model Checker: Primer and Reference Manual}, -Addison-Wesley, 2004.\\\url{http://spinroot.com}. -\item M. Ben-Ari. \textit{Principles of the Spin Model Checker}, -Springer, 2008.\\\url{http://www.springer.com/978-1-84628-769-5}. -\end{itemize} -\end{document} +% +% Spin Reference Card +% +% Copyright 2007 by Mordechai (Moti) Ben-Ari. +% This work is licensed under the Creative Commons +% Attribution-Noncommercial-ShareAlike 3.0 License. +% To view a copy of this license, +% visit http://creativecommons.org/licenses/by-nc-sa/3.0/; +% or, (b) send a letter to Creative Commons, +% 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. +% +\documentclass{leaflet} +%\documentclass[notumble,nocombine]{leaflet} % One page per column +\usepackage{mathptmx} +\usepackage{url} +\newcommand{\sct}[1]{\subsubsection{#1}\mbox{}\\} +\newcommand{\spc}{\hspace*{1.5em}} +\CutLine*{1}\CutLine*{3}\CutLine*{4}\CutLine*{6} + +\title{\vspace*{-2ex}Spin Reference Card} +\author{\vspace*{-2ex}Mordechai (Moti) Ben-Ari\vspace*{-2ex}} + +\begin{document} +\maketitle +\thispagestyle{empty} +\vspace*{-2ex} +{\scriptsize Copyright 2007 by Mordechai (Moti) Ben-Ari. +This work is licensed under the Creative Commons +Attribution-Noncommercial-ShareAlike 3.0 License. +To view a copy of this license, +visit \url{http://creativecommons.org/licenses/by-nc-sa/3.0/}; +or, (b) send a letter to Creative Commons, +543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.} + +\sct{Datatypes} +\texttt{bit} (1 bit)\\ +\texttt{bool} (1 bit)\\ +\texttt{byte} (8 bits unsigned)\\ +\texttt{short} (16$^{*}$ bits signed)\\ +\texttt{int} (32$^{*}$ bits signed)\\ +\texttt{unsigned} ($\leq$ 32$^{*}$ bits unsigned)\\ +\spc{}$^{*}$ - for a 32-bit machine.\\ +\texttt{pid}\\ +\texttt{chan}\\ +\texttt{mtype} = \{ name, name, ... \} (8 bits) \\ +\texttt{typedef} typename \{ sequence of declarations \}\\ +\\ +Declaration - type var [= initial value]\\ +Default initial values are zero.\\ +Array declaration - type var[N] [= initial value]\\ +Array initial value assigned to all elements. + +\sct{Operators (descending precedence)} +\spc{}\verb+()+ \spc{}\verb+[]+ \spc{}\verb+.+ \\ +\spc{}\verb+!+ \spc{}\verb+~+ \spc{}\verb=++= \spc{}\verb+--+\\ +\spc{}\verb+*+ \spc{}\verb+/+ \spc{}\verb+%+\\ +\spc{}\verb=+= \spc{}\verb+-+ \\ +\spc{}\verb+<<+ \spc{}\verb+>>+ \\ +\spc{}\verb+<+ \spc{}\verb+<=+ \spc{}\verb+>+ \spc{}\verb+>= +\\ +\spc{}\verb+==+ \spc{}\verb+!=+\\ +\spc{}\verb+&+ \\ +\spc{}\verb+^+ \\ +\spc{}\verb=|= \\ +\spc{}\verb+&&+\\ +\spc{}\verb=||=\\ +\spc{}\verb+( ... -> ... : ... )+ conditional expression\\ +\spc{}\verb+=+ + +\sct{Predefined} +Constants - \texttt{true}, \texttt{false}\\ +Variables (read-only except \texttt{\_}):\\ +\spc{}\texttt{\_} - write-only hidden scratch variable\\ +\spc{}\texttt{\_nr\_pr} - number of processes\\ +\spc{}\texttt{\_pid} - instantiation number of executing process\\ +\spc{}\texttt{timeout} - no executable statements in the system? + +\sct{Preprocessor} +\texttt{\#define} name (arguments) string\\ +\texttt{\#undef}, \texttt{\#if}, \texttt{\#ifdef}, \texttt{\#ifndef}, \texttt{\#else}, \texttt{\#endif}\\ +\texttt{\#include} "file name"\\ +\texttt{inline} name (arguments) \{ ... \} + +\sct{Statements} +Assignment - var = expression, var\verb=++=, var\verb=--=\\ +\texttt{assert}(expression)\\ +\\ +\texttt{printf}, \texttt{printm} - print to standard output\\ +\spc{}\verb=%c= (character), \verb=%d= (decimal), \verb=%e= (\texttt{mtype}),\\ +\spc{}\verb=%o= (octal), \verb=%u= (unsigned), \verb=%x= (hex)\\ +\texttt{scanf} - read from standard input in simulation mode\\ +\\ +\texttt{skip} - no operation\\ +\texttt{break} - exit from innermost \texttt{do} loop\\ +\texttt{goto} - jump to label\\ +Label prefixes with a special meaning:\\ +\spc{}\texttt{accept} - accept cycle\\ +\spc{}\texttt{end} - valid end state\\ +\spc{}\texttt{progress} - non-progress cycle\\ +\\ +\texttt{atomic} \{ ... \} - execute without interleaving\\ +\texttt{d\_step} \{ ... \} - execute deterministically (no jumping +in or out; deterministic choice among true guards; only the first +statement can block).\\ +\\ +\{ ... \} \texttt{unless} \{ ... \} - exception handling. + +\sct{Guarded commands} +\texttt{if} :: guard \verb=->= statements :: ... \texttt{fi}\\ +\texttt{do} :: guard \verb=->= statements :: ... \texttt{od}\\ +\texttt{else} guard - executed if all others are false. + +\sct{Processes} +Declaration - \texttt{proctype} procname (parameters) \{ ... \}\\ +Activate with prefixes - \texttt{active} or \texttt{active}[N]\\ +Explicit process activation - \texttt{run} procname (arguments)\\ +Initial process - \texttt{init} \{ ... \}\\ +Declaration suffixes:\\ +\spc{}\texttt{priority} - set simulation priority\\ +\spc{}\texttt{provided} (e) - executable only if expression e is true + +\sct{Channels} +\texttt{chan} ch = [ capacity ] \texttt{of} \{ type, type, ... \}\\ +\\ +\begin{tabular}{@{\hspace*{0pt}}ll} +ch ! args & send\\ +ch !! args & sorted send\\ +\\ +ch ? args & receive and remove if \emph{first} message matches\\ +ch ?? args & receive and remove if \emph{any} message matches\\ +ch ? \verb+<+args\verb+>+ & receive if \emph{first} message matches\\ +ch ?? \verb+<+args\verb+>+ & receive if \emph{any} message matches\\ +ch ? [args] & poll \emph{first} message (side-effect free)\\ +ch ?? [args] & poll \emph{any} message (side-effect free)\\ +\\ +\end{tabular} +Matching in a receive statement: constants and \texttt{mtype} symbols must match; +variables are assigned the values in the message; +\texttt{eval}(expression) forces a match with the current +value of the expression.\\ +\\ +\texttt{len}(ch) - number of messages in a channel\\ +\texttt{empty}(ch) / \texttt{nempty}(ch) - is channel empty / not empty?\\ +\texttt{full}(ch) / \texttt{nfull}(ch) - is channel full / not full?\\ +\\ +Channel use assertions:\\ +\spc{}\texttt{xr} ch - channel ch is receive-only in this process\\ +\spc{}\texttt{xs} ch - channel ch is send-only in this process + +\newpage + +\sct{Temporal logic} + +\vspace*{-2ex}\spc{} +\begin{tabular}{cl} +\verb+!+ & not\\ +\verb+&&+ & and\\ +\verb+||+ & or\\ +\verb+->+ & implies\\ +\verb+<->+ & equivalent to\\ +&\\ +\verb+[]+ & always\\ +\verb+<>+ & eventually\\ +\verb+X+ & next\\ +\verb+U+ & strong until\\ +\verb+V+ & dual of U defined as \verb+pVq <-> !(!pU!q)+ +\end{tabular} + +\sct{Remote references} +Test the control state or the value of a variable:\\ +\spc{}process-name \verb+@+ label-name\\ +\spc{}proctype-name [ expression ] \verb+@+ label-name\\ +\spc{}process-name : label-name\\ +\spc{}proctype-name [ expression ] : label-name + +\sct{Never claim} +\texttt{never} \{ ... \}.\\ +Predefined constructs that can only appear in a never claim:\\ +\spc{}\texttt{\_last} - last process to execute\\ +\spc{}\texttt{enabled}(p) - is process enabled?\\ +\spc{}\texttt{np\_} - true if no process is at a progress label\\ +\spc{}\texttt{pc\_value}(p) - current control state of process\\ +\spc{}remote references\\ +See also \texttt{trace} and \texttt{notrace}. + +\sct{Variable declaration prefixes} +\texttt{hidden} - hide this variable from the system state\\ +\texttt{local} - a global variable is accessed only by one process\\ +\texttt{show} - track variable in Xspin message sequence charts + +\sct{Verification} +Safety:\\ +\spc{}\verb+spin -a file+\\ +\spc{}\verb+gcc -DSAFETY -o pan pan.c+\\ +\spc{}\verb+pan+ or \verb+./pan+\\ +\spc{}\verb+spin -t -p -l -g -r -s file+ + +\newpage + +Liveness:\\ +\spc{}\verb+spin -a file+\\ +\spc{}\verb+gcc -o pan pan.c+\\ +\spc{}\verb+pan -a -f+ or \verb+./pan -a -f+\\ +\spc{}\verb+spin -t -p -l -g -r -s file+ + +\sct{Spin arguments} +\begin{tabular}{ll} +\texttt{-a} & generate verifier and syntax check\\ +\texttt{-i} & interactive simulation\\ +\texttt{-I} & display Promela program after preprocessing\\ +\texttt{-nN} & seed for random simulation\\ +\texttt{-t} & guided simulation with trail\\ +\texttt{-tN} & guided simulation with Nth trail\\ +\texttt{-uN} & maximum number of steps is N\\ +&\\ +\texttt{-f} & translate an LTL formula into a never claim\\ +\texttt{-F} & translate an LTL formula in a file into a never claim\\ +\texttt{-N} & include never claim from a file\\ +&\\ +\texttt{-l} & display local variables\\ +\texttt{-g} & display global variables\\ +\texttt{-p} & display statements\\ +\texttt{-r} & display receive events\\ +\texttt{-s} & display send events +\end{tabular} + +\sct{Compile arguments} +\begin{tabular}{ll} +\texttt{-DBFS} & breadth-first search\\ +\texttt{-DNP} & enable detection of non-progress cycles\\ +\texttt{-DSAFETY} & optimize for safety\\ +\\ +\texttt{-DBITSTATE} & bitstate hashing\\ +\texttt{-DCOLLAPSE} & collapse compression\\ +\texttt{-DHC} & hash-compact compression\\ +\texttt{-DMA=n} & minimized DFA with maximum n bytes\\ +\texttt{-DMEMLIM=N} & use up to N megabytes of memory +\end{tabular} + +\sct{Pan arguments} +\begin{tabular}{ll} +\texttt{-a} & find acceptance cycles\\ +\texttt{-f} & weak fairness\\ +\texttt{-l} & find non-progress cycles +\end{tabular} + +\newpage + +\begin{tabular}{ll} +\texttt{-cN} & stop after Nth error\\ +\texttt{-c0} & report all errors\\ +\texttt{-e} & create trails for all errors\\ +\texttt{-i} & search for shortest path to error\\ +\texttt{-I} & approximate search for shortest path to error\\ +\texttt{-mN} & maximum search depth is N\\ +\texttt{-wN} & $2^{N}$ hash table entries\\ +\\ +\texttt{-A} & suppress reporting of assertion violations\\ +\texttt{-E} & suppress reporting of invalid end states +\end{tabular} + +\sct{Caveats} +\vspace*{-2ex} +\begin{itemize} +\item Expessions must be side-effect free. +\item Local variable declarations always take effect at the beginning of a process. +\item A \texttt{true} guard can always be selected; an \texttt{else} guard is selected only if all others are false. +\item Macros and \texttt{inline} do \emph{not} create a new scope. +\item Place labels before an \texttt{if} or \texttt{do}, \emph{not} before a guard. +\item In an \texttt{if} or \texttt{do} statement, interleaving can occur between a guard and the following statement. +\item Processes are activated and die in LIFO order. +\item Atomic propositions in LTL formulas must be identifiers starting with lowerase letters and must be boolean variables or symbols for boolean-valued expressions. +\item Arrays of \texttt{bit} or \texttt{bool} are stored in bytes. +\item The type of a message field of a channel cannot be an array; +it can be a \texttt{typedef} that contains an array. +\item The functions \texttt{empty} and \texttt{full} cannot be negated. +\end{itemize} + +\sct{References} +\vspace*{-2ex} +\begin{itemize} +\item G. J. Holzmann. \textit{The Spin Model Checker: Primer and Reference Manual}, +Addison-Wesley, 2004.\\\url{http://spinroot.com}. +\item M. Ben-Ari. \textit{Principles of the Spin Model Checker}, +Springer, 2008.\\\url{http://www.springer.com/978-1-84628-769-5}. +\end{itemize} +\end{document} diff --git a/filterSpin/Config.java b/filterSpin/Config.java deleted file mode 100644 index fff591d..0000000 --- a/filterSpin/Config.java +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2008 by Mordechai (Moti) Ben-Ari. -/** - Local configuration class for standalone FilterSpin -*/ -package filterSpin; -public class Config { - static final String VERSION = "0.1"; - static final String CONFIG_FILE = "config.cfg"; - static final String SEPARATOR = "#"; - - static void setDefaultProperties( - java.util.Properties properties) { - properties.put("PROCESS_WIDTH", Integer.toString(7)); - properties.put("STATEMENT_WIDTH", Integer.toString(18)); - properties.put("VARIABLE_WIDTH", Integer.toString(10)); - properties.put("LINES_PER_TITLE", Integer.toString(20)); - properties.put("PROCESS_TITLE", "Process "); - properties.put("STATEMENT_TITLE", "Statement "); - properties.put("MSC", Boolean.toString(false)); - } - - /** - Set the default properties and then try to read configuration file - */ - static void init(java.util.Properties properties) { - setDefaultProperties(properties); - try { - properties.load(new java.io.FileInputStream(CONFIG_FILE)); - } catch (java.io.IOException e1) { - System.err.println("Cannot open configuration file; using defaults"); - } - } - - static final String USAGE = - "FilterSpin Version " + VERSION + - " Copyright 2008 (GNU GPL) by Moti Ben-Ari.\n" + - "Usage java filterSpin.FilterSpin [arguments] file\n" + - " file File with Spin output\n" + - " -v string Variables to exclude\n" + - " -s string Statements to exclude\n" + - " string may be file name or list of identifiers with '/'"; -} diff --git a/filterSpin/Filter.java b/filterSpin/Filter.java deleted file mode 100644 index 1cb2a80..0000000 --- a/filterSpin/Filter.java +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2004-10 by Mordechai (Moti) Ben-Ari. See copyright.txt. -/** - Filter Spin output. - Display a table: process, statement, variables. -*/ -package filterSpin; -import java.util.*; -public class Filter { - // Properties and copies of the data from the properties - private Properties properties; - private static String processTitle; - private static String statementTitle; - private static int processWidth; - private static int variableWidth; - private static int statementWidth; - private static int linesPerTitle; - private static boolean msc; - private static boolean newversion; // Spin version >= 6 - - private String title; // Title string - private int lines; // Line counter to redisplay title - - // Map from variable names to values - private TreeMap variables = new TreeMap(); - - // Excluded variable and statements - private ArrayList excludedVar = new ArrayList(); - private ArrayList excludedState = new ArrayList(); - - /** - Initialize variables and local copies of properties - */ - public void init (Properties properties) { - variables.clear(); - title = ""; - lines = -1; - this.properties = properties; - processTitle = properties.getProperty("PROCESS_TITLE"); - statementTitle = properties.getProperty("STATEMENT_TITLE"); - processWidth = Integer.valueOf(properties.getProperty("PROCESS_WIDTH")); - variableWidth = Integer.valueOf(properties.getProperty("VARIABLE_WIDTH")); - statementWidth = Integer.valueOf(properties.getProperty("STATEMENT_WIDTH")); - linesPerTitle = Integer.valueOf(properties.getProperty("LINES_PER_TITLE")); - msc = Boolean.valueOf(properties.getProperty("MSC")); - newversion = Integer.valueOf(properties.getProperty("VERSION")) >= 6; - } - - // Parse string to initialize excluded arrays - public void setExcluded(String s, boolean exVar) { - ArrayList excluded = exVar ? excludedVar : excludedState; - // Replace whitespace by separator - s = s.replaceAll("\\s+", Config.SEPARATOR) + Config.SEPARATOR; - excluded.clear(); - do { - int nl = s.indexOf(Config.SEPARATOR); - if (nl == -1) break; - if (!s.substring(0,nl).equals("")) - excluded.add(s.substring(0, nl)); - s = s.substring(nl+1); - } while (true); - } - - /** - Check if name is excluded variable (exVar=true) or statement (exVar=false) - For each excluded string S; - If variable name includes S, do not display, - but if some +T in file is in name, display anyway. - */ - private boolean checkExcluded(String name, boolean exVar) { - ArrayList excluded = exVar ? excludedVar : excludedState; - for (int i = 0; i < excluded.size(); i++) - if ((excluded.get(i).charAt(0) != '+') && - (name.indexOf(excluded.get(i)) != -1)) { - boolean included = false; - for (int j = 0; j < excluded.size(); j++) - included = included || - ((excluded.get(j).charAt(0) == '+') && - (name.indexOf(excluded.get(j).substring(1)) != -1)); - return !included; - } - return false; - } - - // Filter string s and return new string or "" to ignore - public String filter(String s) { - try { - // Variables and queues start with double tab - if (s.startsWith("\t\t")) - return filterVariable(s); - - // Filter statements - else if ((s.indexOf("proc") != -1) && (s.indexOf("[") != -1)) - return filterStatement(s); - - // Display some messages unmodified - else if ((s.startsWith("pan:")) || - (s.startsWith("spin:")) || - (s.startsWith("tl_spin:")) || - (s.startsWith("Error:")) || - (s.startsWith("error:")) ) - return s + "\n"; - else if (s.indexOf("<<<<<") != -1) - return s + "\n"; - - // Display choices that have no proc and line number - else if (s.indexOf("choice") != -1) - return s.substring(s.indexOf("choice")) + "\n"; - - // Display error count with bullets to emphasize - else if (s.indexOf("errors:") != -1) - return - s.substring(0, s.indexOf("errors:")) + "\u2022\u2022\u2022 " + - s.substring(s.indexOf("errors:")) + " \u2022\u2022\u2022\n"; - - // Display MSC lines (without MSC:) if msc is true - else if (msc && s.trim().startsWith("MSC:")) - return s.substring(s.indexOf("MSC:")+5) + "\n"; - - // Display printf lines if msc is false - else if (!msc && !s.equals("")) - return s + "\n"; - else - return ""; - } catch (Exception e) { - System.err.println("\n + Error in filter for:\n" + s + "\n"); - e.printStackTrace(); - return ""; - } - } - - // Filter variables (including queues) - private String filterVariable(String s) { - String varName, varValue; - if (s.startsWith("\t\tqueue")) { - varName = s.substring(s.indexOf('(')+1, s.indexOf(')')); - varValue = s.substring(s.indexOf(':')+1).trim(); - } - else { - varName = s.substring(2, s.indexOf('=')-1); - varValue = s.substring(s.indexOf('=')+1).trim(); - } - if (checkExcluded(varName, true)) return ""; - // Construct new title if new variables encountered - boolean newTitle = !variables.containsKey(varName); - variables.put(varName, varValue); - if (newTitle) { - title = formatItem(processTitle, processWidth) + " " + - formatItem(statementTitle, statementWidth) + " " + - collectionToString(variables.keySet()) + "\n"; - lines = -1; - } - return ""; - } - - // Filter statements - private String filterStatement(String s) { - String u = ""; - int procIndex = s.indexOf("proc")+4; // After "proc" - // Get process name - String proc = - s.substring(procIndex, s.indexOf(")")+1).trim(); - proc = proc.substring(0, proc.indexOf("(")) + - strip(proc.substring(proc.indexOf("("))); - - // Get line number and statement name - String statement = "", line = ""; - if (s.indexOf('[') != -1) { - if (newversion) { - // Spin 6 has "filename:#" - // Skip over initial ":" and start at file name - int colonIndex = s.indexOf(":", procIndex); - line = formatItem( - s.substring(colonIndex+1, s.indexOf(" ", colonIndex)).trim(), 3); - } - else - // Earlier versions had "line #" - line = formatItem( - s.substring(s.indexOf("line")+4, s.indexOf("\"")).trim(), 3); - statement = - strip(s.substring(s.indexOf('[')+1, s.lastIndexOf(']'))); - statement = line + " " + statement; - } - - if (checkExcluded(statement, false)) return ""; - - // For choice, display just process and statement - if (s.indexOf("choice") != -1) - u = s.substring(s.indexOf("choice"), s.indexOf(':')+2) + - proc + " " + statement + "\n"; - // Display table line (unless goto/else/break) - else if ((statement.indexOf("goto") == -1) && - !statement.equals("else") && - !statement.equals("break")) { - u = formatItem(proc, processWidth) + " " + - formatItem(statement, statementWidth) + " " + - collectionToString(variables.values()) + "\n"; - - // Display title if needed - lines = (lines + 1) % linesPerTitle; - if (lines == 0) u = title + u; - } - return u; - } - - // Strip balanced parentheses - private String strip(String s) { - while ( (s.charAt(0)=='(') && (s.charAt(s.length()-1)==')')) - s = s.substring(1, s.length()-1); - return s; - } - - /** - Format a variable name or value s into a field of length len - If item is too long, shorten it - But, for array variables, shorten the name, not the index - If item is too short, pad it - */ - private String formatItem(String s, int len) { - if (s.length() > len) { - if (s.indexOf("[") != -1) { - String subscript = - s.substring(s.indexOf("["), s.lastIndexOf("]")+1); - if (subscript.length() < len) - return s.substring(0, len-subscript.length()) + subscript; - else - return s.substring(0, len); - } - else - return s.substring(0,len); - } - else if (s.length() < len) - return (s + " ").substring(0,len); - else - return s; - } - - /** Transform a collection of variables to a string, - calling formatItem for each element - */ - private String collectionToString(Collection c) { - String s = ""; - Iterator it = c.iterator(); - while (it.hasNext()) - s = s + formatItem(it.next(), variableWidth) + " "; - return s; - } -} diff --git a/filterSpin/FilterSpin.java b/filterSpin/FilterSpin.java deleted file mode 100644 index ecbc71b..0000000 --- a/filterSpin/FilterSpin.java +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2008 by Mordechai (Moti) Ben-Ari. See copyright.txt. -/** - Class with main method for standalone FilterSpin -*/ -package filterSpin; -import java.io.*; -class FilterSpin { - /** - Read the files of excluded variables/statements and - return as a single string - */ - private static String readFile(File fc) { - BufferedReader textReader = null; - String s = ""; - try { - textReader = new BufferedReader(new FileReader(fc)); - String line; - while (true) { - line = textReader.readLine(); - if (line == null) break; - else s = s + line + '\n'; - } - textReader.close(); - return s; - } - catch (IOException e) { - error("File error " + fc); - return ""; - } - } - - /** - Read the Spin raw output and call the filter for each line - */ - private static void filterFile(File fc, Filter filter) { - BufferedReader textReader = null; - try { - textReader = new BufferedReader(new FileReader(fc)); - String line; - while (true) { - line = textReader.readLine(); - if (line == null) break; - line = filter.filter(line); - if (!line.equals("")) System.out.print(line); - } - textReader.close(); - } - catch (IOException e) { - error("File error " + fc); - System.exit(1); - } - } - - static void error(String s) { - System.err.println(s); - System.exit(1); - } - - public static void main(String[] args) { - if (args.length == 0) error(Config.USAGE); - - // Last argument is file name - File file = new File(args[args.length-1]); - - // Search for excluded file names or strings - String exc = Config.SEPARATOR, exs = Config.SEPARATOR; - for (int i = 0; i < args.length-1; i++) - if (args[i].equals("-v")) exc = args[i+1]; - else if (args[i].equals("-s")) exs = args[i+1]; - - // Create filter and property objects and initialize - Filter filter = new Filter(); - java.util.Properties properties = new java.util.Properties(); - Config.init(properties); - filter.init(properties); - - // Read excluded files (if any) and set excluded data structures - if (exc.indexOf(Config.SEPARATOR) == -1) - exc = readFile(new File(exc)); - filter.setExcluded(exc, true); - if (exs.indexOf(Config.SEPARATOR) == -1) - exs = readFile(new File(exs)); - filter.setExcluded(exs, false); - - // Filter the raw Spin data - filterFile(file, filter); - } -} diff --git a/jspin-examples/barz.pml b/jspin-examples/barz.pml index 67dfa81..19554ef 100644 --- a/jspin-examples/barz.pml +++ b/jspin-examples/barz.pml @@ -1,50 +1,50 @@ -/* Copyright (C) 2006-10 M. Ben-Ari. See copyright.txt */ -/* - Barz's implementation of general semaphores - by binary semaphores -*/ - -#define NPROCS 3 -#define K 2 -#define PID -#include "critical.h" - -byte gate = ((K == 0) -> 0 : 1); -int count = K; - -bool test[NPROCS] = false; -#define notInTest ((test[0]==false) && (test[1]==false) && (test[2]==false)) - -/* Verify Safety with the following properties */ - -ltl p0 { [](gate <= 1) } /* gate is a binary semaphore */ -ltl p1 { []((count == 0) -> (gate == 0)) } -ltl p2 { [](((gate == 0) && notInTest) -> (count == 0)) } - -active [NPROCS] proctype P () { - do :: - /* Wait */ - atomic { gate > 0; gate--; test[_pid] = true; } - assert(gate == 0); - d_step { - count--; - if - :: count > 0 -> gate++; - :: else - fi; - test[_pid] = false; - } - - critical_section(); - - /* Signal */ - d_step { - count++; - if - :: count == 1 -> gate++; - :: else - fi; - } - od -} - +/* Copyright (C) 2006-10 M. Ben-Ari. See copyright.txt */ +/* + Barz's implementation of general semaphores + by binary semaphores +*/ + +#define NPROCS 3 +#define K 2 +#define PID +#include "critical.h" + +byte gate = ((K == 0) -> 0 : 1); +int count = K; + +bool test[NPROCS] = false; +#define notInTest ((test[0]==false) && (test[1]==false) && (test[2]==false)) + +/* Verify Safety with the following properties */ + +ltl p0 { [](gate <= 1) } /* gate is a binary semaphore */ +ltl p1 { []((count == 0) -> (gate == 0)) } +ltl p2 { [](((gate == 0) && notInTest) -> (count == 0)) } + +active [NPROCS] proctype P () { + do :: + /* Wait */ + atomic { gate > 0; gate--; test[_pid] = true; } + assert(gate == 0); + d_step { + count--; + if + :: count > 0 -> gate++; + :: else + fi; + test[_pid] = false; + } + + critical_section(); + + /* Signal */ + d_step { + count++; + if + :: count == 1 -> gate++; + :: else + fi; + } + od +} + diff --git a/jspin-examples/count.pml b/jspin-examples/count.pml index fb88ba6..647cf15 100644 --- a/jspin-examples/count.pml +++ b/jspin-examples/count.pml @@ -3,24 +3,25 @@ Increment a variable in two processes. Check that final value can be two!! */ -#define TIMES 10 -byte n = 0; -byte finished = 0; - -active [2] proctype P() { - byte i = 1; - byte temp; - do :: ( i > TIMES ) -> break - :: else -> - temp = n; - n = temp + 1; - i++ - od; - finished++; /* Process terminates */ -} - -active proctype Finish() { - finished == 2; /* Wait for termination */ +#define TIMES 10 +byte n = 0; +byte finished = 0; + +active [2] proctype P() { + byte i = 1; + byte temp; + do :: ( i > TIMES ) -> break + :: else -> + temp = n; + n = temp + 1; + i++ + od; + finished++; /* Process terminates */ +} + +active proctype Finish() { + finished == 2; /* Wait for termination */ printf("n = %d\n", n); - assert (n > 2); /* Assert can't be 2 */ -} + assert (n > 2); + /* Assert can't be 2 */ +} diff --git a/jspin-examples/critical.h b/jspin-examples/critical.h index 70c00cb..5965b33 100644 --- a/jspin-examples/critical.h +++ b/jspin-examples/critical.h @@ -1,37 +1,37 @@ -/* Copyright (C) 2006 M. Ben-Ari. See copyright.txt */ -/* - Definitions for critical section - If K is defined, checks (critical <= K), otherwise (critical == 1). - If PID is defined, prints _pid in CS, otherwise prints a character parameter. - If NOSTARVE is defined, you can Verify Acceptance of <>nostarve. -*/ - -#ifdef NOSTARVE -bool P1inCS = false; -#define nostarve P1inCS -#endif - -byte critical = 0; - -#ifdef PID -inline critical_section() { - printf("MSC: %d in CS\n", _pid); -#else -inline critical_section(proc) { - printf("MSC: %c in CS\n", proc); -#endif - critical++; -#ifdef K - assert (critical <= K); -#else - assert (critical == 1); -#endif -#ifdef NOSTARVE +/* Copyright (C) 2006 M. Ben-Ari. See copyright.txt */ +/* + Definitions for critical section + If K is defined, checks (critical <= K), otherwise (critical == 1). + If PID is defined, prints _pid in CS, otherwise prints a character parameter. + If NOSTARVE is defined, you can Verify Acceptance of <>nostarve. +*/ + +#ifdef NOSTARVE +bool P1inCS = false; +#define nostarve P1inCS +#endif + +byte critical = 0; + +#ifdef PID +inline critical_section() { + printf("MSC: %d in CS\n", _pid); +#else +inline critical_section(proc) { + printf("MSC: %c in CS\n", proc); +#endif + critical++; +#ifdef K + assert (critical <= K); +#else + assert (critical == 1); +#endif +#ifdef NOSTARVE if :: _pid == 1 -> P1inCS = true; P1inCS = false :: else - fi; -#endif - critical--; -} - + fi; +#endif + critical--; +} + diff --git a/jspin-examples/dekker.pml b/jspin-examples/dekker.pml index 2f1f969..258710f 100644 --- a/jspin-examples/dekker.pml +++ b/jspin-examples/dekker.pml @@ -1,50 +1,50 @@ -/* Dekker's algorithm */ -bool wantp = false, wantq = false; -byte turn = 1; +/* Dekker's algorithm */ +bool wantp = false, wantq = false; +byte turn = 1; bool csp = false, csq = false; - + ltl { []<>csp && []<>csq } -active proctype p() { - do - :: wantp = true; - do - :: !wantq -> break; - :: else -> - if - :: (turn == 1) - :: (turn == 2) -> - wantp = false; - (turn == 1); - wantp = true - fi - od; +active proctype p() { + do + :: wantp = true; + do + :: !wantq -> break; + :: else -> + if + :: (turn == 1) + :: (turn == 2) -> + wantp = false; + (turn == 1); + wantp = true + fi + od; csp = true; assert (!(csp && csq)); csp = false; - wantp = false; - turn = 2 - od -} - -active proctype q() { - do - :: wantq = true; - do - :: !wantp -> break; - :: else -> - if - :: (turn == 2) - :: (turn == 1) -> - wantq = false; - (turn == 2); - wantq = true - fi - od; + wantp = false; + turn = 2 + od +} + +active proctype q() { + do + :: wantq = true; + do + :: !wantp -> break; + :: else -> + if + :: (turn == 2) + :: (turn == 1) -> + wantq = false; + (turn == 2); + wantq = true + fi + od; csq = true; assert (!(csp && csq)); csq = false; - wantq = false; - turn = 1 - od -} + wantq = false; + turn = 1 + od +} diff --git a/jspin-examples/second.pml b/jspin-examples/second.pml index d2c37c6..a15f51c 100644 --- a/jspin-examples/second.pml +++ b/jspin-examples/second.pml @@ -1,26 +1,28 @@ -/* Second attempt */ -bool wantp = false, wantq = false; +/* Second attempt */ +bool wantp = false, wantq = false; byte critical = 0; - -active proctype p() { + +active proctype p() { do - :: !wantq; - wantp = true; + :: + !wantq; + wantp = true; critical++; assert (critical == 1); critical--; - wantp = false; - od -} - -active proctype q() { + wantp = false; + od +} + +active proctype q() { do - :: !wantp; - wantq = true; + :: + !wantp; + wantq = true; critical++; assert (critical == 1); critical--; - wantq = false; - od -} - \ No newline at end of file + wantq = false; + od +} + diff --git a/jspin-examples/third.pml b/jspin-examples/third.pml index b27d820..b5adc66 100644 --- a/jspin-examples/third.pml +++ b/jspin-examples/third.pml @@ -1,26 +1,28 @@ -/* Third attempt */ -bool wantp = false, wantq = false; +/* Third attempt */ +bool wantp = false, wantq = false; byte critical = 0; - -active proctype p() { + +active proctype p() { do - :: wantp = true; - !wantq; + :: + wantp = true; + !wantq; critical++; assert (critical == 1); critical--; - wantp = false; - od -} - -active proctype q() { + wantp = false; + od +} + +active proctype q() { do - :: wantq = true; - !wantp; + :: + wantq = true; + !wantp; critical++; assert (critical == 1); critical--; - wantq = false; - od -} - \ No newline at end of file + wantq = false; + od +} + diff --git a/jspin.iss b/jspin.iss index 54d2351..c9c12f1 100644 --- a/jspin.iss +++ b/jspin.iss @@ -1,47 +1,47 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -[Setup] -AppName=jSpin - Spin Development Environment -AppVerName=jSpin - Version 5.0 -AppPublisher=Moti Ben-Ari, Weizmann Institute of Science -AppPublisherURL=http://stwww.weizmann.ac.il/g-cs/benari/jspin/index.html -AppSupportURL=http://stwww.weizmann.ac.il/g-cs/benari/jspin/index.html -AppUpdatesURL=http://stwww.weizmann.ac.il/g-cs/benari/jspin/index.html -DefaultGroupName=jSpin -OutputDir=c:\jspin -DefaultDirName=c:\jspin -AllowNoIcons=yes -LicenseFile=C:\jspin\txt\gpl.txt -SetupIconFile=C:\jspin\jspin.ico -Compression=lzma -SolidCompression=yes - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Files] -Source: "C:\jspin\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion -Source: "C:\jspin\jspin-examples\*.p*"; DestDir: "{app}\jspin-examples"; Flags: ignoreversion -Source: "C:\jspin\spider-examples\*.p*"; DestDir: "{app}\spider-examples"; Flags: ignoreversion -Source: "C:\jspin\txt\*"; DestDir: "{app}\txt"; Flags: ignoreversion -Source: "C:\jspin\jspin\*.java"; DestDir: "{app}\jspin"; Flags: ignoreversion -Source: "C:\jspin\jspin\*.mf"; DestDir: "{app}\jspin"; Flags: ignoreversion -Source: "C:\jspin\spinSpider\*.java"; DestDir: "{app}\spinSpider"; Flags: ignoreversion -Source: "C:\jspin\filterSpin\*.java"; DestDir: "{app}\filterSpin"; Flags: ignoreversion -Source: "C:\jspin\docs\*.png"; DestDir: "{app}\docs"; Flags: ignoreversion -Source: "C:\jspin\docs\*.tex"; DestDir: "{app}\docs"; Flags: ignoreversion -Source: "C:\jspin\docs\*.pdf"; DestDir: "{app}\docs"; Flags: ignoreversion -Source: "C:\jspin\jspin.ico"; DestDir: "{app}"; Flags: ignoreversion -Source: "C:\jspin\jspin.jar"; DestDir: "{app}"; Flags: ignoreversion -Source: "C:\jspin\build.bat"; DestDir: "{app}"; Flags: ignoreversion -Source: "C:\jspin\config.cfg"; DestDir: "{app}"; Flags: ignoreversion -Source: "C:\jspin\run.bat"; DestDir: "{app}"; Flags: ignoreversion -; NOTE: Don't use "Flags: ignoreversion" on any shared system files - -[Icons] -Name: "{group}\jSpin"; Filename: "{app}\run.bat"; IconFilename: "{app}\jspin.ico"; WorkingDir: "{app}" -Name: "{group}\jSpin User's Guide"; Filename: "{app}\docs\jspin-user.pdf" -Name: "{group}\Website"; Filename: "http://stwww.weizmann.ac.il/g-cs/benari/jspin/index.html" -Name: "{group}\Uninstall jSpin"; Filename: "{uninstallexe}" -Name: "{userdesktop}\jSpin"; Filename: "{app}\run.bat"; IconFilename: "{app}\jspin.ico"; WorkingDir: "{app}" +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=jSpin - Spin Development Environment +AppVerName=jSpin - Version 5.0 +AppPublisher=Moti Ben-Ari, Weizmann Institute of Science +AppPublisherURL=http://stwww.weizmann.ac.il/g-cs/benari/com.spinroot.jspin/index.html +AppSupportURL=http://stwww.weizmann.ac.il/g-cs/benari/com.spinroot.jspin/index.html +AppUpdatesURL=http://stwww.weizmann.ac.il/g-cs/benari/com.spinroot.jspin/index.html +DefaultGroupName=jSpin +OutputDir=c:\com.spinroot.jspin +DefaultDirName=c:\com.spinroot.jspin +AllowNoIcons=yes +LicenseFile=C:\com.spinroot.jspin\txt\gpl.txt +SetupIconFile=C:\com.spinroot.jspin\com.spinroot.jspin.ico +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Files] +Source: "C:\com.spinroot.jspin\bin\*"; DestDir: "{app}\bin"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\com.spinroot.jspin-examples\*.p*"; DestDir: "{app}\com.spinroot.jspin-examples"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\spider-examples\*.p*"; DestDir: "{app}\spider-examples"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\txt\*"; DestDir: "{app}\txt"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\com.spinroot.jspin\*.java"; DestDir: "{app}\com.spinroot.jspin"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\com.spinroot.jspin\*.mf"; DestDir: "{app}\com.spinroot.jspin"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\com.spinroot.spinSpider\*.java"; DestDir: "{app}\com.spinroot.spinSpider"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\com.spinroot.filterSpin\*.java"; DestDir: "{app}\com.spinroot.filterSpin"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\docs\*.png"; DestDir: "{app}\docs"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\docs\*.tex"; DestDir: "{app}\docs"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\docs\*.pdf"; DestDir: "{app}\docs"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\com.spinroot.jspin.ico"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\com.spinroot.jspin.jar"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\build.bat"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\config.cfg"; DestDir: "{app}"; Flags: ignoreversion +Source: "C:\com.spinroot.jspin\run.bat"; DestDir: "{app}"; Flags: ignoreversion +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{group}\jSpin"; Filename: "{app}\run.bat"; IconFilename: "{app}\com.spinroot.jspin.ico"; WorkingDir: "{app}" +Name: "{group}\jSpin User's Guide"; Filename: "{app}\docs\com.spinroot.jspin-user.pdf" +Name: "{group}\Website"; Filename: "http://stwww.weizmann.ac.il/g-cs/benari/com.spinroot.jspin/index.html" +Name: "{group}\Uninstall jSpin"; Filename: "{uninstallexe}" +Name: "{userdesktop}\jSpin"; Filename: "{app}\run.bat"; IconFilename: "{app}\com.spinroot.jspin.ico"; WorkingDir: "{app}" diff --git a/jspin/Config.java b/jspin/Config.java deleted file mode 100644 index 07bb7fb..0000000 --- a/jspin/Config.java +++ /dev/null @@ -1,404 +0,0 @@ -/* Copyright 2003-10 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -package jspin; -import java.io.*; -import java.awt.event.*; -import java.util.*; - -public class Config { - static Properties properties = new Properties(); - // Where to find configuration file - public static String installationDirectory; - public static String currentDirectory; - public static String helpFileName; - public static String aboutFileName; - public static final char sep = java.io.File.separatorChar; // shortcut - - // Strings - static final String SOFTWARE_NAME = "jSpin Version 5.0"; - static final String JAVA_VERSION = "1.5"; - static final String CONFIG_FILE_NAME = "config.cfg"; - static final String SPIDER_TITLE = "SpinSpider"; - static final String OPTIONS_TITLE = "Display"; - static final String SELECT = "Select a statement"; - static final String OPEN_FILE = "Open a Promela file\n"; - static final String processTitle = "Process "; - static final String statementTitle = "Statement "; - - static void setDefaultProperties() { - // Spin version: format changed with Spin 6 - properties.put("VERSION", "6"); - - // Directories and file names - properties.put("SOURCE_DIRECTORY", "jspin-examples"); - properties.put("C_COMPILER", "c:\\mingw\\bin\\gcc.exe"); - properties.put("SPIN", "bin" + sep + "spin.exe"); - properties.put("PAN", "pan"); - properties.put("DOT", "bin" + sep + "dot.exe"); - properties.put("HELP_FILE_NAME", "txt" + sep + "help.txt"); - properties.put("ABOUT_FILE_NAME", "txt" + sep + "copyright.txt"); - - // Options for executing Spin - properties.put("SINGLE_QUOTE", Boolean.toString(false)); - properties.put("COMMON_OPTIONS", "-g -l -p -r -s"); - // Check options changed for version 6 (for now) - // properties.put("CHECK_OPTIONS", "-a -v"); - properties.put("CHECK_OPTIONS", "-a"); - properties.put("RANDOM_OPTIONS", "-X"); - properties.put("INTERACTIVE_OPTIONS", "-i -X"); - properties.put("VERIFY_OPTIONS", "-a"); - properties.put("C_COMPILER_OPTIONS", "-o pan pan.c"); - properties.put("PAN_OPTIONS", "-X"); - properties.put("TRAIL_OPTIONS", "-t -X"); - properties.put("TRANSLATE_OPTIONS", "-f"); - - // Settings - properties.put("MAX_STEPS", "250"); - properties.put("MAX_DEPTH", "2000"); - properties.put("SEED", "0"); - properties.put("NEGATE_LTL", Boolean.toString(true)); - properties.put("FAIRNESS", Boolean.toString(true)); - properties.put("VERIFY_MODE", Safety); - properties.put("RAW", Boolean.toString(false)); - properties.put("PROCESS_WIDTH", Integer.toString(7)); - properties.put("STATEMENT_WIDTH",Integer.toString(18)); - properties.put("VARIABLE_WIDTH", Integer.toString(10)); - properties.put("LINES_PER_TITLE",Integer.toString(20)); - - // Size of main frame - properties.put("WIDTH", Integer.toString(1000)); - properties.put("HEIGHT", Integer.toString(700)); - - // Select dialog - properties.put("SELECT_BUTTON", Integer.toString(220)); - properties.put("SELECT_HEIGHT", Integer.toString(70)); - properties.put("SELECT_MENU", Integer.toString(5)); - properties.put("UNEXECUTABLE", Boolean.toString(false)); - - // Location of dividers in JSplitPanes: Left-right and top-bottom - properties.put("LR_DIVIDER", Integer.toString(400)); - properties.put("TB_DIVIDER", Integer.toString(500)); - properties.put("MIN_DIVIDER", Integer.toString(50)); - - // Font - properties.put("FONT_FAMILY", "Lucida Sans Typewriter"); - properties.put("FONT_STYLE", Integer.toString(java.awt.Font.PLAIN)); - properties.put("FONT_SIZE", Integer.toString(14)); - - // Tab size in editor - properties.put("TAB_SIZE", Integer.toString(4)); - - // Display of Spin output - properties.put("WRAP", Boolean.toString(true)); - properties.put("MSC", Boolean.toString(false)); - properties.put("PROCESS_TITLE", "Process "); - properties.put("STATEMENT_TITLE", "Statement "); - - // Delay while waiting for user input - properties.put("POLLING_DELAY", Integer.toString(200)); - } - - // Component names and mnemonics - static final String File = "File"; - static final int FileMN = KeyEvent.VK_F; - static final String New = "New"; - static final int NewMN = KeyEvent.VK_N; - static final String Open = "Open"; - static final int OpenMN = KeyEvent.VK_O; - static final String Save = "Save"; - static final int SaveMN = KeyEvent.VK_S; - static final String SaveAs = "Save as"; - static final int SaveAsMN = KeyEvent.VK_A; - static final String Switch = "Switch file"; - static final int SwitchMN = KeyEvent.VK_F; - static final String Exit = "Exit"; - static final int ExitMN = KeyEvent.VK_X; - - static final String Editor = "Edit"; - static final int EditorMN = KeyEvent.VK_E; - static final String Undo = "Undo"; - static final int UndoMN = KeyEvent.VK_U; - static final String Redo = "Redo"; - static final int RedoMN = KeyEvent.VK_R; - static final String Copy = "Copy"; - static final int CopyMN = KeyEvent.VK_C; - static final String Cut = "Cut"; - static final int CutMN = KeyEvent.VK_T; - static final String Paste = "Paste"; - static final int PasteMN = KeyEvent.VK_P; - static final String Find = "Find"; - static final int FindMN = KeyEvent.VK_F; - static final String FindAgain = "Find again"; - static final int FindAgainMN = KeyEvent.VK_A; - - static final String Spin = "Spin"; - static final int SpinMN = KeyEvent.VK_S; - static final String Check = "Check"; - static final int CheckMN = KeyEvent.VK_K; - static final String Random = "Random"; - static final int RandomMN = KeyEvent.VK_R; - static final String Inter = "Interactive"; - static final int InterMN = KeyEvent.VK_I; - static final String Verify = "Verify"; - static final int VerifyMN = KeyEvent.VK_V; - static final String Trail = "Guided"; - static final int TrailMN = KeyEvent.VK_G; - static final String Stop = "Stop"; - static final int StopMN = KeyEvent.VK_P; - - static final String Options = "Options"; - static final int OptionsMN = KeyEvent.VK_N; - static final String Common = "Common"; - static final int CommonMN = KeyEvent.VK_C; - static final String OptionsC = "C compiler"; - static final int OptionsCMN = KeyEvent.VK_C; - static final String OptionsPan = "Pan"; - static final int OptionsPanMN = KeyEvent.VK_A; - static final String Default = "Default"; - static final int DefaultMN = KeyEvent.VK_D; - static final String SaveInstall = "Save install"; - static final int SaveInstallMN = KeyEvent.VK_L; - static final String SaveCurrent = "Save current"; - static final int SaveCurrentMN = KeyEvent.VK_S; - - static final String Settings = "Settings"; - static final int SettingsMN = KeyEvent.VK_G; - static final String MaxSteps = "Max steps"; - static final int MaxStepsMN = KeyEvent.VK_M; - static final String MaxDepth = "Max depth"; - static final int MaxDepthMN = KeyEvent.VK_D; - static final String Seed = "Seed"; - static final int SeedMN = KeyEvent.VK_S; - static final String Negate = "Negate LTL"; - static final int NegateMN = KeyEvent.VK_L; - static final String StWidth = "Statement width"; - static final int StWidthMN = KeyEvent.VK_S; - static final String VarWidth = "Variable width"; - static final int VarWidthMN = KeyEvent.VK_V; - static final String ExcludedV = "Exclude variables"; - static final int ExcludedVMN = KeyEvent.VK_E; - static final String ExcludedS = "Exclude statements"; - static final int ExcludedSMN = KeyEvent.VK_X; - static final String Fair = "Weak fairness"; - static final int FairMN = KeyEvent.VK_W; - static final String Safety = "Safety"; - static final int SafetyMN = KeyEvent.VK_Y; - static final String Acceptance = "Acceptance"; - static final int AcceptanceMN = KeyEvent.VK_C; - static final String NonProgress = "Non-progress"; - static final int NonProgressMN = KeyEvent.VK_N; - - static final String Output = "Output"; - static final int OutputMN = KeyEvent.VK_U; - static final String SaveSpin = "Save output"; - static final int SaveSpinMN = KeyEvent.VK_V; - static final String Raw = "Raw output"; - static final int RawMN = KeyEvent.VK_R; - static final String DisplayRaw = "Display raw"; - static final int DisplayRawMN = KeyEvent.VK_D; - - static final String Spider = "SpinSpider"; - static final int SpiderMN = KeyEvent.VK_D; - static final String SpiderDisplay = "Display debug"; - static final int SpiderDisplayMN = KeyEvent.VK_L; - static final String Run = "Run"; - static final int RunMN = KeyEvent.VK_R; - - static final String Help = "Help"; - static final int HelpMN = KeyEvent.VK_H; - static final String About = "About"; - static final int AboutMN = KeyEvent.VK_A; - - static final String Max = "Maximize"; - static final int MaxMN = KeyEvent.VK_M; - - static final String LTLConvert = "Convert"; - static final int LTLConvertMN = KeyEvent.VK_C; - static final String LTLFormula = " LTL formula "; - static final String LTLTranslate = "Translate"; - static final int LTLTranslateMN = KeyEvent.VK_L; - static final String LTLClear = "Clear"; - static final int LTLClearMN = KeyEvent.VK_A; - static final String LTLLoad = "Load"; - static final int LTLLoadMN = KeyEvent.VK_O; - static final String LTLName = "LTL name"; - static final int LTLNameMN = KeyEvent.VK_A; // For toolbar - static final int LTLName1MN = KeyEvent.VK_N; // For menu - static final int LTL_COLUMNS = 50; - - // Common options - static final String OK = "OK"; - static final int OKMN = KeyEvent.VK_O; - static final String Cancel = "Cancel"; - static final String Statements = "Statements"; - static final int StatementsMN = KeyEvent.VK_S; - static final String Globals = "Globals"; - static final int GlobalsMN = KeyEvent.VK_G; - static final String Locals = "Locals"; - static final int LocalsMN = KeyEvent.VK_L; - static final String Sent = "Sent"; - static final int SentMN = KeyEvent.VK_T; - static final String Received = "Received"; - static final int ReceivedMN = KeyEvent.VK_R; - static final String ClearAll = "Clear all"; - static final int ClearAllMN = KeyEvent.VK_C; - static final String SetAll = "Set all"; - static final int SetAllMN = KeyEvent.VK_A; - - // SpinSpider options - static final String NoTrail = "No trail"; - static final int NoTrailMN = KeyEvent.VK_T; - static final String EmphTrail = "Emphasize trail"; - static final int EmphTrailMN = KeyEvent.VK_E; - static final String OnlyTrail = "Only trail"; - static final int OnlyTrailMN = KeyEvent.VK_O; - static final String Automata = "Automata"; - static final int AutomataMN = KeyEvent.VK_A; - static final String Debug = "Debug"; - static final int DebugMN = KeyEvent.VK_D; - static final String DotSize = "Dot size"; - static final String DotSmall = "Small"; - static final int DotSmallMN = KeyEvent.VK_M; - static final String DotLarge = "Large"; - static final int DotLargeMN = KeyEvent.VK_L; - static final String TrailStyle = "Trail style"; - static final String TrailColor = "Color"; - static final int TrailColorMN = KeyEvent.VK_C; - static final String TrailBold = "Bold"; - static final int TrailBoldMN = KeyEvent.VK_B; - static final String Processes = "Processes"; - static final int MAX_PROCESS = 5; - static final String Variables = "Variables"; - static final String Format = "Format"; - static final String DOT = "dot"; - static final String PNG = "png"; - static final String PS = "ps"; - static final String FSM = "fsm"; - - // Accelerators - // Select All by default "control A" - static final String SwitchAC = "control B"; - static final String CopyAC = "control C"; - static final String SpiderAC = "control D"; - static final String VarWidthAC = "control E"; - static final String FindAC = "control F"; - static final String FindAgainAC = "control G"; - // Backspace by default "control H" - static final String CommonAC = "control I"; - static final String ExcludedSAC = "control J"; - static final String AcceptanceAC = "control L"; - static final String MaxStepsAC = "control M"; - static final String NonProgressAC = "control N"; - static final String OpenAC = "control O"; - static final String ExitAC = "control Q"; - static final String DisplayRawAC = "control R"; - static final String SaveAC = "control S"; - static final String SafetyAC = "control T"; - static final String ExcludedVAC = "control U"; - static final String PasteAC = "control V"; - static final String FairAC = "control W"; - static final String CutAC = "control X"; - static final String RedoAC = "control Y"; - static final String UndoAC = "control Z"; - - // Dummy accelerators - static String - AboutAC, CheckAC, DefaultAC, HelpAC, InterAC, LTLClearAC, - LTLLoadAC, LTLTranslateAC, LTLNameAC, MaxAC, MaxDepthAC, SeedAC, - NegateAC, NewAC, OptionsCAC, OptionsInterAC, OptionsPanAC, - OptionsRandomAC, OptionsSaveCurrentAC, OptionsSaveInstallAC, - OptionsTrailAC, RandomAC, SaveAsAC, SaveSpinAC, - SpiderDisplayAC, StopAC, StWidthAC, TrailAC, VerifyAC, RawAC; - - // Initialize configuration file - static public void init() { - setDefaultProperties(); - // Try to open config file in current directory; - // if not there, try installation directory; - // if not there, write default file - currentDirectory = System.getProperty("user.dir"); - installationDirectory = System.getProperty("java.class.path"); - int lastSeparator = installationDirectory.lastIndexOf(java.io.File.separator); - if (lastSeparator == -1) - installationDirectory = "."; - else - installationDirectory = installationDirectory.substring(0, lastSeparator); -// System.err.println(currentDirectory + java.io.File.separator + CONFIG_FILE_NAME); -// System.err.println(installationDirectory + java.io.File.separator + CONFIG_FILE_NAME); - FileInputStream in = null; - try { - in = new FileInputStream( - currentDirectory + java.io.File.separator + CONFIG_FILE_NAME); - System.err.println("Read configuration file from current directory"); - } catch (FileNotFoundException e1) { - try { - in = new FileInputStream( - installationDirectory + java.io.File.separator + CONFIG_FILE_NAME); - System.err.println("Read configuration file from installation directory"); - } catch (FileNotFoundException e4) { - System.err.println( - "Cannot open configuration file, creating new file"); - try { - saveFile(false); - in = new FileInputStream(installationDirectory + java.io.File.separator + CONFIG_FILE_NAME); - } catch (IOException e2) { - System.err.println("Cannot write configuration file"); - return; - } - } - } - try { - properties.load(in); - in.close(); - } catch (IOException e3) { - System.err.println("Cannot read configuration file"); - } - helpFileName = installationDirectory + java.io.File.separator + - properties.getProperty("HELP_FILE_NAME"); - aboutFileName = installationDirectory + java.io.File.separator + - properties.getProperty("ABOUT_FILE_NAME"); - } - - // Save configuration file - static void saveFile(boolean current) { - try { - FileOutputStream out = - new FileOutputStream( - (current ? currentDirectory : installationDirectory) - + java.io.File.separator + CONFIG_FILE_NAME); - properties.store(out, "jSpin configuration file"); - out.close(); - System.err.println("Saved jSpin configuration file config.cfg"); - } catch (IOException e2) { - System.err.println("Cannot write configuration file"); - } - } - - // Interface to get/set propertyies of various types - public static String getStringProperty(String s) { - return properties.getProperty(s); - } - - static void setStringProperty(String s, String newValue) { - properties.setProperty(s, newValue); - } - - public static boolean getBooleanProperty(String s) { - return Boolean.valueOf(properties.getProperty(s)).booleanValue(); - } - - static void setBooleanProperty(String s, boolean newValue) { - properties.setProperty(s, Boolean.toString(newValue)); - } - - public static int getIntProperty(String s) { - return Integer.valueOf(properties.getProperty(s)).intValue(); - } - - static void setIntProperty(String s, int newValue) { - properties.setProperty(s, Integer.toString(newValue)); - } - - public static Properties getProperties() { - return properties; - } -} diff --git a/jspin/DisplayImage.java b/jspin/DisplayImage.java deleted file mode 100644 index 22d877d..0000000 --- a/jspin/DisplayImage.java +++ /dev/null @@ -1,25 +0,0 @@ -/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -// Class DisplayFile for Help, About, Display raw -package jspin; -import javax.swing.*; -import java.awt.event.*; -class DisplayImage extends JFrame implements ActionListener { - DisplayImage(String file) { - ImagePanel image = new ImagePanel(file); - getContentPane().add(new JScrollPane(image)); - setDefaultCloseOperation( - javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - getRootPane().registerKeyboardAction(this, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), - JComponent.WHEN_IN_FOCUSED_WINDOW); - setTitle(file); - setSize((int) (0.8*Config.getIntProperty("WIDTH")), - (int) (0.9*Config.getIntProperty("HEIGHT"))); - setLocationRelativeTo(null); - setVisible(true); - } - public void actionPerformed(ActionEvent e) { - dispose(); - } -} - diff --git a/jspin/Editor.java b/jspin/Editor.java deleted file mode 100644 index eb9b538..0000000 --- a/jspin/Editor.java +++ /dev/null @@ -1,347 +0,0 @@ -/* Copyright 2003-7 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * Editor for Promela programs - */ - -package jspin; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.border.*; -import java.awt.*; -import java.awt.datatransfer.*; -import java.io.*; - -class Editor implements ClipboardOwner, DocumentListener { - File file; // The file to be edited - File lastFile; // Previous file to be edited - String fileName; // The name of the file - String fileRoot; // The file name without its extension - String extension = ""; // The extension of the source file - String root; // The path to the file - String LTLFileName = ""; // LTL file name for this source file - String OUTFileName = ""; // Spin display output file name - String EXCFileName = ""; // File for excluded variable names - String EXSFileName = ""; // File for excluded statements - String PRPFileName = ""; // Property file name for this source file - String PRPName; // Property file name without path - - private JTextArea area; // The area for editing - private JTextField LTLField; // The area for LTL formulas - private JTextArea messageArea; // The area for messages - private String findString; // The string to search for - private int findLoc; // The last location where it was found - private boolean modified; // Was area modified? - private boolean LTLmodified; // Was LTL field modified? - private Border border1; // Border - not modified - private Border border2; // Border - modified - private static final Border border = - BorderFactory.createMatteBorder(2,0,0,0,Color.gray); - private Clipboard clipboard; - private LineNumbers lineNumbers; - private filterSpin.Filter filter; // For setting excluded variable names - - public Editor(JScrollPane jsp, JTextArea a, JTextArea m, JTextField l, - javax.swing.event.UndoableEditListener ud, filterSpin.Filter f) { - area = a; - area.getDocument().addDocumentListener(this); - area.getDocument().addUndoableEditListener(ud); - LTLField = l; - LTLField.getDocument().addDocumentListener(this); - messageArea = m; - PRPName = ""; - clipboard = area.getToolkit().getSystemClipboard(); - lineNumbers = new LineNumbers(area); - jsp.setRowHeaderView(lineNumbers); - filter = f; - } - - void focus(boolean start) { - area.requestFocusInWindow(); - if (start) - area.setCaretPosition(0); - } - - void caretToLine(int line) { - try { - area.requestFocusInWindow(); - area.setCaretPosition(area.getLineStartOffset(line-1)); - } catch (Exception e) { - area.setCaretPosition(0); - } - } - - void cut() { - if (area.getSelectionStart() != area.getSelectionEnd()) { - String s = area.getSelectedText(); - StringSelection contents = new StringSelection(s); - clipboard.setContents(contents, this); - area.replaceRange(null, - area.getSelectionStart(), area.getSelectionEnd()); - } - } - - void copy() { - if (area.getSelectionStart() != area.getSelectionEnd()) { - String s = area.getSelectedText(); - StringSelection contents = new StringSelection(s); - clipboard.setContents(contents, this); - } - } - - void paste() { - Transferable content = clipboard.getContents(this); - if (content != null) { - try { - String s = (String)content.getTransferData( - DataFlavor.stringFlavor); - area.replaceRange(s, - area.getSelectionStart(), area.getSelectionEnd()); - } catch (Exception ex) { - System.err.println("Can't paste"); - } - } - } - - private void showArea(String title) { - String previousTitle = " / " + - ((lastFile == null) ? "-" : lastFile.getName()) + " "; - findString = null; - findLoc = 0; - modified = false; - border1 = BorderFactory.createTitledBorder( - border, " " + title + previousTitle, - TitledBorder.LEFT, TitledBorder.TOP); - border2 = BorderFactory.createTitledBorder( - border, " " + title + " * " + previousTitle, - TitledBorder.LEFT, TitledBorder.TOP); - area.setBorder(border1); - focus(true); - } - - void newFile() { - root = ""; - file = null; - fileName = ""; - fileRoot = ""; - LTLFileName = ""; - OUTFileName = ""; - EXCFileName = ""; - EXSFileName = ""; - PRPFileName = ""; - area.setText(""); - showArea(" "); - } - - private void setPMLRootAndName() { - fileName = file.getName(); - if (file.getParentFile() == null) - root = ""; - else - root = file.getParentFile().getAbsolutePath(); - if (fileName.lastIndexOf('.') == -1) - fileRoot = fileName; - else { - fileRoot = fileName.substring(0, fileName.lastIndexOf('.')); - extension = fileName.substring(fileName.lastIndexOf('.')); - } - LTLFileName = root + File.separator + fileRoot + ".ltl"; - OUTFileName = root + File.separator + fileRoot + ".out"; - EXCFileName = root + File.separator + fileRoot + ".exc"; - EXSFileName = root + File.separator + fileRoot + ".exs"; - PRPFileName = root + File.separator + fileRoot + ".prp"; - PRPName = ""; - showArea(fileName); - } - - private void setPRPRootAndName(File fc) { - String fileName = fc.getName(); - String fileRoot, root; - if (file.getParentFile() == null) - root = ""; - else - root = fc.getParentFile().getAbsolutePath(); - if (fileName.lastIndexOf('.') == -1) - fileRoot = fileName; - else - fileRoot = fileName.substring(0, fileName.lastIndexOf('.')); - LTLFileName = root + File.separator + fileRoot + ".ltl"; - PRPFileName = root + File.separator + fileRoot + ".prp"; - PRPName = fileRoot + ".prp"; - } - - // Open file: Promela (and excluded) or property file - void openFile(File fc, boolean pml) { - String prp = ""; - if (pml) { - if (!fc.exists()) { - messageArea.append("File "+fc+" does not exist\n"); - focus(true); - return; - } - file = fc; - area.setText(readFile(fc)); - setPMLRootAndName(); - prp = readFile(new java.io.File(PRPFileName)); - filter.setExcluded(readFile(new java.io.File(EXCFileName)), true); - filter.setExcluded(readFile(new java.io.File(EXSFileName)), false); - } - else { - if (fc.exists()) - prp = readFile(fc); - else - messageArea.append("Creating new prp file\n"); - setPRPRootAndName(fc); - } - LTLField.setText(prp.startsWith("Error") ? "" : prp); - LTLmodified = false; - } - - String readFile(File fc) { - BufferedReader textReader = null; - try { - textReader = new BufferedReader(new FileReader(fc)); - } catch (IOException e) { - focus(true); - return "Error opening file " + fc; - } - StringWriter textWriter = new StringWriter(); - int c = 0; - try { - while (true) { - c = textReader.read(); - if (c == -1) - break; - else - textWriter.write(c); - } - } catch (IOException e) { - focus(true); - return "Error reading file " + fc; - } - try { - textReader.close(); - } - catch (IOException e) { - focus(true); - return "Error closing file " + fc; - } - return textWriter.toString(); - } - - void saveFile(File fc) { - if (fc != null) { - file = fc; - setPMLRootAndName(); - LTLmodified = true; // To force saving - modified = true; - } - if (LTLmodified) { - if (!LTLField.getText().equals("")) - writeFile(new java.io.File(PRPFileName), LTLField); - LTLmodified = false; - } - if (modified) { - area.setBorder(border1); - writeFile(file, area); - modified = false; - } - } - - void writeFile(File fc, javax.swing.text.JTextComponent area) { - if (fc == null || area == null) - return; - BufferedWriter textWriter = null; - try { - textWriter = new BufferedWriter(new FileWriter(fc)); - } catch (IOException e) { - System.err.println("Error opening file " + fc); - focus(true); - return; - } - BufferedReader textReader = - new BufferedReader(new StringReader(area.getText())); - int c = 0; - try { - while (true) { - c = textReader.read(); - if (c == -1) - break; - else - textWriter.write(c); - } - } catch (IOException e) { - System.err.println("Error writing file " + fc); - focus(true); - return; - } - try { - textWriter.flush(); - textWriter.close(); - } catch (IOException e) { - System.err.println("Error closing file " + fc); - focus(true); - return; - } - messageArea.append("Saved " + fc.getName() + "\n"); - } - - void find() { - findString = JOptionPane.showInputDialog( - area, null, "Find", JOptionPane.PLAIN_MESSAGE); - if (findString != null) { - search(); - findLoc = area.getCaretPosition(); - } else - focus(false); - } - - void findAgain() { - if (findString != null) - search(); - else - focus(false); - } - - private void search() { - int found = area.getText().toLowerCase().indexOf( - findString.toLowerCase(), findLoc); - if (found != -1) { - findLoc = found + 1; - area.setCaretPosition(found); - area.moveCaretPosition(found+findString.length()); - } - focus(false); - } - - private void setModified(DocumentEvent e) { - modified = true; - area.setBorder(border2); - final int lines = area.getLineCount(); - if (lineNumbers != null) { - Runnable updateAComponent = new Runnable() { - public void run() { - lineNumbers.setHeightByLines(lines); - } - }; - SwingUtilities.invokeLater(updateAComponent); - } - } - - public void modifiedLTL() { - LTLmodified = true; - } - - public void changedUpdate(DocumentEvent e) { - setModified(e); - } - - public void insertUpdate(DocumentEvent e) { - setModified(e); - } - - public void removeUpdate(DocumentEvent e) { - setModified(e); - } - - public void lostOwnership(Clipboard clipboard, Transferable content) {} -} diff --git a/jspin/Filter.java b/jspin/Filter.java deleted file mode 100644 index ed59baa..0000000 --- a/jspin/Filter.java +++ /dev/null @@ -1,213 +0,0 @@ -/* Copyright 2004-5 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * Filter Spin output. - * Display a table: process, statement, variables. - * The width of a variable field is dynamically configurable (VARIABLE_WIDTH). -*/ - -package jspin; -import java.util.*; - -class Filter { - private static final String spacerTitle = " "; - - // Print the title repeatedly - private static final int linesPerTitle = 20; - private String title; // String for names of variables - private int lines; // Line counter to redisplay title - - // Map of variable names and values - private TreeMap variables = new TreeMap(); - private int oldSize; // Previous size to see if variable added - - // Excluded variable names and statements - private ArrayList excludedVar = new ArrayList(); - private ArrayList excludedState = new ArrayList(); - - // Called before each new command - void init () { - variables.clear(); - oldSize = 0; - title = ""; - lines = -1; - } - - // Parse string to initialize excluded array; ignore NL and CR - void setExcluded(String s, boolean exVar) { - ArrayList excluded = exVar ? excludedVar : excludedState; - s = s.replace('\r', '\n'); - excluded.clear(); - do { - int nl = s.indexOf('\n'); - if (nl == -1) break; - if (!s.substring(0,nl).equals("")) - excluded.add(s.substring(0,nl)); - s = s.substring(nl+1); - } while (true); - } - - // Check for excluded variables. - // For each excluded string S; - // If variable name includes S, do not display, - // but if some +T in file is in name, display anyway. - private boolean checkExcluded(String name, boolean exVar) { - ArrayList excluded = exVar ? excludedVar : excludedState; - for (int i = 0; i < excluded.size(); i++) - if ((excluded.get(i).charAt(0) != '+') && - (name.indexOf(excluded.get(i)) != -1)) { - boolean included = false; - for (int j = 0; j < excluded.size(); j++) - included = included || - ((excluded.get(j).charAt(0) == '+') && - (name.indexOf(excluded.get(j).substring(1)) != -1)); - return !included; - } - return false; - } - - String filter(String s) { - try { - // Variables and queues start with double tab - if (s.startsWith("\t\t")) { - String varName, varValue; - // Name and value of variable/queue to TreeMap - if (s.startsWith("\t\tqueue")) { - varName = s.substring(s.indexOf('(')+1, s.indexOf(')')); - varValue = s.substring(s.indexOf(':')+1).trim(); - } - else { - varName = s.substring(2, s.indexOf('=')-1); - varValue = s.substring(s.indexOf('=')+1).trim(); - } - if (checkExcluded(varName, true)) return ""; - variables.put(varName, varValue); - // Construct new title if new variables encountered - if (variables.size() > oldSize) { - title = formatItem(Config.processTitle, - Config.getIntProperty("PROCESS_WIDTH")) + - spacerTitle + - formatItem(Config.statementTitle, - Config.getIntProperty("STATEMENT_WIDTH")) + - spacerTitle + - collectionToString(variables.keySet()) + "\n"; - oldSize = variables.size(); - lines = -1; - } - return ""; - } - - // Display Spin and pan messages unmodified - // Also non-prefixed error message - else if ((s.startsWith("pan:")) || - (s.startsWith("spin:")) || - (s.startsWith("tl_spin:")) || - (s.startsWith("Error:")) || - (s.startsWith("error:")) ) - return s + "\n"; - // Display error count - else if (s.indexOf("errors:") != -1) - return - s.substring(0, s.indexOf("errors:")) + "\u2022\u2022\u2022 " + - s.substring(s.indexOf("errors:")) + " \u2022\u2022\u2022\n"; - // Display MSC lines (without MSC:) - else if (Config.getBooleanProperty("MSC") && - s.trim().startsWith("MSC:")) - return s.substring(s.indexOf("MSC:")+5) + "\n"; - // Display cycle messages - else if (s.indexOf("<<<<<") != -1) - return s + "\n"; - - // Display lines with statements, including choices - else if ((s.indexOf("proc") != -1) && (s.indexOf("line") != -1)) { - String u = ""; - // Get process name - String proc = - s.substring(s.indexOf("proc")+4, s.indexOf(")")+1).trim(); - proc = proc.substring(0, proc.indexOf("(")) + - strip(proc.substring(proc.indexOf("("))); - // Get line number and statement name - String statement = ""; - if (s.indexOf('[') != -1) { - statement = formatItem( - s.substring(s.indexOf("line")+4,s.indexOf("\"")).trim(), 3); - statement = statement + " " + - strip(s.substring(s.indexOf('[')+1, s.lastIndexOf(']'))); - } - if (checkExcluded(statement, false)) return ""; - // For choice, display just process and statement - if (s.indexOf("choice") != -1) - u = s.substring(s.indexOf("choice"), s.indexOf(':')+2) + - proc + " " + statement + "\n"; - // Display table line (unless goto/else/break) - else if ((statement.indexOf("goto") == -1) && - !statement.equals("else") && - !statement.equals("break")) { - u = formatItem(proc, - Config.getIntProperty("PROCESS_WIDTH")) + - spacerTitle + - formatItem(statement, - Config.getIntProperty("STATEMENT_WIDTH")) + - spacerTitle + - collectionToString(variables.values()) + "\n"; - lines = (lines + 1) % linesPerTitle; - // Display title if needed - if (lines == 0) u = title + u; - } - return u; - } - // Display choices that have no proc and line number - else if (s.indexOf("choice") != -1) - return s.substring(s.indexOf("choice")) + "\n"; - else if (!Config.getBooleanProperty("MSC") && !s.equals("")) - return s + "\n"; - else - return ""; - - } catch (Exception e) { - System.err.println("\n + jSpin error in filter for:\n" + s + "\n"); - e.printStackTrace(); - return ""; - } - } - - // Strip parentheses - String strip(String s) { - while ( (s.charAt(0)=='(') && (s.charAt(s.length()-1)==')')) - s = s.substring(1, s.length()-1); - return s; - } - - // Format a variable name or value - private String formatItem(String s, int len) { - // Item is too long, must shorten it - if (s.length() > len) { - // Array variable: shorten name, not index - if (s.indexOf("[") != -1) { - String subscript = - s.substring(s.indexOf("["), s.lastIndexOf("]")+1); - if (subscript.length() < len) - return s.substring(0, - len-subscript.length()) + subscript; - else - return s.substring(0, len); - } - else - return s.substring(0,len); - } - // Item is too short, pad it - else if (s.length() < len) - return (s + " ").substring(0,len); - else - return s; - } - - // Transform a collection to a string, calling formatItem for each element - private String collectionToString(Collection c) { - String s = ""; - Iterator it = c.iterator(); - while (it.hasNext()) - s = s + formatItem(it.next(), - Config.getIntProperty("VARIABLE_WIDTH")) + " "; - return s; - } -} diff --git a/jspin/MANIFEST.MF b/jspin/MANIFEST.MF deleted file mode 100644 index 5983cab..0000000 --- a/jspin/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: jspin.jSpin - diff --git a/jspin/Options.java b/jspin/Options.java deleted file mode 100644 index 8bdb4e9..0000000 --- a/jspin/Options.java +++ /dev/null @@ -1,113 +0,0 @@ -/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * Dialog for setting Common Options - */ - -package jspin; -import javax.swing.*; -import java.awt.event.*; - -class Options extends JFrame implements ActionListener, ItemListener { - static final String - ST = "-p", LOC = "-l", GLO = "-g", SENT = "-s", REC = "-r"; - private JCheckBox stBox, locBox, gloBox, sentBox, recBox; - private JButton okButton, cancelButton, clearAllButton, setAllButton; - private JPanel buttonPanel, OKPanel; - private boolean st, loc, glo, sent, rec; - - JCheckBox create(String s, boolean set, int mn) { - JCheckBox cb = new JCheckBox(s, set); - cb.setMnemonic(mn); - cb.addItemListener(this); - buttonPanel.add(cb); - return cb; - } - - Options() { - String s = Config.getStringProperty("COMMON_OPTIONS"); - st = s.indexOf(ST) != -1; - loc = s.indexOf(LOC) != -1; - glo = s.indexOf(GLO) != -1; - sent = s.indexOf(SENT) != -1; - rec = s.indexOf(REC) != -1; - buttonPanel = new JPanel(); - buttonPanel.setLayout(new java.awt.GridLayout(5,1)); - stBox = create(Config.Statements, st, Config.StatementsMN); - locBox = create(Config.Locals, loc, Config.LocalsMN); - gloBox = create(Config.Globals, glo, Config.GlobalsMN); - sentBox = create(Config.Sent, sent, Config.SentMN); - recBox = create(Config.Received, rec, Config.ReceivedMN); - OKPanel = new JPanel(); - OKPanel.setLayout(new java.awt.GridLayout(2,2)); - okButton = new JButton(Config.OK); - cancelButton = new JButton(Config.Cancel); - clearAllButton = new JButton(Config.ClearAll); - setAllButton = new JButton(Config.SetAll); - okButton.setMnemonic(Config.OKMN); - clearAllButton.setMnemonic(Config.ClearAllMN); - setAllButton.setMnemonic(Config.SetAllMN); - OKPanel.add(okButton); - OKPanel.add(cancelButton); - OKPanel.add(setAllButton); - OKPanel.add(clearAllButton); - okButton.addActionListener(this); - cancelButton.addActionListener(this); - setAllButton.addActionListener(this); - clearAllButton.addActionListener(this); - getRootPane().setDefaultButton(okButton); - getRootPane().registerKeyboardAction(this, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), - JComponent.WHEN_IN_FOCUSED_WINDOW); - getContentPane().add(buttonPanel, java.awt.BorderLayout.CENTER); - getContentPane().add(OKPanel, java.awt.BorderLayout.SOUTH); - setTitle(Config.OPTIONS_TITLE); - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setSize(200, 250); - setLocationRelativeTo(null); - validate(); - setVisible(true); - } - - private void setClear(boolean b) { - st = b; loc = b; glo = b; sent = b; rec = b; - stBox.setSelected(b); - locBox.setSelected(b); - gloBox.setSelected(b); - sentBox.setSelected(b); - recBox.setSelected(b); - } - - public void actionPerformed(ActionEvent e) { - String options = ""; - if (e.getSource() == okButton) { - options = options + (st ? ST + " " : ""); - options = options + (loc ? LOC + " " : ""); - options = options + (glo ? GLO + " " : ""); - options = options + (sent ? SENT + " " : ""); - options = options + (rec ? REC + " " : ""); - Config.setStringProperty("COMMON_OPTIONS", options); - dispose(); - } - else if (e.getSource() == setAllButton) { - setClear(true); - } - else if (e.getSource() == clearAllButton) { - setClear(false); - } - else - dispose(); - } - - public void itemStateChanged(ItemEvent e) { - if (e.getItemSelectable() == stBox) - st = e.getStateChange() == ItemEvent.SELECTED; - else if (e.getItemSelectable() == locBox) - loc = e.getStateChange() == ItemEvent.SELECTED; - else if (e.getItemSelectable() == gloBox) - glo = e.getStateChange() == ItemEvent.SELECTED; - else if (e.getItemSelectable() == sentBox) - sent = e.getStateChange() == ItemEvent.SELECTED; - else if (e.getItemSelectable() == recBox) - rec = e.getStateChange() == ItemEvent.SELECTED; - } -} diff --git a/jspin/RunSpin.java b/jspin/RunSpin.java deleted file mode 100644 index f3b5a54..0000000 --- a/jspin/RunSpin.java +++ /dev/null @@ -1,376 +0,0 @@ -/* Copyright 2003-4 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* -* Fork process for running Spin -* Manage dialog for interactive simulation -*/ - -package jspin; -import javax.swing.*; -import java.io.*; -import java.awt.event.*; -import java.util.StringTokenizer; - -class RunSpin { - private Editor editor; // The editor object - private filterSpin.Filter filter; // The filter object - private RunThread runThread; // Thread object for running Spin - private SelectDialog selectDialog; // Thread object for select dialog - - private JTextArea messageArea; // The message area - private JTextArea area; // Output area display - private PrintWriter rawWriter; // To write raw spin output - - private String command, parameters; // The command being executed - private boolean filtering; // Should the output be filtered - private static final int MAX_SELECTIONS = 50; - private String[] selections = new String[MAX_SELECTIONS]; - // Statements selected from - - RunSpin(Editor e, JTextArea m, filterSpin.Filter f) { - editor = e; - messageArea = m; - filter = f; - } - - // Called by jSpin to run Spin - void run(JTextArea area, boolean filtering, String command, String parameters) { - this.filtering = filtering; - this.area = area; - this.command = command; - this.parameters = parameters; - filter.init(Config.properties); - // Make sure that a file has been opened - if (editor.file == null) { - jSpin.append(messageArea, Config.OPEN_FILE); - return; - } - // Save editor buffer and set up display areas - editor.saveFile(null); - if (area != messageArea) - this.area.setText(""); - jSpin.append(messageArea, command + " " + parameters + " ... "); - // Create a thread to run Spin and start it - runThread = new RunThread(); - runThread.start(); - } - - // Run Spin and wait for it to complete - void runAndWait(JTextArea area, boolean filtering, String command, String parameters) { - run(area, filtering, command, parameters); - if (runThread == null) return; // If file not open - try { - runThread.join(); - jSpin.append(messageArea, "done!\n"); - } catch (InterruptedException e) {} - } - - // Check is Spin is still running - boolean isRunning() { - return (runThread != null) && runThread.isAlive(); - } - - // Kill the thread running Spin and the selection dialog - void killSpin() { - if (runThread != null) { - runThread.killSpin(); - runThread.interrupt(); - runThread = null; - } - if (selectDialog != null) { - selectDialog.disposeDialog(); - selectDialog.interrupt(); - selectDialog = null; - } - jSpin.append(messageArea, "\nSpin process stopped\n"); - } - - // Class RunThread enables Spin to run asynchronously - private class RunThread extends Thread { - private Process p; - - public void run() { - try { - if (Config.getBooleanProperty("RAW")) - rawFile(); - // Use ProcessBuilder to run Spin, redirecting ErrorStream - String[] sa = stringToArray(command, parameters); -// for (int i = 0; i < sa.length; i++) System.out.println(sa[i]); - ProcessBuilder pb = new ProcessBuilder(sa); - File pf = editor.file.getParentFile(); - if (pf != null) pb.directory(pf.getCanonicalFile()); - pb.redirectErrorStream(true); - p = pb.start(); - // Connect to I/O streams - InputStream istream = p.getInputStream(); - BufferedReader input = - new BufferedReader(new InputStreamReader(istream)); - OutputStream ostream = p.getOutputStream(); - OutputStreamWriter output = new OutputStreamWriter(ostream); - // Process Spin output line by line - String s = ""; - boolean running = true; - while (running) { - s = input.readLine(); - if (Config.getBooleanProperty("RAW")) - rawWriter.println(s); - if (s == null) - running = false; - else if (s.startsWith("Select a statement") || - s.startsWith("Select stmnt")) - running = select(area, p, input, output); - else if (s.startsWith("spin: type return")) { - output.write("\n"); - output.flush(); - } - else if (filtering) - jSpin.append(area, filter.filter(s)); - else - jSpin.append(area, s + "\n"); - } - // Wait for Spin process to end - p.waitFor(); - if (Config.getBooleanProperty("RAW")) - rawWriter.close(); - // If syntax error, set cursor to line in editor - if (area.getText().indexOf("Error: syntax error") != -1) { - s = area.getText(); - try { - int line = Integer.parseInt( - s.substring( - s.indexOf("line")+4, s.indexOf('"')).trim()); - editor.caretToLine(line); - } catch (NumberFormatException e1) { - editor.caretToLine(0); - } - } - } catch (InterruptedException e) { - jSpin.append(messageArea, "Interrupted exception"); - } - catch (java.io.IOException e) { - jSpin.append(messageArea, "IO exception\n" + e); - } - } - - // String to array of tokens - for ProcessBuilder - // Previous versions of jSpin used StringTokenizer - // which caused problems in Linux - String[] stringToArray(String command, String s) { - char quote = Config.getBooleanProperty("SINGLE_QUOTE") ? '\'' : '"'; - String[] sa = new String[50]; - int count = 0, i = 0, start = 0; - sa[count] = command; - count++; - while (i < s.length() && s.charAt(i) == ' ') i++; - start = i; - boolean isQuote; - do { - if (i == s.length()) break; - isQuote = s.charAt(i) == quote; - if (isQuote) i++; - if (isQuote) { - while (s.charAt(i) != quote) i++; - i++; - } - else - while (i < s.length() && s.charAt(i) != ' ') i++; - sa[count] = s.substring(start, i); - while (i < s.length() && s.charAt(i) == ' ') i++; - start = i; - count++; - } while (true); - String[] sb = new String[count]; - System.arraycopy(sa, 0, sb, 0, count); - return sb; - } - - // Kill spin process - private void killSpin() { - if (p != null) p.destroy(); - } - - // Open file for raw Spin output - private void rawFile() { - String s = editor.root + File.separator + editor.fileRoot + ".raw"; - try { - rawWriter = new PrintWriter(new FileWriter(s)); - jSpin.append(messageArea, "\nOpened " + s + "\n"); - } catch (IOException e) { - jSpin.append(messageArea, "\nCannot open " + s + "\n"); - } - } - - // Select the next statement to run in interactive simulation - private boolean select( - JTextArea area, Process p, - BufferedReader input, OutputStreamWriter output) { - int numOptions = 0; - String filtered; - try { - String s = input.readLine(); - if (Config.getBooleanProperty("RAW")) - rawWriter.println(s); - while (!s.startsWith("Make Selection")) { - filtered = filter.filter(s); - if ((numOptions < MAX_SELECTIONS) && - (Config.getBooleanProperty("UNEXECUTABLE") || - s.indexOf("unexecutable") == -1)) { - selections[numOptions] = new String(filtered.substring(7)); - numOptions++; - } - s = input.readLine(); - if (Config.getBooleanProperty("RAW")) - rawWriter.println(s); - } - if (numOptions == 0) { - output.write("q\n"); - output.flush(); - return false; - } - // Get selection from dialog - int selectedValue = -1; - selectDialog = - new SelectDialog( - numOptions, - numOptions <= Config.getIntProperty("SELECT_MENU"), - selections); - selectDialog.start(); - while (selectedValue == -1) { - try { - Thread.sleep(Config.getIntProperty("POLLING_DELAY")); - } - catch (InterruptedException e) {} - if (selectDialog == null) break; - else selectedValue = selectDialog.getValue(); - } - // For Macintosh (?) - Angelika's problem (?) - if (selectDialog != null) { - selectDialog.interrupt(); - selectDialog = null; - } - // if (selectDialog != null) selectDialog.interrupt(); - // If 0 (escape or close) selected, quit Spin interaction - if (selectedValue == 0) { - output.write("q\n"); - output.flush(); - return false; - } - selectedValue = Integer.valueOf( - selections[selectedValue-1].substring( - 0, selections[selectedValue-1].indexOf(':'))); - // Send selection to Spin - output.write(selectedValue + "\n"); - output.flush(); - s = input.readLine(); // Eat extra new line - if (Config.getBooleanProperty("RAW")) - rawWriter.println(s); - return true; - } catch (Exception e) { - System.err.println(e); - killSpin(); - return false; - } - } - } - - // Class SelectDialog displays the statement select dialog in a thread - private class SelectDialog extends Thread implements ActionListener { - private int selectedValue = -1; - // Positive when a button is selected, zero upon escape or close - private int numOptions; // Number of process buttons - private String[] selections;// The selections - - private JFrame dialog; // The frame - private JPanel panel; - private JButton[] options; // Array of process buttons - private JComboBox pulldown = new JComboBox(); - - // Constructor - set up frame with number of buttons required - SelectDialog (int numOptions, boolean buttons, String[] selections) { - this.numOptions = numOptions; - this.selections = selections; - dialog = new JFrame(); - dialog.addWindowListener( - new WindowAdapter() { - public void windowClosing(WindowEvent e) { - selectedValue = 0; - dialog.dispose(); - } - }); - dialog.getRootPane().registerKeyboardAction(this, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), - JComponent.WHEN_IN_FOCUSED_WINDOW); - dialog.setTitle(Config.SELECT); - panel = new JPanel(); - if (buttons) constructButtonsDialog(); else constructMenuDialog(); - dialog.getContentPane().setLayout(new java.awt.BorderLayout()); - dialog.getContentPane().add(panel, java.awt.BorderLayout.CENTER); - dialog.setLocationRelativeTo(messageArea); - dialog.validate(); - dialog.setVisible(true); - } - - void constructButtonsDialog() { - panel.setLayout(new java.awt.GridLayout(1, numOptions)); - options = new JButton[numOptions]; - JButton button = null; - for (int i = 1; i <= numOptions; i++) { - button = new JButton(selections[i-1]); - button.setFont(messageArea.getFont()); - button.addActionListener(this); - options[i-1] = button; - panel.add(button); - } - dialog.setSize( - Config.getIntProperty("SELECT_BUTTON") * numOptions, - Config.getIntProperty("SELECT_HEIGHT")); - } - - void constructMenuDialog() { - panel.setLayout(new java.awt.BorderLayout()); - pulldown = new JComboBox(); - pulldown.setFont(messageArea.getFont()); - pulldown.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); - pulldown.setEditable(false); - for (int i = 0; i < numOptions; i++) - pulldown.addItem(selections[i]); - pulldown.setSelectedIndex(-1); - pulldown.addActionListener(this); - panel.add(pulldown, java.awt.BorderLayout.CENTER); - dialog.setSize( - Config.getIntProperty("SELECT_BUTTON"), - Config.getIntProperty("SELECT_HEIGHT")); - } - - // Display dialog - public void run() { - dialog.setVisible(true); - } - - // ActionListener - public void actionPerformed(ActionEvent e) { - if (e.getSource() instanceof JButton) { - JButton selected = (JButton) e.getSource(); - for (int i = 0; i < numOptions; i++) - if (options[i].equals(selected)) - selectedValue = i+1; - } - else if (e.getSource() instanceof JComboBox) { - selectedValue = ((JComboBox)e.getSource()).getSelectedIndex()+1; - } - else selectedValue = 0; - dialog.dispose(); - java.awt.Dimension rv = ((JComponent)e.getSource()).getSize(null); - Config.setIntProperty("SELECT_BUTTON", rv.width); - } - - // Dispose of dialog frme - private void disposeDialog() { - if (dialog != null) dialog.dispose(); - } - - // Get value - private int getValue() { - return selectedValue; - } - } -} diff --git a/mingw.iss b/mingw.iss index 6259025..79a513a 100644 --- a/mingw.iss +++ b/mingw.iss @@ -1,20 +1,20 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -[Setup] -AppName=MINGW -AppVerName=mingw -DefaultDirName=c:\mingw -DefaultGroupName=MinGW -DisableProgramGroupPage=yes -OutputDir=c:\vn -Compression=lzma -SolidCompression=yes - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Files] -Source: "C:\mingw\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs -; NOTE: Don't use "Flags: ignoreversion" on any shared system files - +; Script generated by the Inno Setup Script Wizard. +; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! + +[Setup] +AppName=MINGW +AppVerName=mingw +DefaultDirName=c:\mingw +DefaultGroupName=MinGW +DisableProgramGroupPage=yes +OutputDir=c:\vn +Compression=lzma +SolidCompression=yes + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Files] +Source: "C:\mingw\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..be39104 --- /dev/null +++ b/pom.xml @@ -0,0 +1,65 @@ + + + 4.0.0 + + com.spinroot + jspin + 5.0.0 + + jar + + + 1.8 + 1.8 + UTF-8 + UTF-8 + + + + + commons-io + commons-io + 2.5 + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.0.0 + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + true + lib/ + com.spinroot.jspin.jSpin + + + + + + + \ No newline at end of file diff --git a/spider-examples/second.pml b/spider-examples/second.pml index 96c8e6c..47a1e9d 100644 --- a/spider-examples/second.pml +++ b/spider-examples/second.pml @@ -1,19 +1,19 @@ -/* Second attempt */ -bool wantp = false, wantq = false; - -active proctype p() { - do :: - !wantq; - wantp = true; -csp: wantp = false; - od -} - -active proctype q() { - do :: !wantp; - wantq = true; -csq: wantq = false; - od -} - -ltl { !<>(p@csp && q@csq) } +/* Second attempt */ +bool wantp = false, wantq = false; + +active proctype p() { + do :: + !wantq; + wantp = true; +csp: wantp = false; + od +} + +active proctype q() { + do :: !wantp; + wantq = true; +csq: wantq = false; + od +} + +ltl { !<>(p@csp && q@csq) } diff --git a/spider-examples/third.pml b/spider-examples/third.pml index b695c75..8fb3bcd 100644 --- a/spider-examples/third.pml +++ b/spider-examples/third.pml @@ -1,16 +1,17 @@ -bool wantp = false, wantq = false; +bool wantp = false, wantq = false; + +active proctype p() { + do :: wantp = true; + !wantq; +cs: wantp = false; + od +} + +active proctype q() { + do :: +wantq = true; + !wantp; +cs: wantq = false; + od +} -active proctype p() { - do :: wantp = true; - !wantq; -cs: wantp = false; - od -} - -active proctype q() { - do :: wantq = true; - !wantp; -cs: wantq = false; - od -} - diff --git a/spinSpider/Config.java b/spinSpider/Config.java deleted file mode 100644 index d9ec322..0000000 --- a/spinSpider/Config.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - Config - configuration constants and file - Copyright 2005-10 by Mordechai (Moti) Ben-Ari. See SpinSpider.java -*/ -package spinSpider; - -public class Config { - static final String VERSION = "6.0"; - - // Properties data structure is used for command names - // Initialize properties from file or create file or from defaults - static final String CONFIG_FILE = "config.cfg"; - public static final String[] names = { "", "-trail-1", "-trail-2", "-automata" }; - - static public void setDefaultProperties( - java.util.Properties properties) { - // Spin version: format changed with Spin 6 - properties.put("VERSION", "6"); - - properties.put("C_COMPILER", "c:\\mingw\\bin\\gcc.exe"); - properties.put("SPIN", "bin\\spin.exe"); - properties.put("PAN", "pan.exe"); - properties.put("DOT", "bin\\dot.exe"); - } - - static public void init(java.util.Properties properties) { - setDefaultProperties(properties); - try { - properties.load(new java.io.FileInputStream(CONFIG_FILE)); - } catch (java.io.IOException e1) { - System.err.println("Cannot open configuration file; using defaults"); - } - } - - static final int MAX_STACK = 1000; // Stack for processing -DCHECK file - static final int INITIAL = 100; // For ArrayLists - static final int DELTA = 1000; // For node offset in automata - - static final String TITLE = - "SpinSpider Version " + VERSION + - " Copyright 2005-7 (GNU GPL) by Moti Ben-Ari."; - - static final String USAGE = - "Usage java spinSpider.SpinSpider arguments file\n\n" + - " file Promela source file\n\n" + - " -p number of processes (must be >= 1)\n" + - " -vname name of a variable (one parameter per variable)\n\n" + - " -dot dot format\n" + - " -Txxx dot format and run DOT to convert to xxx format\n" + - " (default is png)\n" + - " -fsm fsm format\n\n" + - " -t1 use trail file to emphasize a path\n" + - " -t2 use trail file to draw a path\n" + - " -a draw automata corresponding to source\n\n" + - " -small size of dot graph is smaller\n" + - " -bold bold style instead of color for path\n" + - " -debug write internal tables to file.dbg"; - - static final String dotTrailBold = " style = bold"; - static final String dotTrailColor = " color = red"; - - static final String[] smallDotPrologue = { - "\tgraph [size=\"12.5,7.5\",ranksep=.20];", - "\tnode [shape=box,fontname=Helvetica,fontsize=10];", - "\tnode [width=1.25,height=0.75,fixedsize=true];" - }; - - static final String[] largeDotPrologue = { - "\tgraph [size=\"16,12\",ranksep=.25];", - "\tnode [shape=box,fontname=Helvetica,fontsize=14];", - "\tnode [width=1.6,height=1.2,fixedsize=true];" - }; - static final String[] automataDotPrologue = { - "\tgraph [size=\"16,12\",ranksep=.4];", - "\tnode [shape=circle,fontname=Helvetica,fontsize=14];", - "\tedge [fontname=Helvetica,fontsize=14];" - }; - -} diff --git a/spinSpider/DrawAutomata.java b/spinSpider/DrawAutomata.java deleted file mode 100644 index a51cc23..0000000 --- a/spinSpider/DrawAutomata.java +++ /dev/null @@ -1,100 +0,0 @@ -/* Copyright 2007 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* - * Draw the automata representation of a Promela program. -*/ - -package spinSpider; -import java.io.*; - -public class DrawAutomata { - SpinSpider spd; - - public DrawAutomata(SpinSpider s) { - spd = s; - } - - // Extract an int value that appears between "from" and "to" in "s" - private static int extract(String s, String from, String to) { - return - Integer.parseInt( - s.substring(s.indexOf(from)+from.length(), s.indexOf(to)) - .trim()); - } - - public void drawAutomata() { - BufferedReader statementReader = null; - PrintWriter graphWriter = null; - String s = ""; - String fn = spd.fileName + Config.names[3]; - - spd.progress("Drawing automata"); - try { - statementReader = new BufferedReader( - new FileReader(spd.fileName + ".dbg")); - } catch (IOException e) { spd.fileError(".dbg"); } - try { - graphWriter = new PrintWriter( - new FileWriter(fn + ".dot")); - } catch (IOException e) { spd.fileError(".dot"); } - - // Write dot prologue - graphWriter.println("digraph \"" + fn + "\"" + " {"); - for (int i = 0; i < Config.automataDotPrologue.length; i++) - graphWriter.println(Config.automataDotPrologue[i]); - - // Skip over first parts of debug files - while (true) { - try { s = statementReader.readLine(); } - catch (IOException e) { spd.fileError(".dbg"); } - if (s == null) - spd.fileError(".dbg"); - else - if (s.equals("Statements from -d file")) - break; - } - - // Extract data from each line and write nodes and edges - // Use DELTA to create unique node numbers for each process - int process = 0, proc, line, source, target; - boolean endState = false, atomic = false, previousAtomic = false; - String emphasize = spd.trailStyle == 0 ? Config.dotTrailColor : Config.dotTrailBold; - while (true) { - try { s = statementReader.readLine(); } - catch (IOException e) { spd.fileError(".dbg"); } - if (s == null) break; - if (s.indexOf("process") == -1) break; - proc = extract(s, "process=", ", source"); - // New process - if (proc != process) { - process = proc; - endState = false; - } - source = extract(s, "source=", ", target") + process*Config.DELTA; - line = extract(s, "line=", "."); - graphWriter.println(source + " [label=" + line + "]"); - target = extract(s, "target=", ", id") + process*Config.DELTA; - if ((target == process*Config.DELTA) && !endState) { - endState = true; - graphWriter.println(target + " [label=0]"); - } - atomic = s.indexOf("atomic,") != -1; - graphWriter.println(source + " -> " + target + - " [label=\"" + s.substring(s.indexOf('.')+1) + "\"" + - (atomic || previousAtomic ? emphasize : "") + "]"); - previousAtomic = atomic; - } - - try { statementReader.close(); } - catch (IOException e) { spd.fileError(".dbg"); } - graphWriter.println("}"); - graphWriter.close(); - - // Call dot to format dot file - if (!spd.format.equals("dot")) - spd.runProcess(spd.properties.getProperty("DOT") + - " -T" + spd.format + - " -o " + fn + "." + spd.format + " " + - fn + ".dot", null); - } - -} diff --git a/spinSpider/Read.java b/spinSpider/Read.java deleted file mode 100644 index 431fd3e..0000000 --- a/spinSpider/Read.java +++ /dev/null @@ -1,212 +0,0 @@ -/* Copyright 2006-10 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* - * Read the data files -*/ - -package spinSpider; -import java.io.*; -import java.util.Properties; - -class Read { - SpinSpider spd; - String fileName; - Properties properties; - - Read(SpinSpider s, String f, Properties p) { - spd = s; - fileName = f; - properties = p; - } - - // Read the state transitions output by -DCHECK and never claim - // Thanks to Gerard Holzmann for showing me how to do this. - void readCheckFile() { - BufferedReader checkReader = null; - String s = ""; // Read line to s - String[] tokens; // For tokenizing - // Stack of states traversed - int[] stack = new int[Config.MAX_STACK]; - int newState = 0; // State number in "New" - int depth = 0; // Stack depth - boolean needNew = false; // Need state information after "New" - int offset = 0; // Offset of variables after procs - - spd.progress("Reading -DCHECK file"); - try { - checkReader = new BufferedReader( - new FileReader(fileName + ".chk")); - } catch (IOException e) { spd.fileError(".chk"); } - - while (true) { - try { s = checkReader.readLine(); } - catch (IOException e) { spd.fileError(".chk"); } - if ((s == null) || s.indexOf("Spin Version") != -1) break; - - tokens = s.trim().split("\\s"); - // "New" indicates a new state - // Push on the stack - // Immediately thereafter the *spd* output will appear - if ((tokens.length > 2) && tokens[0].equals("New")) { - newState = Integer.parseInt(tokens[2]); - stack[depth] = newState; - needNew = true; - } - // "Down" for a program (not a claim) indicates a transition - // to the new state that was just pushed on the stack - else if ((tokens.length > 3) && (tokens[1].equals("Down"))) { - if (tokens[3].equals("program") && (newState > 0)) - spd.transitions.add( - new Transition(stack[depth-1], newState)); - depth++; - stack[depth] = stack[depth-1]; - } - // "Up" - pop the stack - else if ((tokens.length > 1) && tokens[1].equals("Up")) { - depth--; - } - // "Old" - just a transition, no need to push a new state - else if ((tokens.length > 2) && tokens[0].equals("Old")) { - newState = Integer.parseInt(tokens[2]); - spd.transitions.add( - new Transition(stack[depth], newState)); - } - // "Stack" - have never occurred - // When it does you'll have to figure out what to do! - else if ((tokens.length > 2) && tokens[0].equals("Stack")) { - // For now, I don't know why this is here..... - System.out.println("Stack line = " + s); - System.exit(3); - } - // "*spd*" - The data created by the never claim - else if (needNew && (tokens.length > 1) && - tokens[0].equals("*spd*")) { - // The first time, set the number of processes and variables - if (State.numProcs == 0) { - State.numProcs = Integer.parseInt(tokens[1]); - offset = State.numProcs + 3; - State.numVars = Integer.parseInt(tokens[offset-1]); - } - // Parse the pc values and the values of the variables - // and construct a new state - needNew = false; - int[] st = new int[State.numProcs]; - String[] vn = new String[State.numVars]; - String[] vr = new String[State.numVars]; - for (int proc = 0; proc < State.numProcs; proc++) - st[proc] = Integer.parseInt(tokens[proc + 2]); - for (int var = 0; var < State.numVars; var++) { - vn[var] = tokens[offset + 2*var]; - vr[var] = tokens[offset + 2*var + 1]; - } - - spd.states.add(new State(st, vn, vr)); - } - } - try { checkReader.close(); } - catch (IOException e) { spd.fileError(".chk"); } - } - - // Extract an int value that appears between "from" and "to" in "s" - private static int extract(String s, String from, String to) { - return - Integer.parseInt( - s.substring(s.indexOf(from)+from.length(), s.indexOf(to)) - .trim()); - } - - // Create statement database from -d file - void createStatements() { - BufferedReader statementReader = null; - String s = ""; - int proc = 0; // For detecting change of process - int countStatements = 0; // Count statements per process - spd.progress("Reading -d file"); - try { - statementReader = new BufferedReader( - new FileReader(fileName + ".d")); - } catch (IOException e) { spd.fileError(".d"); } - - while (true) { - try { s = statementReader.readLine(); } - catch (IOException e) { spd.fileError(".d"); } - if (s == null) { - if (spd.trailCode != 3) - spd.fileError(".d (the never claim may be missing)"); - break; - } - - // Start of never claim - terminate processing - else if (s.indexOf("claim never") != -1) { - spd.statementsPerProcess.add( - new Integer(countStatements)); - break; - } - - // Beginning of transitions of a process - store and reset count - else if (s.indexOf("proctype") != -1) { - if (proc != 0) - spd.statementsPerProcess.add( - new Integer(countStatements)); - countStatements = 0; - proc++; - } - - // Entry for each transition - else if (s.indexOf("-> state") != -1) { - countStatements++; - // For Spin 6 the format for the line number is different - int arrow = s.indexOf("=>"); - int lineNumber; - if (Integer.valueOf(properties.getProperty("VERSION")).intValue() >= 6) - lineNumber = s.lastIndexOf(':', arrow) + 1; - else - lineNumber = s.lastIndexOf("line ", arrow) + 5; - - spd.statements.add(new Statement( - proc-1, // process number - extract(s, "state", "-(tr"), // source state - extract(s, "-> state", "[id"), // target state - extract(s, "[id", "tp"), // id number for trail - s.indexOf("[A") != -1, // atomic for automata - // source line number - Integer.parseInt(s.substring(lineNumber, arrow-1)), - s.substring(arrow+2).trim())); // source statement - } - } - try { statementReader.close(); } - catch (IOException e) { spd.fileError(".d"); } - } - - // Read the trail file whose entries are - - // "sequence number : process number : transition id" - // Sequence number = -2 means there is a never claim - // In that case, ignore its transitions (process number 0) - void readTrail() { - BufferedReader trailReader = null; - boolean claim = false; - String s = ""; - spd.progress("Reading trail file"); - try { - trailReader = new BufferedReader( - new FileReader(fileName + ".pml.trail")); - } catch (IOException e) { spd.fileError(".pml.trail"); return; } - - while (true) { - try { s = trailReader.readLine(); } - catch (IOException e) { spd.fileError(".pml.tral"); } - if (s == null) break; - String[] t = s.split(":"); - if (t[0].startsWith("-2")) { - claim = true; - continue; - } - if ((t[0].charAt(0) == '-')) continue; - if (claim && (t[1].charAt(0) == '0')) continue; - Trail tr = new Trail(Integer.valueOf(t[2]).intValue()); - spd.trails.add(tr); - } - try { trailReader.close(); } - catch (IOException e) { spd.fileError(".pml.trail"); } - } - -} diff --git a/spinSpider/SetTrail.java b/spinSpider/SetTrail.java deleted file mode 100644 index 0a3ac06..0000000 --- a/spinSpider/SetTrail.java +++ /dev/null @@ -1,63 +0,0 @@ -/* Copyright 2006 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* - * Use the trail file to give attributes to states and transitions -*/ - -package spinSpider; -class SetTrail { - SpinSpider spd; - SetTrail(SpinSpider s) { spd = s; } - - // Traverse the state diagram according to the trail file - void setTrail() { - int i = 0; - if (spd.states.size() == 0) return; - - // Start from first state - spd.states.get(i).inTrail = true; - // For each line in the trail, find a statement with matching id - for (Trail tr : spd.trails) { - Statement st = null; - for (Statement stmt: spd.statements) - if (stmt.id == tr.id) { - st = stmt; - break; - } - // Set trail flag for the state obtained by taking - // this transition in the trail - i = findNewState(i, st); - spd.states.get(i).inTrail = true; - } - } - - // Starting from state "index", find where the state where - // statement "stmt" goes to - private int findNewState(int index, Statement stmt) { - boolean ok; - State currentState = spd.states.get(index); - for (State s: spd.states) { - ok = true; - // For each process, the location is the same, - // except for the process executed by this statement, - // in which case the new state is reached by the statement - for (int i = 0; i < s.s.length; i++) { - if (i == stmt.process) ok = ok && (s.s[i] == stmt.targetState); - if (i != stmt.process) ok = ok && (s.s[i] == currentState.s[i]); - } - - // Flag the transition - if (ok) { - boolean foundTransition = false; - for (Transition tr: spd.transitions) - if ((tr.head == index) && (tr.tail == spd.states.indexOf(s))) { - tr.inTrail = true; - foundTransition = true; - } - if (foundTransition) - return spd.states.indexOf(s); - else continue; - } - } - return 0; - } -} diff --git a/spinSpider/Write.java b/spinSpider/Write.java deleted file mode 100644 index 2a3a5c7..0000000 --- a/spinSpider/Write.java +++ /dev/null @@ -1,259 +0,0 @@ -/* Copyright 2005-7 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* - * Write the output in different formats -*/ - -package spinSpider; - -import java.io.*; - -public class Write { - SpinSpider spd; - Write(SpinSpider s, String f) { - spd = s; - } - - // Write the never claim from the number of processes and - // the names of the variables - boolean writeNeverClaim(int numProcs, String[] vars) { - PrintWriter neverWriter = null; - spd.progress("Writing never claim"); - if (vars.length == 0) { - spd.progress("No variables for never claim"); - return false; - } - try { - neverWriter = new PrintWriter(new FileWriter(spd.fileName + ".nvr")); - } catch (IOException e) { spd.fileError(".nvr"); } - - neverWriter.print("never {\n\tdo\n\t:: printf(\"*spd* " + numProcs); - for (int i = 0; i < numProcs; i++) - neverWriter.print(" %d"); - neverWriter.print(" " + vars.length); - for (int i = 0; i < vars.length; i++) - neverWriter.print(" " + vars[i] + " %d"); - neverWriter.print("\\n\",\n\t\t"); - for (int i = 0; i < numProcs; i++) - neverWriter.print("pc_value(" + i + "), "); - for (int i = 0; i < vars.length; i++) - neverWriter.print((i==0?"":", ") + vars[i]); - neverWriter.println(")\n\tod\n}"); - neverWriter.close(); - return true; - } - - // Write the graph in dot format - nodes and edges - // trailCode = 0 (no trail), 1 (emphasize trail), 2 (just trail) - void writeDotGraph() { - PrintWriter graphWriter = null; - String fn = spd.fileName + Config.names[spd.trailCode]; - String label; // Building the label in this string - int numStates = 0; // For printing a node number - String[] dotPrologue = - spd.dotSize == 0 ? Config.smallDotPrologue : Config.largeDotPrologue; - String dotTrail = - spd.trailStyle == 0 ? Config.dotTrailColor : Config.dotTrailBold; - - spd.progress("Writing dot file"); - try { - graphWriter = new PrintWriter(new FileWriter(fn + ".dot")); - } catch (IOException e) { spd.fileError(".dot"); } - - // Write dot prologue - graphWriter.println("digraph \"" + fn + "\"" + " {"); - for (int i = 0; i < dotPrologue.length; i++) - graphWriter.println(dotPrologue[i]); - - // Write states - for (State st : spd.states) { - label = (numStates++) + " [label=\""; - for (int proc = 0; proc < State.numProcs; proc++) - for (Statement t : spd.statements) - if ((t.process == proc) && - (t.sourceState == st.s[proc])) - label = label + t.line + ". " + t.source + "\\n"; - for (int var = 0; var < State.numVars; var++) - label = label + " " + st.v[var]; - graphWriter.print(label+ "\""); - if ((spd.trailCode == 1) && st.inTrail) - graphWriter.print(dotTrail); - if ((spd.trailCode == 2) && !st.inTrail) - graphWriter.print(" style = invis "); - graphWriter.println("];"); - } - - // Write transitions - for (Transition t : spd.transitions) { - graphWriter.print(t.head + " -> " + t.tail); - if ((spd.trailCode == 1) && t.inTrail) - graphWriter.print(" [" + dotTrail + "]"); - if ((spd.trailCode == 2) && !t.inTrail) - graphWriter.print(" [ style = invis ]"); - graphWriter.println(";"); - } - graphWriter.println("}"); - graphWriter.close(); - if ((spd.trailCode != 3) && !spd.format.equals("dot")) - spd.runProcess(spd.properties.getProperty("DOT") + - " -T" + spd.format + - " -o " + fn + "." + spd.format + " " + - fn + ".dot", null); - } - - // Write the graph in fsm format - // This format is used by tools developed at the - // Eindhoven University of Technology - void writeFSMGraph() { - int offset; - PrintWriter graphWriter = null; - spd.progress("Writing fsm file"); - try { - graphWriter = new PrintWriter(new FileWriter(spd.fileName + ".fsm")); - } catch (IOException e) { spd.fileError(".fsm"); } - - // If the program terminates there is an end statement - // that is not a "source" in the -d file - // Add dummy statements at the end of the "statements" data structure - // spp1 is the original statementsPerProcess - // spp2 is statementsPerProcess with added dummy statements - int[] spp1 = new int[spd.statementsPerProcess.size()]; - int[] spp2 = new int[spd.statementsPerProcess.size()]; - for (int i = 0; i < spp1.length; i++) { - spp1[i] = spd.statementsPerProcess.get(i).intValue(); - spp2[i] = spp1[i]; - } - boolean[] endStates = new boolean[State.numProcs]; - for (int i = 0; i < spd.statements.size(); i++) { - Statement st = spd.statements.get(i); - if ( (st.targetState == 0) && (!endStates[st.process])) { - spd.statements.add(new Statement(st.process, 0, 0, 0, false, 0, "")); - spp2[st.process]++; - endStates[st.process] = true; - } - } - - // Compute fan in and fan out of each node - int[] fanIn = new int[spd.states.size()]; - int[] fanOut = new int[spd.states.size()]; - for (int i = 0; i < spd.transitions.size(); i++) { - fanIn[spd.transitions.get(i).tail]++; - fanOut[spd.transitions.get(i).head]++; - } - // Compute the maximum fan in and fan out in the diagram - int maxFanIn = 0, maxFanOut = 0; - for (int i = 0; i < spd.states.size(); i++) { - if (fanIn[i] > maxFanIn) maxFanIn = fanIn[i]; - if (fanOut[i] > maxFanOut) maxFanOut = fanOut[i]; - } - maxFanIn++; - maxFanOut++; - - // Processes: - // "p" + number of process + "(" + statements per process + ")" - // + "String" + list of statements - offset = 0; - for (int proc = 0; proc < State.numProcs; proc++) { - graphWriter.print("p" + (proc+1) + - "(" + spp2[proc] + ") String"); - for (int stmt = 0; stmt < spp1[proc]; stmt++) { - Statement stm = spd.statements.get(offset + stmt); - graphWriter.print(" \"" + stm.line + "," + stm.source + "\""); - } - offset = offset + spp1[proc]; - if (spp2[proc] > spp1[proc]) - graphWriter.print(" \" end state \""); - graphWriter.println(); - } - - // Variables: - // name of variable + "(" + number of values + ")" - // + "Nat" + list of values - for (int var = 0; var < State.numVars; var++) { - int max = 0; - for (State st : spd.states) { - int val = Integer.parseInt(st.v[var]); - if (val > max) max = val; - } - graphWriter.print(spd.states.get(0).vname[var] + "(" + (max+1) + ") Nat"); - for (int i = 0; i <= max; i++) - graphWriter.print(" \"" + i + "\""); - graphWriter.println(); - } - - // Fan in, fan out, node nr - graphWriter.print("fan_in(" + maxFanIn + ") Nat"); - for (int i = 0; i < maxFanIn; i++) - graphWriter.print(" \"" + i + "\""); - graphWriter.println(); - graphWriter.print("fan_out(" + maxFanOut + ") Nat"); - for (int i = 0; i < maxFanOut; i++) - graphWriter.print(" \"" + i + "\""); - graphWriter.println(); - graphWriter.println("node_nr(0)"); - graphWriter.println("---"); - - // States: - // Process location counters (relative to lists above!) - // Values of variables - // Fan-in and fan-out - int stateCount = 0; - for (State st : spd.states) { - offset = 0; - for (int proc = 0; proc < State.numProcs; proc++) { - boolean found = false; - for (int i = 0; i < spp1[proc]; i++) - if (spd.statements.get(offset + i).sourceState == st.s[proc]) { - graphWriter.print(i + " "); - found = true; - break; - } - if (!found) { - graphWriter.print((spp2[proc]-1) + " "); - } - offset = offset + spp1[proc]; - } - for (int var = 0; var < State.numVars; var++) - graphWriter.print(st.v[var] + " "); - graphWriter.print(fanIn[stateCount] + " " + - fanOut[stateCount] + " " + (stateCount+1)); - stateCount++; - graphWriter.println(); - } - graphWriter.println("---"); - - // Transitions - for (Transition t : spd.transitions) - graphWriter.println((t.head+1) + " " + (t.tail+1)); - graphWriter.close(); - } - - // Write debug file using toString defined in each class - void writeDebug() { - PrintWriter debugWriter = null; - spd.progress("Writing debug file"); - try { - debugWriter = new PrintWriter( - new FileWriter(spd.fileName + ".dbg")); - } catch (IOException e) { spd.fileError(".dbg"); } - - debugWriter.println("States"); - int n = 0; - for (State s: spd.states) - debugWriter.println((n++) + ". " + s); - - debugWriter.println("\nTransitions"); - for (Transition t: spd.transitions) - debugWriter.println(t); - - debugWriter.println("\nStatements from -d file"); - for (Statement st: spd.statements) - debugWriter.println(st); - - if (spd.trailCode > 0) { - debugWriter.println("\nTrail"); - for (Trail tr: spd.trails) - debugWriter.println(tr); - } - debugWriter.close(); - } -} diff --git a/src/main/java/com/spinroot/filterSpin/Config.java b/src/main/java/com/spinroot/filterSpin/Config.java new file mode 100644 index 0000000..636d438 --- /dev/null +++ b/src/main/java/com/spinroot/filterSpin/Config.java @@ -0,0 +1,42 @@ +// Copyright 2008 by Mordechai (Moti) Ben-Ari. +/** + * Local configuration class for standalone FilterSpin + */ +package com.spinroot.filterSpin; + +public class Config { + static final String VERSION = "0.1"; + static final String CONFIG_FILE = "config.cfg"; + static final String SEPARATOR = "#"; + static final String USAGE = + "FilterSpin Version " + VERSION + + " Copyright 2008 (GNU GPL) by Moti Ben-Ari.\n" + + "Usage java com.spinroot.filterSpin.FilterSpin [arguments] file\n" + + " file File with Spin output\n" + + " -v string Variables to exclude\n" + + " -s string Statements to exclude\n" + + " string may be file name or list of identifiers with '/'"; + + static void setDefaultProperties( + java.util.Properties properties) { + properties.put("PROCESS_WIDTH", Integer.toString(7)); + properties.put("STATEMENT_WIDTH", Integer.toString(18)); + properties.put("VARIABLE_WIDTH", Integer.toString(10)); + properties.put("LINES_PER_TITLE", Integer.toString(20)); + properties.put("PROCESS_TITLE", "Process "); + properties.put("STATEMENT_TITLE", "Statement "); + properties.put("MSC", Boolean.toString(false)); + } + + /** + * Set the default properties and then try to read configuration file + */ + static void init(java.util.Properties properties) { + setDefaultProperties(properties); + try { + properties.load(new java.io.FileInputStream(CONFIG_FILE)); + } catch (java.io.IOException e1) { + System.err.println("Cannot open configuration file; using defaults"); + } + } +} diff --git a/src/main/java/com/spinroot/filterSpin/Filter.java b/src/main/java/com/spinroot/filterSpin/Filter.java new file mode 100644 index 0000000..3e1c172 --- /dev/null +++ b/src/main/java/com/spinroot/filterSpin/Filter.java @@ -0,0 +1,245 @@ +// Copyright 2004-10 by Mordechai (Moti) Ben-Ari. See copyright.txt. +/** + * Filter Spin output. + * Display a table: process, statement, variables. + */ +package com.spinroot.filterSpin; + +import java.util.*; + +public class Filter { + private static String processTitle; + private static String statementTitle; + private static int processWidth; + private static int variableWidth; + private static int statementWidth; + private static int linesPerTitle; + private static boolean msc; + private static boolean newversion; // Spin version >= 6 + // Properties and copies of the data from the properties + private Properties properties; + private String title; // Title string + private int lines; // Line counter to redisplay title + + // Map from variable names to values + private Map variables = new TreeMap<>(); + + // Excluded variable and statements + private List excludedVar = new ArrayList<>(); + private List excludedState = new ArrayList<>(); + + /** + * Initialize variables and local copies of properties + */ + public void init(Properties properties) { + variables.clear(); + title = ""; + lines = -1; + this.properties = properties; + processTitle = properties.getProperty("PROCESS_TITLE"); + statementTitle = properties.getProperty("STATEMENT_TITLE"); + processWidth = Integer.valueOf(properties.getProperty("PROCESS_WIDTH")); + variableWidth = Integer.valueOf(properties.getProperty("VARIABLE_WIDTH")); + statementWidth = Integer.valueOf(properties.getProperty("STATEMENT_WIDTH")); + linesPerTitle = Integer.valueOf(properties.getProperty("LINES_PER_TITLE")); + msc = Boolean.valueOf(properties.getProperty("MSC")); + newversion = Integer.valueOf(properties.getProperty("VERSION")) >= 6; + } + + // Parse string to initialize excluded arrays + public void setExcluded(String s, boolean exVar) { + List excluded = exVar ? excludedVar : excludedState; + // Replace whitespace by separator + s = s.replaceAll("\\s+", Config.SEPARATOR) + Config.SEPARATOR; + excluded.clear(); + do { + int nl = s.indexOf(Config.SEPARATOR); + if (nl == -1) break; + if (!s.substring(0, nl).equals("")) + excluded.add(s.substring(0, nl)); + s = s.substring(nl + 1); + } while (true); + } + + /** + * Check if name is excluded variable (exVar=true) or statement (exVar=false) + * For each excluded string S; + * If variable name includes S, do not display, + * but if some +T in file is in name, display anyway. + */ + private boolean checkExcluded(String name, boolean exVar) { + List excluded = exVar ? excludedVar : excludedState; + for (int i = 0; i < excluded.size(); i++) + if ((excluded.get(i).charAt(0) != '+') && + (name.indexOf(excluded.get(i)) != -1)) { + boolean included = false; + for (int j = 0; j < excluded.size(); j++) + included = included || + ((excluded.get(j).charAt(0) == '+') && + (name.indexOf(excluded.get(j).substring(1)) != -1)); + return !included; + } + return false; + } + + // Filter string s and return new string or "" to ignore + public String filter(String s) { + try { + // Variables and queues start with double tab + if (s.startsWith("\t\t")) + return filterVariable(s); + + // Filter statements + else if ((s.indexOf("proc") != -1) && (s.indexOf("[") != -1)) + return filterStatement(s); + + // Display some messages unmodified + else if ((s.startsWith("pan:")) || + (s.startsWith("spin:")) || + (s.startsWith("tl_spin:")) || + (s.startsWith("Error:")) || + (s.startsWith("error:"))) + return s + "\n"; + else if (s.indexOf("<<<<<") != -1) + return s + "\n"; + + // Display choices that have no proc and line number + else if (s.indexOf("choice") != -1) + return s.substring(s.indexOf("choice")) + "\n"; + + // Display error count with bullets to emphasize + else if (s.indexOf("errors:") != -1) + return + s.substring(0, s.indexOf("errors:")) + "\u2022\u2022\u2022 " + + s.substring(s.indexOf("errors:")) + " \u2022\u2022\u2022\n"; + + // Display MSC lines (without MSC:) if msc is true + else if (msc && s.trim().startsWith("MSC:")) + return s.substring(s.indexOf("MSC:") + 5) + "\n"; + + // Display printf lines if msc is false + else if (!msc && !s.equals("")) + return s + "\n"; + else + return ""; + } catch (Exception e) { + System.err.println("\n + Error in filter for:\n" + s + "\n"); + e.printStackTrace(); + return ""; + } + } + + // Filter variables (including queues) + private String filterVariable(String s) { + String varName, varValue; + if (s.startsWith("\t\tqueue")) { + varName = s.substring(s.indexOf('(') + 1, s.indexOf(')')); + varValue = s.substring(s.indexOf(':') + 1).trim(); + } else { + varName = s.substring(2, s.indexOf('=') - 1); + varValue = s.substring(s.indexOf('=') + 1).trim(); + } + if (checkExcluded(varName, true)) return ""; + // Construct new title if new variables encountered + boolean newTitle = !variables.containsKey(varName); + variables.put(varName, varValue); + if (newTitle) { + title = formatItem(processTitle, processWidth) + " " + + formatItem(statementTitle, statementWidth) + " " + + collectionToString(variables.keySet()) + "\n"; + lines = -1; + } + return ""; + } + + // Filter statements + private String filterStatement(String s) { + String u = ""; + int procIndex = s.indexOf("proc") + 4; // After "proc" + // Get process name + String proc = + s.substring(procIndex, s.indexOf(")") + 1).trim(); + proc = proc.substring(0, proc.indexOf("(")) + + strip(proc.substring(proc.indexOf("("))); + + // Get line number and statement name + String statement = "", line = ""; + if (s.indexOf('[') != -1) { + if (newversion) { + // Spin 6 has "filename:#" + // Skip over initial ":" and start at file name + int colonIndex = s.indexOf(":", procIndex); + line = formatItem( + s.substring(colonIndex + 1, s.indexOf(" ", colonIndex)).trim(), 3); + } else + // Earlier versions had "line #" + line = formatItem( + s.substring(s.indexOf("line") + 4, s.indexOf("\"")).trim(), 3); + statement = + strip(s.substring(s.indexOf('[') + 1, s.lastIndexOf(']'))); + statement = line + " " + statement; + } + + if (checkExcluded(statement, false)) return ""; + + // For choice, display just process and statement + if (s.indexOf("choice") != -1) + u = s.substring(s.indexOf("choice"), s.indexOf(':') + 2) + + proc + " " + statement + "\n"; + // Display table line (unless goto/else/break) + else if ((statement.indexOf("goto") == -1) && + !statement.equals("else") && + !statement.equals("break")) { + u = formatItem(proc, processWidth) + " " + + formatItem(statement, statementWidth) + " " + + collectionToString(variables.values()) + "\n"; + + // Display title if needed + lines = (lines + 1) % linesPerTitle; + if (lines == 0) u = title + u; + } + return u; + } + + // Strip balanced parentheses + private String strip(String s) { + while ((s.charAt(0) == '(') && (s.charAt(s.length() - 1) == ')')) + s = s.substring(1, s.length() - 1); + return s; + } + + /** + * Format a variable name or value s into a field of length len + * If item is too long, shorten it + * But, for array variables, shorten the name, not the index + * If item is too short, pad it + */ + private String formatItem(String s, int len) { + if (s.length() > len) { + if (s.indexOf("[") != -1) { + String subscript = + s.substring(s.indexOf("["), s.lastIndexOf("]") + 1); + if (subscript.length() < len) + return s.substring(0, len - subscript.length()) + subscript; + else + return s.substring(0, len); + } else + return s.substring(0, len); + } else if (s.length() < len) + return (s + " ").substring(0, len); + else + return s; + } + + /** + * Transform a collection of variables to a string, + * calling formatItem for each element + */ + private String collectionToString(Collection c) { + String s = ""; + Iterator it = c.iterator(); + while (it.hasNext()) + s = s + formatItem(it.next(), variableWidth) + " "; + return s; + } +} diff --git a/src/main/java/com/spinroot/filterSpin/FilterSpin.java b/src/main/java/com/spinroot/filterSpin/FilterSpin.java new file mode 100644 index 0000000..702d167 --- /dev/null +++ b/src/main/java/com/spinroot/filterSpin/FilterSpin.java @@ -0,0 +1,91 @@ +// Copyright 2008 by Mordechai (Moti) Ben-Ari. See copyright.txt. +/** + * Class with main method for standalone FilterSpin + */ +package com.spinroot.filterSpin; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; + +class FilterSpin { + /** + * Read the files of excluded variables/statements and + * return as a single string + */ + private static String readFile(File fc) { + BufferedReader textReader = null; + String s = ""; + try { + textReader = new BufferedReader(new FileReader(fc)); + String line; + while (true) { + line = textReader.readLine(); + if (line == null) break; + else s = s + line + '\n'; + } + textReader.close(); + return s; + } catch (IOException e) { + error("File error " + fc); + return ""; + } + } + + /** + * Read the Spin raw output and call the filter for each line + */ + private static void filterFile(File fc, Filter filter) { + BufferedReader textReader = null; + try { + textReader = new BufferedReader(new FileReader(fc)); + String line; + while (true) { + line = textReader.readLine(); + if (line == null) break; + line = filter.filter(line); + if (!line.equals("")) System.out.print(line); + } + textReader.close(); + } catch (IOException e) { + error("File error " + fc); + System.exit(1); + } + } + + static void error(String s) { + System.err.println(s); + System.exit(1); + } + + public static void main(String[] args) { + if (args.length == 0) error(Config.USAGE); + + // Last argument is file name + File file = new File(args[args.length - 1]); + + // Search for excluded file names or strings + String exc = Config.SEPARATOR, exs = Config.SEPARATOR; + for (int i = 0; i < args.length - 1; i++) + if (args[i].equals("-v")) exc = args[i + 1]; + else if (args[i].equals("-s")) exs = args[i + 1]; + + // Create filter and property objects and initialize + Filter filter = new Filter(); + java.util.Properties properties = new java.util.Properties(); + Config.init(properties); + filter.init(properties); + + // Read excluded files (if any) and set excluded data structures + if (exc.indexOf(Config.SEPARATOR) == -1) + exc = readFile(new File(exc)); + filter.setExcluded(exc, true); + if (exs.indexOf(Config.SEPARATOR) == -1) + exs = readFile(new File(exs)); + filter.setExcluded(exs, false); + + // Filter the raw Spin data + filterFile(file, filter); + } +} diff --git a/src/main/java/com/spinroot/jspin/Config.java b/src/main/java/com/spinroot/jspin/Config.java new file mode 100644 index 0000000..7e0aa1f --- /dev/null +++ b/src/main/java/com/spinroot/jspin/Config.java @@ -0,0 +1,397 @@ +/* Copyright 2003-10 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +package com.spinroot.jspin; + +import java.awt.event.KeyEvent; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +public class Config { + public static final char sep = java.io.File.separatorChar; // shortcut + // Strings + static final String SOFTWARE_NAME = "jSpin Version 5.0"; + static final String JAVA_VERSION = "1.8"; + static final String CONFIG_FILE_NAME = "config.cfg"; + static final String SPIDER_TITLE = "SpinSpider"; + static final String OPTIONS_TITLE = "Display"; + static final String SELECT = "Select a statement"; + static final String OPEN_FILE = "Open a Promela file\n"; + static final String processTitle = "Process "; + static final String statementTitle = "Statement "; + // Component names and mnemonics + static final String File = "File"; + static final int FileMN = KeyEvent.VK_F; + static final String New = "New"; + static final int NewMN = KeyEvent.VK_N; + static final String Open = "Open"; + static final int OpenMN = KeyEvent.VK_O; + static final String Save = "Save"; + static final int SaveMN = KeyEvent.VK_S; + static final String SaveAs = "Save as"; + static final int SaveAsMN = KeyEvent.VK_A; + static final String Switch = "Switch file"; + static final int SwitchMN = KeyEvent.VK_F; + static final String Exit = "Exit"; + static final int ExitMN = KeyEvent.VK_X; + static final String Editor = "Edit"; + static final int EditorMN = KeyEvent.VK_E; + static final String Undo = "Undo"; + static final int UndoMN = KeyEvent.VK_U; + static final String Redo = "Redo"; + static final int RedoMN = KeyEvent.VK_R; + static final String Copy = "Copy"; + static final int CopyMN = KeyEvent.VK_C; + static final String Cut = "Cut"; + static final int CutMN = KeyEvent.VK_T; + static final String Paste = "Paste"; + static final int PasteMN = KeyEvent.VK_P; + static final String Find = "Find"; + static final int FindMN = KeyEvent.VK_F; + static final String FindAgain = "Find again"; + static final int FindAgainMN = KeyEvent.VK_A; + static final String Spin = "Spin"; + static final int SpinMN = KeyEvent.VK_S; + static final String Check = "Check"; + static final int CheckMN = KeyEvent.VK_K; + static final String Random = "Random"; + static final int RandomMN = KeyEvent.VK_R; + static final String Inter = "Interactive"; + static final int InterMN = KeyEvent.VK_I; + static final String Verify = "Verify"; + static final int VerifyMN = KeyEvent.VK_V; + static final String Trail = "Guided"; + static final int TrailMN = KeyEvent.VK_G; + static final String Stop = "Stop"; + static final int StopMN = KeyEvent.VK_P; + static final String Options = "Options"; + static final int OptionsMN = KeyEvent.VK_N; + static final String Common = "Common"; + static final int CommonMN = KeyEvent.VK_C; + static final String OptionsC = "C compiler"; + static final int OptionsCMN = KeyEvent.VK_C; + static final String OptionsPan = "Pan"; + static final int OptionsPanMN = KeyEvent.VK_A; + static final String Default = "Default"; + static final int DefaultMN = KeyEvent.VK_D; + static final String SaveInstall = "Save install"; + static final int SaveInstallMN = KeyEvent.VK_L; + static final String SaveCurrent = "Save current"; + static final int SaveCurrentMN = KeyEvent.VK_S; + static final String Settings = "Settings"; + static final int SettingsMN = KeyEvent.VK_G; + static final String MaxSteps = "Max steps"; + static final int MaxStepsMN = KeyEvent.VK_M; + static final String MaxDepth = "Max depth"; + static final int MaxDepthMN = KeyEvent.VK_D; + static final String Seed = "Seed"; + static final int SeedMN = KeyEvent.VK_S; + static final String Negate = "Negate LTL"; + static final int NegateMN = KeyEvent.VK_L; + static final String StWidth = "Statement width"; + static final int StWidthMN = KeyEvent.VK_S; + static final String VarWidth = "Variable width"; + static final int VarWidthMN = KeyEvent.VK_V; + static final String ExcludedV = "Exclude variables"; + static final int ExcludedVMN = KeyEvent.VK_E; + static final String ExcludedS = "Exclude statements"; + static final int ExcludedSMN = KeyEvent.VK_X; + static final String Fair = "Weak fairness"; + static final int FairMN = KeyEvent.VK_W; + static final String Safety = "Safety"; + static final int SafetyMN = KeyEvent.VK_Y; + static final String Acceptance = "Acceptance"; + static final int AcceptanceMN = KeyEvent.VK_C; + static final String NonProgress = "Non-progress"; + static final int NonProgressMN = KeyEvent.VK_N; + static final String Output = "Output"; + static final int OutputMN = KeyEvent.VK_U; + static final String SaveSpin = "Save output"; + static final int SaveSpinMN = KeyEvent.VK_V; + static final String Raw = "Raw output"; + static final int RawMN = KeyEvent.VK_R; + static final String DisplayRaw = "Display raw"; + static final int DisplayRawMN = KeyEvent.VK_D; + static final String Spider = "SpinSpider"; + static final int SpiderMN = KeyEvent.VK_D; + static final String SpiderDisplay = "Display debug"; + static final int SpiderDisplayMN = KeyEvent.VK_L; + static final String Run = "Run"; + static final int RunMN = KeyEvent.VK_R; + static final String Help = "Help"; + static final int HelpMN = KeyEvent.VK_H; + static final String About = "About"; + static final int AboutMN = KeyEvent.VK_A; + static final String Max = "Maximize"; + static final int MaxMN = KeyEvent.VK_M; + static final String LTLConvert = "Convert"; + static final int LTLConvertMN = KeyEvent.VK_C; + static final String LTLFormula = " LTL formula "; + static final String LTLTranslate = "Translate"; + static final int LTLTranslateMN = KeyEvent.VK_L; + static final String LTLClear = "Clear"; + static final int LTLClearMN = KeyEvent.VK_A; + static final String LTLLoad = "Load"; + static final int LTLLoadMN = KeyEvent.VK_O; + static final String LTLName = "LTL name"; + static final int LTLNameMN = KeyEvent.VK_A; // For toolbar + static final int LTLName1MN = KeyEvent.VK_N; // For menu + static final int LTL_COLUMNS = 50; + // Common options + static final String OK = "OK"; + static final int OKMN = KeyEvent.VK_O; + static final String Cancel = "Cancel"; + static final String Statements = "Statements"; + static final int StatementsMN = KeyEvent.VK_S; + static final String Globals = "Globals"; + static final int GlobalsMN = KeyEvent.VK_G; + static final String Locals = "Locals"; + static final int LocalsMN = KeyEvent.VK_L; + static final String Sent = "Sent"; + static final int SentMN = KeyEvent.VK_T; + static final String Received = "Received"; + static final int ReceivedMN = KeyEvent.VK_R; + static final String ClearAll = "Clear all"; + static final int ClearAllMN = KeyEvent.VK_C; + static final String SetAll = "Set all"; + static final int SetAllMN = KeyEvent.VK_A; + // SpinSpider options + static final String NoTrail = "No trail"; + static final int NoTrailMN = KeyEvent.VK_T; + static final String EmphTrail = "Emphasize trail"; + static final int EmphTrailMN = KeyEvent.VK_E; + static final String OnlyTrail = "Only trail"; + static final int OnlyTrailMN = KeyEvent.VK_O; + static final String Automata = "Automata"; + static final int AutomataMN = KeyEvent.VK_A; + static final String Debug = "Debug"; + static final int DebugMN = KeyEvent.VK_D; + static final String DotSize = "Dot size"; + static final String DotSmall = "Small"; + static final int DotSmallMN = KeyEvent.VK_M; + static final String DotLarge = "Large"; + static final int DotLargeMN = KeyEvent.VK_L; + static final String TrailStyle = "Trail style"; + static final String TrailColor = "Color"; + static final int TrailColorMN = KeyEvent.VK_C; + static final String TrailBold = "Bold"; + static final int TrailBoldMN = KeyEvent.VK_B; + static final String Processes = "Processes"; + static final int MAX_PROCESS = 5; + static final String Variables = "Variables"; + static final String Format = "Format"; + static final String DOT = "dot"; + static final String PNG = "png"; + static final String PS = "ps"; + static final String FSM = "fsm"; + // Accelerators + // Select All by default "control A" + static final String SwitchAC = "control B"; + static final String CopyAC = "control C"; + static final String SpiderAC = "control D"; + static final String VarWidthAC = "control E"; + static final String FindAC = "control F"; + static final String FindAgainAC = "control G"; + // Backspace by default "control H" + static final String CommonAC = "control I"; + static final String ExcludedSAC = "control J"; + static final String AcceptanceAC = "control L"; + static final String MaxStepsAC = "control M"; + static final String NonProgressAC = "control N"; + static final String OpenAC = "control O"; + static final String ExitAC = "control Q"; + static final String DisplayRawAC = "control R"; + static final String SaveAC = "control S"; + static final String SafetyAC = "control T"; + static final String ExcludedVAC = "control U"; + static final String PasteAC = "control V"; + static final String FairAC = "control W"; + static final String CutAC = "control X"; + static final String RedoAC = "control Y"; + static final String UndoAC = "control Z"; + // Where to find configuration file + public static String installationDirectory; + public static String currentDirectory; + public static String helpFileName; + public static String aboutFileName; + static Properties properties = new Properties(); + // Dummy accelerators + static String + AboutAC, CheckAC, DefaultAC, HelpAC, InterAC, LTLClearAC, + LTLLoadAC, LTLTranslateAC, LTLNameAC, MaxAC, MaxDepthAC, SeedAC, + NegateAC, NewAC, OptionsCAC, OptionsInterAC, OptionsPanAC, + OptionsRandomAC, OptionsSaveCurrentAC, OptionsSaveInstallAC, + OptionsTrailAC, RandomAC, SaveAsAC, SaveSpinAC, + SpiderDisplayAC, StopAC, StWidthAC, TrailAC, VerifyAC, RawAC; + + static void setDefaultProperties() { + // Spin version: format changed with Spin 6 + properties.put("VERSION", "6"); + + // Directories and file names + properties.put("SOURCE_DIRECTORY", "jspin-examples"); + properties.put("C_COMPILER", "clang"); + properties.put("SPIN", "/home/victor/Spin/spin"); + properties.put("PAN", "pan"); + properties.put("DOT", "dot"); + properties.put("HELP_FILE_NAME", "txt" + sep + "help.txt"); + properties.put("ABOUT_FILE_NAME", "txt" + sep + "copyright.txt"); + + // Options for executing Spin + properties.put("SINGLE_QUOTE", Boolean.toString(false)); + properties.put("COMMON_OPTIONS", "-g -l -p -r -s"); + // Check options changed for version 6 (for now) + // properties.put("CHECK_OPTIONS", "-a -v"); + properties.put("CHECK_OPTIONS", "-a"); + properties.put("RANDOM_OPTIONS", "-X"); + properties.put("INTERACTIVE_OPTIONS", "-i -X"); + properties.put("VERIFY_OPTIONS", "-a"); + properties.put("C_COMPILER_OPTIONS", "-o pan pan.c"); + properties.put("PAN_OPTIONS", "-X"); + properties.put("TRAIL_OPTIONS", "-t -X"); + properties.put("TRANSLATE_OPTIONS", "-f"); + + // Settings + properties.put("MAX_STEPS", "250"); + properties.put("MAX_DEPTH", "2000"); + properties.put("SEED", "0"); + properties.put("NEGATE_LTL", Boolean.toString(true)); + properties.put("FAIRNESS", Boolean.toString(true)); + properties.put("VERIFY_MODE", Safety); + properties.put("RAW", Boolean.toString(false)); + properties.put("PROCESS_WIDTH", Integer.toString(7)); + properties.put("STATEMENT_WIDTH", Integer.toString(18)); + properties.put("VARIABLE_WIDTH", Integer.toString(10)); + properties.put("LINES_PER_TITLE", Integer.toString(20)); + + // Size of main frame + properties.put("WIDTH", Integer.toString(1000)); + properties.put("HEIGHT", Integer.toString(700)); + + // Select dialog + properties.put("SELECT_BUTTON", Integer.toString(220)); + properties.put("SELECT_HEIGHT", Integer.toString(70)); + properties.put("SELECT_MENU", Integer.toString(5)); + properties.put("UNEXECUTABLE", Boolean.toString(false)); + + // Location of dividers in JSplitPanes: Left-right and top-bottom + properties.put("LR_DIVIDER", Integer.toString(400)); + properties.put("TB_DIVIDER", Integer.toString(500)); + properties.put("MIN_DIVIDER", Integer.toString(50)); + + // Font + properties.put("FONT_FAMILY", "Lucida Sans Typewriter"); + properties.put("FONT_STYLE", Integer.toString(java.awt.Font.PLAIN)); + properties.put("FONT_SIZE", Integer.toString(14)); + + // Tab size in editor + properties.put("TAB_SIZE", Integer.toString(4)); + + // Display of Spin output + properties.put("WRAP", Boolean.toString(true)); + properties.put("MSC", Boolean.toString(false)); + properties.put("PROCESS_TITLE", "Process "); + properties.put("STATEMENT_TITLE", "Statement "); + + // Delay while waiting for user input + properties.put("POLLING_DELAY", Integer.toString(200)); + } + + // Initialize configuration file + static public void init() { + setDefaultProperties(); + // Try to open config file in current directory; + // if not there, try installation directory; + // if not there, write default file + currentDirectory = System.getProperty("user.dir"); + installationDirectory = System.getProperty("java.class.path"); + int lastSeparator = installationDirectory.lastIndexOf(java.io.File.separator); + if (lastSeparator == -1) + installationDirectory = "."; + else + installationDirectory = installationDirectory.substring(0, lastSeparator); +// System.err.println(currentDirectory + java.io.File.separator + CONFIG_FILE_NAME); +// System.err.println(installationDirectory + java.io.File.separator + CONFIG_FILE_NAME); + FileInputStream in = null; + try { + in = new FileInputStream( + currentDirectory + java.io.File.separator + CONFIG_FILE_NAME); + System.err.println("Read configuration file from current directory"); + } catch (FileNotFoundException e1) { + try { + in = new FileInputStream( + installationDirectory + java.io.File.separator + CONFIG_FILE_NAME); + System.err.println("Read configuration file from installation directory"); + } catch (FileNotFoundException e4) { + System.err.println( + "Cannot open configuration file, creating new file"); + try { + saveFile(false); + in = new FileInputStream(installationDirectory + java.io.File.separator + CONFIG_FILE_NAME); + } catch (IOException e2) { + System.err.println("Cannot write configuration file"); + return; + } + } + } + try { + properties.load(in); + in.close(); + } catch (IOException e3) { + System.err.println("Cannot read configuration file"); + } + helpFileName = installationDirectory + java.io.File.separator + + properties.getProperty("HELP_FILE_NAME"); + aboutFileName = installationDirectory + java.io.File.separator + + properties.getProperty("ABOUT_FILE_NAME"); + } + + // Save configuration file + static void saveFile(boolean current) { + try { + FileOutputStream out = + new FileOutputStream( + (current ? currentDirectory : installationDirectory) + + java.io.File.separator + CONFIG_FILE_NAME); + properties.store(out, "jSpin configuration file"); + out.close(); + System.err.println("Saved jSpin configuration file config.cfg"); + } catch (IOException e2) { + System.err.println("Cannot write configuration file"); + } + } + + public static String getSpin() { + return Config.getStringProperty("SPIN"); + } + + // Interface to get/set propertyies of various types + public static String getStringProperty(String s) { + return properties.getProperty(s); + } + + static void setStringProperty(String s, String newValue) { + properties.setProperty(s, newValue); + } + + public static boolean getBooleanProperty(String s) { + return Boolean.valueOf(properties.getProperty(s)); + } + + static void setBooleanProperty(String s, boolean newValue) { + properties.setProperty(s, Boolean.toString(newValue)); + } + + public static int getIntProperty(String s) { + return Integer.valueOf(properties.getProperty(s)); + } + + static void setIntProperty(String s, int newValue) { + properties.setProperty(s, Integer.toString(newValue)); + } + + public static Properties getProperties() { + return properties; + } +} diff --git a/src/main/java/com/spinroot/jspin/DisplayImage.java b/src/main/java/com/spinroot/jspin/DisplayImage.java new file mode 100644 index 0000000..55682a6 --- /dev/null +++ b/src/main/java/com/spinroot/jspin/DisplayImage.java @@ -0,0 +1,30 @@ +/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +// Class DisplayFile for Help, About, Display raw +package com.spinroot.jspin; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +class DisplayImage extends JFrame implements ActionListener { + DisplayImage(String file) { + ImagePanel image = new ImagePanel(file); + getContentPane().add(new JScrollPane(image)); + setDefaultCloseOperation( + javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + getRootPane().registerKeyboardAction(this, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + setTitle(file); + setSize((int) (0.8 * Config.getIntProperty("WIDTH")), + (int) (0.9 * Config.getIntProperty("HEIGHT"))); + setLocationRelativeTo(null); + setVisible(true); + } + + public void actionPerformed(ActionEvent e) { + dispose(); + } +} + diff --git a/src/main/java/com/spinroot/jspin/Editor.java b/src/main/java/com/spinroot/jspin/Editor.java new file mode 100644 index 0000000..ae4284b --- /dev/null +++ b/src/main/java/com/spinroot/jspin/Editor.java @@ -0,0 +1,411 @@ +/* Copyright 2003-7 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * Editor for Promela programs + */ + +package com.spinroot.jspin; + +import org.apache.commons.io.FileUtils; + +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.border.TitledBorder; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.datatransfer.*; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +class Editor implements ClipboardOwner, DocumentListener { + private static final Border border = BorderFactory.createMatteBorder(2, 0, 0, 0, Color.gray); + /** + * The file to be edited + */ + private File file; + /** + * Previous file to be edited + */ + private File lastFile; + /** + * The name of the file + */ + private String fileName; + /** + * The file name without its extension + */ + private String fileRoot; + /** + * The extension of the source file + */ + private String extension = ""; + /** + * The path to the file + */ + private String root; + /** + * LTL file name for this source file + */ + private String LTLFileName = ""; + /** + * Spin display output file name + */ + private String OUTFileName = ""; + /** + * File for excluded variable names + */ + private String EXCFileName = ""; + /** + * File for excluded statements + */ + private String EXSFileName = ""; + /** + * Property file name for this source file + */ + private String PRPFileName = ""; + /** + * Property file name without path + */ + private String PRPName; + /** + * The area for editing + */ + private JTextArea area; + /** + * The area for LTL formulas + */ + private JTextField LTLField; + /** + * The area for messages + */ + private JTextArea messageArea; + /** + * The string to search for + */ + private String findString; + /** + * The last location where it was found + */ + private int findLoc; + /** + * Was area modified? + */ + private boolean modified; + /** + * Was LTL field modified? + */ + private boolean LTLmodified; + /** + * Border - not modified + */ + private Border border1; + /** + * Border - modified + */ + private Border border2; + private Clipboard clipboard; + private LineNumbers lineNumbers; + /** + * For setting excluded variable names + */ + private com.spinroot.filterSpin.Filter filter; + + public Editor(JScrollPane jsp, JTextArea area, JTextArea m, JTextField l, + javax.swing.event.UndoableEditListener ud, com.spinroot.filterSpin.Filter filter) { + this.area = area; + LTLField = l; + LTLField.getDocument().addDocumentListener(this); + messageArea = m; + PRPName = ""; + clipboard = this.area.getToolkit().getSystemClipboard(); + lineNumbers = new LineNumbers(this.area); + jsp.setRowHeaderView(lineNumbers); + this.filter = filter; + } + + public File getFile() { + return file; + } + + public File getLastFile() { + return lastFile; + } + + public void setLastFile(File lastFile) { + this.lastFile = lastFile; + } + + public String getFileName() { + return fileName; + } + + public String getFileRoot() { + return fileRoot; + } + + public void setFileRoot(String fileRoot) { + this.fileRoot = fileRoot; + } + + public String getExtension() { + return extension; + } + + public String getRoot() { + return root; + } + + public String getLTLFileName() { + return LTLFileName; + } + + public String getOUTFileName() { + return OUTFileName; + } + + public String getEXCFileName() { + return EXCFileName; + } + + public String getEXSFileName() { + return EXSFileName; + } + + void focus(boolean start) { + area.requestFocusInWindow(); + if (start) + area.setCaretPosition(0); + } + + void caretToLine(int line) { + try { + area.requestFocusInWindow(); + area.setCaretPosition(area.getLineStartOffset(line - 1)); + } catch (Exception e) { + area.setCaretPosition(0); + } + } + + void cut() { + if (area.getSelectionStart() != area.getSelectionEnd()) { + String s = area.getSelectedText(); + StringSelection contents = new StringSelection(s); + clipboard.setContents(contents, this); + area.replaceRange(null, + area.getSelectionStart(), area.getSelectionEnd()); + } + } + + void copy() { + if (area.getSelectionStart() != area.getSelectionEnd()) { + String s = area.getSelectedText(); + StringSelection contents = new StringSelection(s); + clipboard.setContents(contents, this); + } + } + + void paste() { + Transferable content = clipboard.getContents(this); + if (content != null) { + try { + String s = (String) content.getTransferData( + DataFlavor.stringFlavor); + area.replaceRange(s, + area.getSelectionStart(), area.getSelectionEnd()); + } catch (Exception ex) { + System.err.println("Can't paste"); + } + } + } + + private void showArea(String title) { + String previousTitle = " / " + + ((lastFile == null) ? "-" : lastFile.getName()) + " "; + findString = null; + findLoc = 0; + modified = false; + border1 = BorderFactory.createTitledBorder( + border, " " + title + previousTitle, + TitledBorder.LEFT, TitledBorder.TOP); + border2 = BorderFactory.createTitledBorder( + border, " " + title + " * " + previousTitle, + TitledBorder.LEFT, TitledBorder.TOP); + area.setBorder(border1); + focus(true); + } + + void newFile() { + root = ""; + file = null; + fileName = ""; + fileRoot = ""; + LTLFileName = ""; + OUTFileName = ""; + EXCFileName = ""; + EXSFileName = ""; + PRPFileName = ""; + area.setText(""); + showArea(" "); + } + + private void setPMLRootAndName() { + fileName = file.getName(); + if (file.getParentFile() == null) + root = ""; + else + root = file.getParentFile().getAbsolutePath(); + if (fileName.lastIndexOf('.') == -1) + fileRoot = fileName; + else { + fileRoot = fileName.substring(0, fileName.lastIndexOf('.')); + extension = fileName.substring(fileName.lastIndexOf('.')); + } + LTLFileName = root + File.separator + fileRoot + ".ltl"; + OUTFileName = root + File.separator + fileRoot + ".out"; + EXCFileName = root + File.separator + fileRoot + ".exc"; + EXSFileName = root + File.separator + fileRoot + ".exs"; + PRPFileName = root + File.separator + fileRoot + ".prp"; + PRPName = ""; + showArea(fileName); + } + + private void setPRPRootAndName(File fc) { + String fileName = fc.getName(); + String fileRoot, root; + if (file.getParentFile() == null) + root = ""; + else + root = fc.getParentFile().getAbsolutePath(); + if (fileName.lastIndexOf('.') == -1) + fileRoot = fileName; + else + fileRoot = fileName.substring(0, fileName.lastIndexOf('.')); + LTLFileName = root + File.separator + fileRoot + ".ltl"; + PRPFileName = root + File.separator + fileRoot + ".prp"; + PRPName = fileRoot + ".prp"; + } + + // Open file: Promela (and excluded) or property file + void openFile(File fc, boolean pml) { + String prp = ""; + if (pml) { + if (!fc.exists()) { + messageArea.append("File " + fc + " does not exist\n"); + focus(true); + return; + } + file = fc; + area.setText(readFile(fc)); + setPMLRootAndName(); + prp = readFile(new java.io.File(PRPFileName)); + filter.setExcluded(readFile(new java.io.File(EXCFileName)), true); + filter.setExcluded(readFile(new java.io.File(EXSFileName)), false); + } else { + if (fc.exists()) + prp = readFile(fc); + else + messageArea.append("Creating new prp file\n"); + setPRPRootAndName(fc); + } + LTLField.setText(prp.startsWith("Error") ? "" : prp); + LTLmodified = false; + } + + String readFile(File fc) { + try { + return FileUtils.readFileToString(fc, StandardCharsets.UTF_8); + } catch (IOException e) { + focus(true); + return "IO error with file " + fc; + } + } + + void saveFile(File fc) { + if (fc != null) { + file = fc; + setPMLRootAndName(); + LTLmodified = true; // To force saving + modified = true; + } + if (LTLmodified) { + if (!LTLField.getText().equals("")) + writeFile(new java.io.File(PRPFileName), LTLField); + LTLmodified = false; + } + if (modified) { + area.setBorder(border1); + writeFile(file, area); + modified = false; + } + } + + void writeFile(File fc, javax.swing.text.JTextComponent area) { + if (fc == null || area == null) { + return; + } + try { + FileUtils.writeStringToFile(fc, area.getText(), StandardCharsets.UTF_8); + messageArea.append("Saved " + fc.getName() + "\n"); + } catch (IOException e) { + e.printStackTrace(); + } + } + + void find() { + findString = JOptionPane.showInputDialog( + area, null, "Find", JOptionPane.PLAIN_MESSAGE); + if (findString != null) { + search(); + findLoc = area.getCaretPosition(); + } else + focus(false); + } + + void findAgain() { + if (findString != null) + search(); + else + focus(false); + } + + private void search() { + int found = area.getText().toLowerCase().indexOf( + findString.toLowerCase(), findLoc); + if (found != -1) { + findLoc = found + 1; + area.setCaretPosition(found); + area.moveCaretPosition(found + findString.length()); + } + focus(false); + } + + private void setModified(DocumentEvent e) { + modified = true; + area.setBorder(border2); + final int lines = area.getLineCount(); + if (lineNumbers != null) { + Runnable updateAComponent = () -> lineNumbers.setHeightByLines(lines); + SwingUtilities.invokeLater(updateAComponent); + } + } + + public void modifiedLTL() { + LTLmodified = true; + } + + public void changedUpdate(DocumentEvent e) { + setModified(e); + } + + public void insertUpdate(DocumentEvent e) { + setModified(e); + } + + public void removeUpdate(DocumentEvent e) { + setModified(e); + } + + public void lostOwnership(Clipboard clipboard, Transferable content) { + } +} diff --git a/jspin/Excluded.java b/src/main/java/com/spinroot/jspin/Excluded.java similarity index 55% rename from jspin/Excluded.java rename to src/main/java/com/spinroot/jspin/Excluded.java index eef378a..7be83bc 100644 --- a/jspin/Excluded.java +++ b/src/main/java/com/spinroot/jspin/Excluded.java @@ -1,59 +1,62 @@ -/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * Edit excluded variables - */ - -package jspin; -import javax.swing.*; -import java.awt.event.*; - -class Excluded extends JFrame implements ActionListener { - private JTextArea names; - private JButton okButton = new JButton(Config.OK); - private JButton cancelButton = new JButton(Config.Cancel); - private JPanel textPanel = new JPanel(); - private JPanel OKPanel = new JPanel(); - private Editor editor; - private filterSpin.Filter filter; - private boolean exVar; - private String fileName; - - Excluded(Editor e, java.awt.Font font, filterSpin.Filter f, boolean v) { - editor = e; - filter = f; - exVar = v; - fileName = exVar ? editor.EXCFileName : editor.EXSFileName; - String read = editor.readFile(new java.io.File(fileName)); - if (read.startsWith("Error")) read = ""; - names = new JTextArea(read, 9, 32); - names.setFont(font); - textPanel.add(new JScrollPane(names)); - OKPanel.add(okButton); - OKPanel.add(cancelButton); - okButton.setMnemonic(Config.OKMN); - okButton.addActionListener(this); - cancelButton.addActionListener(this); - getRootPane().setDefaultButton(okButton); - getRootPane().registerKeyboardAction(this, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), - JComponent.WHEN_IN_FOCUSED_WINDOW); - getContentPane().add(textPanel, java.awt.BorderLayout.CENTER); - getContentPane().add(OKPanel, java.awt.BorderLayout.SOUTH); - setTitle(exVar ? Config.ExcludedV : Config.ExcludedS); - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setSize(Config.getIntProperty("WIDTH")/3, - Config.getIntProperty("HEIGHT")/3); - setLocationRelativeTo(null); - validate(); - setVisible(true); - jSpin.append(names, null); // Set caret to end of display - } - - public void actionPerformed(ActionEvent e) { - if ((e.getSource() == okButton) && !fileName.equals("")) { - editor.writeFile(new java.io.File(fileName), names); - filter.setExcluded(names.getText(), exVar); - } - dispose(); - } -} +/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * Edit excluded variables + */ + +package com.spinroot.jspin; + +import javax.swing.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +class Excluded extends JFrame implements ActionListener { + private JTextArea names; + private JButton okButton = new JButton(Config.OK); + private JButton cancelButton = new JButton(Config.Cancel); + private JPanel textPanel = new JPanel(); + private JPanel OKPanel = new JPanel(); + private Editor editor; + private com.spinroot.filterSpin.Filter filter; + private boolean exVar; + private String fileName; + + Excluded(Editor editor, java.awt.Font font, com.spinroot.filterSpin.Filter filter, boolean v) { + this.editor = editor; + this.filter = filter; + exVar = v; + fileName = exVar ? this.editor.getEXCFileName() : this.editor.getEXSFileName(); + String read = this.editor.readFile(new java.io.File(fileName)); + if (read.startsWith("Error")) read = ""; + names = new JTextArea(read, 9, 32); + names.setFont(font); + textPanel.add(new JScrollPane(names)); + OKPanel.add(okButton); + OKPanel.add(cancelButton); + okButton.setMnemonic(Config.OKMN); + okButton.addActionListener(this); + cancelButton.addActionListener(this); + getRootPane().setDefaultButton(okButton); + getRootPane().registerKeyboardAction(this, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + getContentPane().add(textPanel, java.awt.BorderLayout.CENTER); + getContentPane().add(OKPanel, java.awt.BorderLayout.SOUTH); + setTitle(exVar ? Config.ExcludedV : Config.ExcludedS); + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setSize(Config.getIntProperty("WIDTH") / 3, + Config.getIntProperty("HEIGHT") / 3); + setLocationRelativeTo(null); + validate(); + setVisible(true); + jSpin.append(names, null); // Set caret to end of display + } + + public void actionPerformed(ActionEvent e) { + if ((e.getSource() == okButton) && !fileName.equals("")) { + editor.writeFile(new java.io.File(fileName), names); + filter.setExcluded(names.getText(), exVar); + } + dispose(); + } +} diff --git a/src/main/java/com/spinroot/jspin/Filter.java b/src/main/java/com/spinroot/jspin/Filter.java new file mode 100644 index 0000000..2fc2c86 --- /dev/null +++ b/src/main/java/com/spinroot/jspin/Filter.java @@ -0,0 +1,214 @@ +/* Copyright 2004-5 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * Filter Spin output. + * Display a table: process, statement, variables. + * The width of a variable field is dynamically configurable (VARIABLE_WIDTH). +*/ + +package com.spinroot.jspin; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.TreeMap; + +class Filter { + private static final String spacerTitle = " "; + + // Print the title repeatedly + private static final int linesPerTitle = 20; + private String title; // String for names of variables + private int lines; // Line counter to redisplay title + + // Map of variable names and values + private TreeMap variables = new TreeMap(); + private int oldSize; // Previous size to see if variable added + + // Excluded variable names and statements + private ArrayList excludedVar = new ArrayList(); + private ArrayList excludedState = new ArrayList(); + + // Called before each new command + void init() { + variables.clear(); + oldSize = 0; + title = ""; + lines = -1; + } + + // Parse string to initialize excluded array; ignore NL and CR + void setExcluded(String s, boolean exVar) { + List excluded = exVar ? excludedVar : excludedState; + s = s.replace('\r', '\n'); + excluded.clear(); + do { + int nl = s.indexOf('\n'); + if (nl == -1) break; + if (!s.substring(0, nl).equals("")) + excluded.add(s.substring(0, nl)); + s = s.substring(nl + 1); + } while (true); + } + + // Check for excluded variables. + // For each excluded string S; + // If variable name includes S, do not display, + // but if some +T in file is in name, display anyway. + private boolean checkExcluded(String name, boolean exVar) { + List excluded = exVar ? excludedVar : excludedState; + for (int i = 0; i < excluded.size(); i++) + if ((excluded.get(i).charAt(0) != '+') && + (name.indexOf(excluded.get(i)) != -1)) { + boolean included = false; + for (int j = 0; j < excluded.size(); j++) + included = included || + ((excluded.get(j).charAt(0) == '+') && + (name.indexOf(excluded.get(j).substring(1)) != -1)); + return !included; + } + return false; + } + + String filter(String s) { + try { + // Variables and queues start with double tab + if (s.startsWith("\t\t")) { + String varName, varValue; + // Name and value of variable/queue to TreeMap + if (s.startsWith("\t\tqueue")) { + varName = s.substring(s.indexOf('(') + 1, s.indexOf(')')); + varValue = s.substring(s.indexOf(':') + 1).trim(); + } else { + varName = s.substring(2, s.indexOf('=') - 1); + varValue = s.substring(s.indexOf('=') + 1).trim(); + } + if (checkExcluded(varName, true)) return ""; + variables.put(varName, varValue); + // Construct new title if new variables encountered + if (variables.size() > oldSize) { + title = formatItem(Config.processTitle, + Config.getIntProperty("PROCESS_WIDTH")) + + spacerTitle + + formatItem(Config.statementTitle, + Config.getIntProperty("STATEMENT_WIDTH")) + + spacerTitle + + collectionToString(variables.keySet()) + "\n"; + oldSize = variables.size(); + lines = -1; + } + return ""; + } + + // Display Spin and pan messages unmodified + // Also non-prefixed error message + else if ((s.startsWith("pan:")) || + (s.startsWith("spin:")) || + (s.startsWith("tl_spin:")) || + (s.startsWith("Error:")) || + (s.startsWith("error:"))) + return s + "\n"; + // Display error count + else if (s.indexOf("errors:") != -1) + return + s.substring(0, s.indexOf("errors:")) + "\u2022\u2022\u2022 " + + s.substring(s.indexOf("errors:")) + " \u2022\u2022\u2022\n"; + // Display MSC lines (without MSC:) + else if (Config.getBooleanProperty("MSC") && + s.trim().startsWith("MSC:")) + return s.substring(s.indexOf("MSC:") + 5) + "\n"; + // Display cycle messages + else if (s.indexOf("<<<<<") != -1) + return s + "\n"; + + // Display lines with statements, including choices + else if ((s.indexOf("proc") != -1) && (s.indexOf("line") != -1)) { + String u = ""; + // Get process name + String proc = + s.substring(s.indexOf("proc") + 4, s.indexOf(")") + 1).trim(); + proc = proc.substring(0, proc.indexOf("(")) + + strip(proc.substring(proc.indexOf("("))); + // Get line number and statement name + String statement = ""; + if (s.indexOf('[') != -1) { + statement = formatItem( + s.substring(s.indexOf("line") + 4, s.indexOf("\"")).trim(), 3); + statement = statement + " " + + strip(s.substring(s.indexOf('[') + 1, s.lastIndexOf(']'))); + } + if (checkExcluded(statement, false)) return ""; + // For choice, display just process and statement + if (s.indexOf("choice") != -1) + u = s.substring(s.indexOf("choice"), s.indexOf(':') + 2) + + proc + " " + statement + "\n"; + // Display table line (unless goto/else/break) + else if ((statement.indexOf("goto") == -1) && + !statement.equals("else") && + !statement.equals("break")) { + u = formatItem(proc, + Config.getIntProperty("PROCESS_WIDTH")) + + spacerTitle + + formatItem(statement, + Config.getIntProperty("STATEMENT_WIDTH")) + + spacerTitle + + collectionToString(variables.values()) + "\n"; + lines = (lines + 1) % linesPerTitle; + // Display title if needed + if (lines == 0) u = title + u; + } + return u; + } + // Display choices that have no proc and line number + else if (s.indexOf("choice") != -1) + return s.substring(s.indexOf("choice")) + "\n"; + else if (!Config.getBooleanProperty("MSC") && !s.equals("")) + return s + "\n"; + else + return ""; + + } catch (Exception e) { + System.err.println("\n + jSpin error in filter for:\n" + s + "\n"); + e.printStackTrace(); + return ""; + } + } + + // Strip parentheses + String strip(String s) { + while ((s.charAt(0) == '(') && (s.charAt(s.length() - 1) == ')')) + s = s.substring(1, s.length() - 1); + return s; + } + + // Format a variable name or value + private String formatItem(String s, int len) { + // Item is too long, must shorten it + if (s.length() > len) { + // Array variable: shorten name, not index + if (s.indexOf("[") != -1) { + String subscript = + s.substring(s.indexOf("["), s.lastIndexOf("]") + 1); + if (subscript.length() < len) + return s.substring(0, + len - subscript.length()) + subscript; + else + return s.substring(0, len); + } else + return s.substring(0, len); + } + // Item is too short, pad it + else if (s.length() < len) + return (s + " ").substring(0, len); + else + return s; + } + + // Transform a collection to a string, calling formatItem for each element + private String collectionToString(Collection c) { + StringBuilder s = new StringBuilder(); + for (String aC : c) { + s.append(formatItem(aC, Config.getIntProperty("VARIABLE_WIDTH"))).append(" "); + } + return s.toString(); + } +} diff --git a/jspin/ImagePanel.java b/src/main/java/com/spinroot/jspin/ImagePanel.java similarity index 72% rename from jspin/ImagePanel.java rename to src/main/java/com/spinroot/jspin/ImagePanel.java index 816c778..4719236 100644 --- a/jspin/ImagePanel.java +++ b/src/main/java/com/spinroot/jspin/ImagePanel.java @@ -1,24 +1,29 @@ -/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * Display images from dot file - */ -package jspin; -import java.awt.*; - -import javax.swing.*; - -class ImagePanel extends JPanel { - private Image image; - ImagePanel(String fileName) { - image = Toolkit.getDefaultToolkit().createImage(fileName); - MediaTracker tracker = new MediaTracker(this); - tracker.addImage(image, 0); - try { tracker.waitForID(0); } - catch (InterruptedException e) {} - setPreferredSize(new Dimension(image.getWidth(this), image.getHeight(this))); - } - public void paintComponent(Graphics g) { - super.paintComponent(g); - g.drawImage(image, 0, 0, null); - } -} +/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * Display images from dot file + */ +package com.spinroot.jspin; + +import javafx.embed.swing.JFXPanel; + +import java.awt.*; + +class ImagePanel extends JFXPanel { + private Image image; + + ImagePanel(String fileName) { + image = Toolkit.getDefaultToolkit().createImage(fileName); + MediaTracker tracker = new MediaTracker(this); + tracker.addImage(image, 0); + try { + tracker.waitForID(0); + } catch (InterruptedException e) { + } + setPreferredSize(new Dimension(image.getWidth(this), image.getHeight(this))); + } + + public void paintComponent(Graphics g) { + super.paintComponent(g); + g.drawImage(image, 0, 0, null); + } +} diff --git a/jspin/JSpinFileFilter.java b/src/main/java/com/spinroot/jspin/JSpinFileFilter.java similarity index 66% rename from jspin/JSpinFileFilter.java rename to src/main/java/com/spinroot/jspin/JSpinFileFilter.java index 516b6e7..4ef0992 100644 --- a/jspin/JSpinFileFilter.java +++ b/src/main/java/com/spinroot/jspin/JSpinFileFilter.java @@ -1,35 +1,39 @@ -/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * File filter for jSpin -*/ - -package jspin; -import java.io.File; -import javax.swing.filechooser.*; - -public class JSpinFileFilter extends FileFilter { - - private String ext1 = ""; - private String ext2 = ""; - private String ext3 = ""; - private String description = ""; - - public JSpinFileFilter(String d, String e1, String e2, String e3) { - ext1 = e1; ext2 = e2; ext3 = e3; description = d; - } - - public boolean accept(File f) { - if (f.isDirectory()) - return true; - else { - String e = f.getName().toUpperCase(); - return e.endsWith(ext1) || - (ext2 == null ? false : e.endsWith(ext2)) || - (ext3 == null ? false : e.endsWith(ext3)); - } - } - - public String getDescription() { - return description; - } -} +/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * File filter for jSpin +*/ + +package com.spinroot.jspin; + +import javax.swing.filechooser.FileFilter; +import java.io.File; + +public class JSpinFileFilter extends FileFilter { + + private String ext1 = ""; + private String ext2 = ""; + private String ext3 = ""; + private String description = ""; + + public JSpinFileFilter(String d, String e1, String e2, String e3) { + ext1 = e1; + ext2 = e2; + ext3 = e3; + description = d; + } + + public boolean accept(File f) { + if (f.isDirectory()) + return true; + else { + String e = f.getName().toUpperCase(); + return e.endsWith(ext1) || + (ext2 != null && e.endsWith(ext2)) || + (ext3 != null && e.endsWith(ext3)); + } + } + + public String getDescription() { + return description; + } +} diff --git a/jspin/LineNumbers.java b/src/main/java/com/spinroot/jspin/LineNumbers.java similarity index 76% rename from jspin/LineNumbers.java rename to src/main/java/com/spinroot/jspin/LineNumbers.java index 9ecd38b..fbd34de 100644 --- a/jspin/LineNumbers.java +++ b/src/main/java/com/spinroot/jspin/LineNumbers.java @@ -3,14 +3,15 @@ * Display line numbers in editor */ -package jspin; -import java.awt.*; +package com.spinroot.jspin; + import javax.swing.*; +import java.awt.*; public class LineNumbers extends JComponent { - private int size; // Width of line numbers - private Font font; // Font of editor window - private int ascent; // Data for computation of line height + private int size; // Width of line numbers + private Font font; // Font of editor window + private int ascent; // Data for computation of line height private int increment; private int top; @@ -20,8 +21,8 @@ public class LineNumbers extends JComponent { size = fm.stringWidth("000") + 6; ascent = fm.getAscent(); increment = ascent + fm.getDescent(); - // Extra line for file name in border - top = fm.getHeight() + fm.getDescent() + 3; + // Extra line for file name in border + top = fm.getHeight() + fm.getDescent() + 3; setPreferredSize(new Dimension(size, area.getSize().height)); revalidate(); } @@ -40,11 +41,11 @@ public void paintComponent(Graphics g) { // Ruler labels in black color g.setFont(font); g.setColor(Color.black); - int end = 0; //This keeps the position for the end of the view - int start = 0; //This keeps the position for the beginning of the view + int end = 0; //This keeps the position for the end of the view + int start = 0; //This keeps the position for the beginning of the view start = (drawHere.y / increment) * increment; end = (((drawHere.y + drawHere.height) / increment) + 1) - * increment; + * increment; int lineNumber = (int) Math.floor(drawHere.y / increment) + 1; start += top + ascent; end += top + ascent; diff --git a/src/main/java/com/spinroot/jspin/Options.java b/src/main/java/com/spinroot/jspin/Options.java new file mode 100644 index 0000000..3b5052c --- /dev/null +++ b/src/main/java/com/spinroot/jspin/Options.java @@ -0,0 +1,118 @@ +/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * Dialog for setting Common Options + */ + +package com.spinroot.jspin; + +import javax.swing.*; +import java.awt.event.*; + +class Options extends JFrame implements ActionListener, ItemListener { + static final String ST = "-p", LOC = "-l", GLO = "-g", SENT = "-s", REC = "-r"; + private JCheckBox stBox, locBox, gloBox, sentBox, recBox; + private JButton okButton, cancelButton, clearAllButton, setAllButton; + private JPanel buttonPanel, OKPanel; + private boolean st; + private boolean loc; + private boolean glo; + private boolean sent; + private boolean rec; + + Options() { + String s = Config.getStringProperty("COMMON_OPTIONS"); + st = s.contains(ST); + loc = s.contains(LOC); + glo = s.contains(GLO); + sent = s.contains(SENT); + rec = s.contains(REC); + buttonPanel = new JPanel(); + buttonPanel.setLayout(new java.awt.GridLayout(5, 1)); + stBox = create(Config.Statements, st, Config.StatementsMN); + locBox = create(Config.Locals, loc, Config.LocalsMN); + gloBox = create(Config.Globals, glo, Config.GlobalsMN); + sentBox = create(Config.Sent, sent, Config.SentMN); + recBox = create(Config.Received, rec, Config.ReceivedMN); + OKPanel = new JPanel(); + OKPanel.setLayout(new java.awt.GridLayout(2, 2)); + okButton = new JButton(Config.OK); + cancelButton = new JButton(Config.Cancel); + clearAllButton = new JButton(Config.ClearAll); + setAllButton = new JButton(Config.SetAll); + okButton.setMnemonic(Config.OKMN); + clearAllButton.setMnemonic(Config.ClearAllMN); + setAllButton.setMnemonic(Config.SetAllMN); + OKPanel.add(okButton); + OKPanel.add(cancelButton); + OKPanel.add(setAllButton); + OKPanel.add(clearAllButton); + okButton.addActionListener(this); + cancelButton.addActionListener(this); + setAllButton.addActionListener(this); + clearAllButton.addActionListener(this); + getRootPane().setDefaultButton(okButton); + getRootPane().registerKeyboardAction(this, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + getContentPane().add(buttonPanel, java.awt.BorderLayout.CENTER); + getContentPane().add(OKPanel, java.awt.BorderLayout.SOUTH); + setTitle(Config.OPTIONS_TITLE); + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setSize(200, 250); + setLocationRelativeTo(null); + validate(); + setVisible(true); + } + + private JCheckBox create(String s, boolean set, int mn) { + JCheckBox cb = new JCheckBox(s, set); + cb.setMnemonic(mn); + cb.addItemListener(this); + buttonPanel.add(cb); + return cb; + } + + private void setClear(boolean b) { + st = b; + loc = b; + glo = b; + sent = b; + rec = b; + stBox.setSelected(b); + locBox.setSelected(b); + gloBox.setSelected(b); + sentBox.setSelected(b); + recBox.setSelected(b); + } + + public void actionPerformed(ActionEvent e) { + String options = ""; + if (e.getSource() == okButton) { + options = options + (st ? ST + " " : ""); + options = options + (loc ? LOC + " " : ""); + options = options + (glo ? GLO + " " : ""); + options = options + (sent ? SENT + " " : ""); + options = options + (rec ? REC + " " : ""); + Config.setStringProperty("COMMON_OPTIONS", options); + dispose(); + } else if (e.getSource() == setAllButton) { + setClear(true); + } else if (e.getSource() == clearAllButton) { + setClear(false); + } else + dispose(); + } + + public void itemStateChanged(ItemEvent e) { + if (e.getItemSelectable() == stBox) + st = e.getStateChange() == ItemEvent.SELECTED; + else if (e.getItemSelectable() == locBox) + loc = e.getStateChange() == ItemEvent.SELECTED; + else if (e.getItemSelectable() == gloBox) + glo = e.getStateChange() == ItemEvent.SELECTED; + else if (e.getItemSelectable() == sentBox) + sent = e.getStateChange() == ItemEvent.SELECTED; + else if (e.getItemSelectable() == recBox) + rec = e.getStateChange() == ItemEvent.SELECTED; + } +} diff --git a/src/main/java/com/spinroot/jspin/RunSpin.java b/src/main/java/com/spinroot/jspin/RunSpin.java new file mode 100644 index 0000000..825a0a7 --- /dev/null +++ b/src/main/java/com/spinroot/jspin/RunSpin.java @@ -0,0 +1,371 @@ +/* Copyright 2003-4 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* +* Fork process for running Spin +* Manage dialog for interactive simulation +*/ + +package com.spinroot.jspin; + +import javax.swing.*; +import java.awt.event.*; +import java.io.*; + +class RunSpin { + private static final int MAX_SELECTIONS = 50; + private Editor editor; // The editor object + private com.spinroot.filterSpin.Filter filter; // The filter object + private RunThread runThread; // Thread object for running Spin + private SelectDialog selectDialog; // Thread object for select dialog + private JTextArea messageArea; // The message area + private JTextArea area; // Output area display + private PrintWriter rawWriter; // To write raw spin output + private String command, parameters; // The command being executed + private boolean filtering; // Should the output be filtered + private String[] selections = new String[MAX_SELECTIONS]; + // Statements selected from + + RunSpin(Editor e, JTextArea m, com.spinroot.filterSpin.Filter f) { + editor = e; + messageArea = m; + filter = f; + } + + // Called by jSpin to run Spin + void run(JTextArea area, boolean filtering, String command, String parameters) { + this.filtering = filtering; + this.area = area; + this.command = command; + this.parameters = parameters; + filter.init(Config.properties); + // Make sure that a file has been opened + if (editor.getFile() == null) { + jSpin.append(messageArea, Config.OPEN_FILE); + return; + } + // Save editor buffer and set up display areas + editor.saveFile(null); + if (area != messageArea) + this.area.setText(""); + jSpin.append(messageArea, command + " " + parameters + " ... "); + // Create a thread to run Spin and start it + runThread = new RunThread(); + runThread.start(); + } + + // Run Spin and wait for it to complete + void runAndWait(JTextArea area, boolean filtering, String command, String parameters) { + run(area, filtering, command, parameters); + if (runThread == null) return; // If file not open + try { + runThread.join(); + jSpin.append(messageArea, "done!\n"); + } catch (InterruptedException e) { + } + } + + // Check is Spin is still running + boolean isRunning() { + return (runThread != null) && runThread.isAlive(); + } + + // Kill the thread running Spin and the selection dialog + void killSpin() { + if (runThread != null) { + runThread.killSpin(); + runThread.interrupt(); + runThread = null; + } + if (selectDialog != null) { + selectDialog.disposeDialog(); + selectDialog.interrupt(); + selectDialog = null; + } + jSpin.append(messageArea, "\nSpin process stopped\n"); + } + + // Class RunThread enables Spin to run asynchronously + private class RunThread extends Thread { + private Process p; + + public void run() { + try { + if (Config.getBooleanProperty("RAW")) + rawFile(); + // Use ProcessBuilder to run Spin, redirecting ErrorStream + String[] sa = stringToArray(command, parameters); +// for (int i = 0; i < sa.length; i++) System.out.println(sa[i]); + ProcessBuilder pb = new ProcessBuilder(sa); + File pf = editor.getFile().getParentFile(); + if (pf != null) pb.directory(pf.getCanonicalFile()); + pb.redirectErrorStream(true); + p = pb.start(); + // Connect to I/O streams + InputStream istream = p.getInputStream(); + BufferedReader input = + new BufferedReader(new InputStreamReader(istream)); + OutputStream ostream = p.getOutputStream(); + OutputStreamWriter output = new OutputStreamWriter(ostream); + // Process Spin output line by line + String s = ""; + boolean running = true; + while (running) { + s = input.readLine(); + if (Config.getBooleanProperty("RAW")) + rawWriter.println(s); + if (s == null) + running = false; + else if (s.startsWith("Select a statement") || + s.startsWith("Select stmnt")) + running = select(area, p, input, output); + else if (s.startsWith("spin: type return")) { + output.write("\n"); + output.flush(); + } else if (filtering) + jSpin.append(area, filter.filter(s)); + else + jSpin.append(area, s + "\n"); + } + // Wait for Spin process to end + p.waitFor(); + if (Config.getBooleanProperty("RAW")) + rawWriter.close(); + // If syntax error, set cursor to line in editor + if (area.getText().indexOf("Error: syntax error") != -1) { + s = area.getText(); + try { + int line = Integer.parseInt( + s.substring( + s.indexOf("line") + 4, s.indexOf('"')).trim()); + editor.caretToLine(line); + } catch (NumberFormatException e1) { + editor.caretToLine(0); + } + } + } catch (InterruptedException e) { + jSpin.append(messageArea, "Interrupted exception"); + } catch (java.io.IOException e) { + jSpin.append(messageArea, "IO exception\n" + e); + } + } + + // String to array of tokens - for ProcessBuilder + // Previous versions of jSpin used StringTokenizer + // which caused problems in Linux + String[] stringToArray(String command, String s) { + char quote = Config.getBooleanProperty("SINGLE_QUOTE") ? '\'' : '"'; + String[] sa = new String[50]; + int count = 0, i = 0, start = 0; + sa[count] = command; + count++; + while (i < s.length() && s.charAt(i) == ' ') i++; + start = i; + boolean isQuote; + do { + if (i == s.length()) break; + isQuote = s.charAt(i) == quote; + if (isQuote) i++; + if (isQuote) { + while (s.charAt(i) != quote) i++; + i++; + } else + while (i < s.length() && s.charAt(i) != ' ') i++; + sa[count] = s.substring(start, i); + while (i < s.length() && s.charAt(i) == ' ') i++; + start = i; + count++; + } while (true); + String[] sb = new String[count]; + System.arraycopy(sa, 0, sb, 0, count); + return sb; + } + + // Kill spin process + private void killSpin() { + if (p != null) p.destroy(); + } + + // Open file for raw Spin output + private void rawFile() { + String s = editor.getRoot() + File.separator + editor.getFileRoot() + ".raw"; + try { + rawWriter = new PrintWriter(new FileWriter(s)); + jSpin.append(messageArea, "\nOpened " + s + "\n"); + } catch (IOException e) { + jSpin.append(messageArea, "\nCannot open " + s + "\n"); + } + } + + // Select the next statement to run in interactive simulation + private boolean select( + JTextArea area, Process p, + BufferedReader input, OutputStreamWriter output) { + int numOptions = 0; + String filtered; + try { + String s = input.readLine(); + if (Config.getBooleanProperty("RAW")) + rawWriter.println(s); + while (!s.startsWith("Make Selection")) { + filtered = filter.filter(s); + if ((numOptions < MAX_SELECTIONS) && + (Config.getBooleanProperty("UNEXECUTABLE") || + s.indexOf("unexecutable") == -1)) { + selections[numOptions] = new String(filtered.substring(7)); + numOptions++; + } + s = input.readLine(); + if (Config.getBooleanProperty("RAW")) + rawWriter.println(s); + } + if (numOptions == 0) { + output.write("q\n"); + output.flush(); + return false; + } + // Get selection from dialog + int selectedValue = -1; + selectDialog = + new SelectDialog( + numOptions, + numOptions <= Config.getIntProperty("SELECT_MENU"), + selections); + selectDialog.start(); + while (selectedValue == -1) { + try { + Thread.sleep(Config.getIntProperty("POLLING_DELAY")); + } catch (InterruptedException e) { + } + if (selectDialog == null) break; + else selectedValue = selectDialog.getValue(); + } + // For Macintosh (?) - Angelika's problem (?) + if (selectDialog != null) { + selectDialog.interrupt(); + selectDialog = null; + } + // if (selectDialog != null) selectDialog.interrupt(); + // If 0 (escape or close) selected, quit Spin interaction + if (selectedValue == 0) { + output.write("q\n"); + output.flush(); + return false; + } + selectedValue = Integer.valueOf( + selections[selectedValue - 1].substring( + 0, selections[selectedValue - 1].indexOf(':'))); + // Send selection to Spin + output.write(selectedValue + "\n"); + output.flush(); + s = input.readLine(); // Eat extra new line + if (Config.getBooleanProperty("RAW")) + rawWriter.println(s); + return true; + } catch (Exception e) { + System.err.println(e); + killSpin(); + return false; + } + } + } + + // Class SelectDialog displays the statement select dialog in a thread + private class SelectDialog extends Thread implements ActionListener { + private int selectedValue = -1; + // Positive when a button is selected, zero upon escape or close + private int numOptions; // Number of process buttons + private String[] selections;// The selections + + private JFrame dialog; // The frame + private JPanel panel; + private JButton[] options; // Array of process buttons + private JComboBox pulldown = new JComboBox(); + + // Constructor - set up frame with number of buttons required + SelectDialog(int numOptions, boolean buttons, String[] selections) { + this.numOptions = numOptions; + this.selections = selections; + dialog = new JFrame(); + dialog.addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent e) { + selectedValue = 0; + dialog.dispose(); + } + }); + dialog.getRootPane().registerKeyboardAction(this, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + dialog.setTitle(Config.SELECT); + panel = new JPanel(); + if (buttons) constructButtonsDialog(); + else constructMenuDialog(); + dialog.getContentPane().setLayout(new java.awt.BorderLayout()); + dialog.getContentPane().add(panel, java.awt.BorderLayout.CENTER); + dialog.setLocationRelativeTo(messageArea); + dialog.validate(); + dialog.setVisible(true); + } + + void constructButtonsDialog() { + panel.setLayout(new java.awt.GridLayout(1, numOptions)); + options = new JButton[numOptions]; + JButton button = null; + for (int i = 1; i <= numOptions; i++) { + button = new JButton(selections[i - 1]); + button.setFont(messageArea.getFont()); + button.addActionListener(this); + options[i - 1] = button; + panel.add(button); + } + dialog.setSize( + Config.getIntProperty("SELECT_BUTTON") * numOptions, + Config.getIntProperty("SELECT_HEIGHT")); + } + + void constructMenuDialog() { + panel.setLayout(new java.awt.BorderLayout()); + pulldown = new JComboBox(); + pulldown.setFont(messageArea.getFont()); + pulldown.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); + pulldown.setEditable(false); + for (int i = 0; i < numOptions; i++) + pulldown.addItem(selections[i]); + pulldown.setSelectedIndex(-1); + pulldown.addActionListener(this); + panel.add(pulldown, java.awt.BorderLayout.CENTER); + dialog.setSize( + Config.getIntProperty("SELECT_BUTTON"), + Config.getIntProperty("SELECT_HEIGHT")); + } + + // Display dialog + public void run() { + dialog.setVisible(true); + } + + // ActionListener + public void actionPerformed(ActionEvent e) { + if (e.getSource() instanceof JButton) { + JButton selected = (JButton) e.getSource(); + for (int i = 0; i < numOptions; i++) + if (options[i].equals(selected)) + selectedValue = i + 1; + } else if (e.getSource() instanceof JComboBox) { + selectedValue = ((JComboBox) e.getSource()).getSelectedIndex() + 1; + } else selectedValue = 0; + dialog.dispose(); + java.awt.Dimension rv = ((JComponent) e.getSource()).getSize(null); + Config.setIntProperty("SELECT_BUTTON", rv.width); + } + + // Dispose of dialog frme + private void disposeDialog() { + if (dialog != null) dialog.dispose(); + } + + // Get value + private int getValue() { + return selectedValue; + } + } +} diff --git a/jspin/SpiderFile.java b/src/main/java/com/spinroot/jspin/SpiderFile.java similarity index 62% rename from jspin/SpiderFile.java rename to src/main/java/com/spinroot/jspin/SpiderFile.java index 48fcab5..ff80600 100644 --- a/jspin/SpiderFile.java +++ b/src/main/java/com/spinroot/jspin/SpiderFile.java @@ -1,89 +1,93 @@ -/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * Read and write the SpinSpider properties file for this program - */ - -package jspin; -import java.io.*; -import java.util.Properties; - -class SpiderFile { - private Properties properties; - private String fileName; - - SpiderFile (Properties p, String f) { - properties = p; - fileName = f + ".spd"; - } - - private void setDefaultProperties() { - properties.put("TRAIL_CODE", Integer.toString(0)); - properties.put("DOT_SIZE", Integer.toString(0)); - properties.put("TRAIL_STYLE", Integer.toString(0)); - properties.put("SPIDER_DEBUG", Boolean.toString(false)); - properties.put("PROCESSES", Integer.toString(2)); - properties.put("FORMAT", Config.PNG); - properties.put("VARIABLES", ""); - } - - // Initialize configuration file - public void init() { - setDefaultProperties(); - FileInputStream in = null; - try { - in = new FileInputStream(fileName); - } catch (FileNotFoundException e1) { - System.out.println( - "Cannot open SpinSpider file, creating new file"); - try { - saveFile(); - in = new FileInputStream(fileName); - } catch (IOException e2) { - System.err.println("Cannot write SpinSpider file"); - } - } - try { - properties.load(in); - in.close(); - } catch (IOException e3) { - System.err.println("Cannot read SpinSpider file"); - } - } - - // Save configuration file - void saveFile() { - try { - FileOutputStream out = new FileOutputStream(fileName); - properties.store(out, "SpinSpider configuration file"); - out.close(); - System.out.println("Saved SpinSpider file " + fileName); - } catch (IOException e2) { - System.err.println("Cannot write SpinSpider file"); - } - } - - // Interface to get/set propertyies of various types - public String getStringProperty(String s) { - return properties.getProperty(s); - } - - void setStringProperty(String s, String newValue) { - properties.setProperty(s, newValue); - } - - public boolean getBooleanProperty(String s) { - return Boolean.valueOf(properties.getProperty(s)).booleanValue(); - } - - void setBooleanProperty(String s, boolean newValue) { - properties.setProperty(s, Boolean.toString(newValue)); - } - - public int getIntProperty(String s) { - return Integer.valueOf(properties.getProperty(s)).intValue(); - } - - void setIntProperty(String s, int newValue) { - properties.setProperty(s, Integer.toString(newValue)); - } -} +/* Copyright 2005 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * Read and write the SpinSpider properties file for this program + */ + +package com.spinroot.jspin; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Properties; + +class SpiderFile { + private Properties properties; + private String fileName; + + SpiderFile(Properties p, String f) { + properties = p; + fileName = f + ".spd"; + } + + private void setDefaultProperties() { + properties.put("TRAIL_CODE", Integer.toString(0)); + properties.put("DOT_SIZE", Integer.toString(0)); + properties.put("TRAIL_STYLE", Integer.toString(0)); + properties.put("SPIDER_DEBUG", Boolean.toString(false)); + properties.put("PROCESSES", Integer.toString(2)); + properties.put("FORMAT", Config.PNG); + properties.put("VARIABLES", ""); + } + + // Initialize configuration file + public void init() { + setDefaultProperties(); + FileInputStream in = null; + try { + in = new FileInputStream(fileName); + } catch (FileNotFoundException e1) { + System.out.println( + "Cannot open SpinSpider file, creating new file"); + try { + saveFile(); + in = new FileInputStream(fileName); + } catch (IOException e2) { + System.err.println("Cannot write SpinSpider file"); + } + } + try { + properties.load(in); + in.close(); + } catch (IOException e3) { + System.err.println("Cannot read SpinSpider file"); + } + } + + // Save configuration file + void saveFile() { + try { + FileOutputStream out = new FileOutputStream(fileName); + properties.store(out, "SpinSpider configuration file"); + out.close(); + System.out.println("Saved SpinSpider file " + fileName); + } catch (IOException e2) { + System.err.println("Cannot write SpinSpider file"); + } + } + + // Interface to get/set propertyies of various types + public String getStringProperty(String s) { + return properties.getProperty(s); + } + + void setStringProperty(String s, String newValue) { + properties.setProperty(s, newValue); + } + + public boolean getBooleanProperty(String s) { + return Boolean.valueOf(properties.getProperty(s)); + } + + void setBooleanProperty(String s, boolean newValue) { + properties.setProperty(s, Boolean.toString(newValue)); + } + + public int getIntProperty(String s) { + return Integer.valueOf(properties.getProperty(s)); + } + + void setIntProperty(String s, int newValue) { + properties.setProperty(s, Integer.toString(newValue)); + } +} diff --git a/jspin/SpiderOptions.java b/src/main/java/com/spinroot/jspin/SpiderOptions.java similarity index 51% rename from jspin/SpiderOptions.java rename to src/main/java/com/spinroot/jspin/SpiderOptions.java index 1a597f7..1d1b6c8 100644 --- a/jspin/SpiderOptions.java +++ b/src/main/java/com/spinroot/jspin/SpiderOptions.java @@ -1,212 +1,215 @@ -/* Copyright 2007 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - * Dialog for setting SpinSpider options - */ - -package jspin; -import javax.swing.*; -import javax.swing.border.*; -import java.awt.event.*; - -class SpiderOptions extends JDialog implements ActionListener { - private JCheckBox debugBox; - private JRadioButton noTrail, emphTrail, onlyTrail, small, large, bold, color, automata; - private ButtonGroup trailGroup, dotGroup, styleGroup; - private JButton runButton, cancelButton; - private JLabel processLabel, variablesLabel, dotLabel, formatLabel, styleLabel; - private JComboBox formatBox, processBox; - private JTextArea variablesText; - private JPanel OKPanel, formatPanel, leftPanel, neverPanel, processPanel, - variablesPanel, trailPanel, sizePanel, boxPanel, stylePanel; - private Border border; - - private boolean ok; - private SpiderFile sp; - - SpiderOptions(JFrame parent, SpiderFile sp, java.awt.Font font) { - super(parent, true); - this.sp = sp; - - border = BorderFactory.createEtchedBorder(); - - formatLabel = new JLabel(Config.Format, JLabel.CENTER); - formatBox = new JComboBox(); - formatBox.setEditable(false); - formatBox.addItem(Config.DOT); - formatBox.addItem(Config.PNG); - formatBox.addItem(Config.FSM); - formatBox.addItem(Config.PS); - formatBox.setSelectedItem(sp.getStringProperty("FORMAT")); - - int trailCode = sp.getIntProperty("TRAIL_CODE"); - noTrail = new JRadioButton(Config.NoTrail, trailCode == 0); - noTrail.setMnemonic(Config.NoTrailMN); - emphTrail = new JRadioButton(Config.EmphTrail, trailCode == 1); - emphTrail.setMnemonic(Config.EmphTrailMN); - onlyTrail = new JRadioButton(Config.OnlyTrail, trailCode == 2); - onlyTrail.setMnemonic(Config.OnlyTrailMN); - automata = new JRadioButton(Config.Automata, trailCode == 3); - automata.setMnemonic(Config.AutomataMN); - trailGroup = new ButtonGroup(); - trailGroup.add(noTrail); - trailGroup.add(emphTrail); - trailGroup.add(onlyTrail); - trailGroup.add(automata); - - dotLabel = new JLabel(Config.DotSize, JLabel.CENTER); - int dotSize = sp.getIntProperty("DOT_SIZE"); - small = new JRadioButton(Config.DotSmall, dotSize == 0); - small.setMnemonic(Config.DotSmallMN); - large = new JRadioButton(Config.DotLarge, dotSize == 1); - large.setMnemonic(Config.DotLargeMN); - dotGroup = new ButtonGroup(); - dotGroup.add(small); - dotGroup.add(large); - - styleLabel = new JLabel(Config.TrailStyle, JLabel.CENTER); - int trailStyle = sp.getIntProperty("TRAIL_STYLE"); - color = new JRadioButton(Config.TrailColor, trailStyle == 0); - color.setMnemonic(Config.TrailColorMN); - bold = new JRadioButton(Config.TrailBold, trailStyle == 1); - bold.setMnemonic(Config.TrailBoldMN); - styleGroup = new ButtonGroup(); - styleGroup.add(color); - styleGroup.add(bold); - - debugBox = new JCheckBox(Config.Debug, - sp.getBooleanProperty("SPIDER_DEBUG")); - debugBox.setMnemonic(Config.DebugMN); - - processLabel = new JLabel(Config.Processes, JLabel.CENTER); - processBox = new JComboBox(); - processBox.setEditable(false); - for (int i = 0; i < Config.MAX_PROCESS; i++) - processBox.addItem(" " + (i+1)); - processBox.setSelectedIndex(sp.getIntProperty("PROCESSES")-1); - - variablesLabel = new JLabel(Config.Variables, JLabel.CENTER); - variablesText = new JTextArea(sp.getStringProperty("VARIABLES")); - variablesText.setFont(font); - - runButton = new JButton(Config.Run); - cancelButton = new JButton(Config.Cancel); - runButton.setMnemonic(Config.RunMN); - runButton.addActionListener(this); - cancelButton.addActionListener(this); - - trailPanel = new JPanel(); - trailPanel.setLayout(new java.awt.GridLayout(4,1)); - trailPanel.setBorder(border); - trailPanel.add(noTrail); - trailPanel.add(emphTrail); - trailPanel.add(onlyTrail); - trailPanel.add(automata); - - sizePanel = new JPanel(); - sizePanel.setLayout(new java.awt.GridLayout(3,1)); - sizePanel.setBorder(border); - sizePanel.add(dotLabel); - sizePanel.add(small); - sizePanel.add(large); - - stylePanel = new JPanel(); - stylePanel.setLayout(new java.awt.GridLayout(3,1)); - stylePanel.setBorder(border); - stylePanel.add(styleLabel); - stylePanel.add(color); - stylePanel.add(bold); - - formatPanel = new JPanel(); - formatPanel.setLayout(new java.awt.GridLayout(2,1)); - formatPanel.setBorder(border); - formatPanel.add(formatLabel); - formatPanel.add(formatBox); - - leftPanel = new JPanel(); - leftPanel.setLayout(new java.awt.BorderLayout()); - leftPanel.setBorder(border); - leftPanel.add(formatPanel, java.awt.BorderLayout.NORTH); - leftPanel.add(sizePanel, java.awt.BorderLayout.CENTER); - leftPanel.add(stylePanel, java.awt.BorderLayout.SOUTH); - leftPanel.setPreferredSize(new java.awt.Dimension(100,0)); - - processPanel = new JPanel(); - processPanel.setLayout(new java.awt.GridLayout(2,1)); - processPanel.setBorder(border); - processPanel.add(processLabel); - processPanel.add(processBox); - - boxPanel = new JPanel(); - boxPanel.setLayout(new java.awt.BorderLayout()); - boxPanel.setBorder(border); - boxPanel.add(debugBox, java.awt.BorderLayout.CENTER); - - neverPanel = new JPanel(); - neverPanel.setLayout(new java.awt.BorderLayout()); - neverPanel.setBorder(border); - neverPanel.add(trailPanel, java.awt.BorderLayout.CENTER); - neverPanel.add(processPanel, java.awt.BorderLayout.NORTH); - neverPanel.add(boxPanel, java.awt.BorderLayout.SOUTH); - - variablesPanel = new JPanel(); - variablesPanel.setLayout(new java.awt.BorderLayout()); - variablesPanel.setBorder(border); - variablesPanel.add(variablesLabel, java.awt.BorderLayout.NORTH); - variablesPanel.add(variablesText, java.awt.BorderLayout.CENTER); - - OKPanel = new JPanel(); - OKPanel.setLayout(new java.awt.GridLayout(1,5)); - OKPanel.setBorder(border); - OKPanel.add(new JLabel(" ")); - OKPanel.add(runButton); - OKPanel.add(new JLabel(" ")); - OKPanel.add(cancelButton); - OKPanel.add(new JLabel(" ")); - - getRootPane().setDefaultButton(runButton); - getRootPane().registerKeyboardAction(this, - KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), - JComponent.WHEN_IN_FOCUSED_WINDOW); - - getContentPane().setLayout(new java.awt.BorderLayout()); - getContentPane().add(neverPanel, java.awt.BorderLayout.EAST); - getContentPane().add(variablesPanel, java.awt.BorderLayout.CENTER); - getContentPane().add(leftPanel, java.awt.BorderLayout.WEST); - getContentPane().add(OKPanel, java.awt.BorderLayout.SOUTH); - - setTitle(Config.SPIDER_TITLE); - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - setSize(400, 300); - setLocationRelativeTo(null); - validate(); - } - - boolean showDialog() { - ok = false; - setVisible(true); - return ok; - } - - public void actionPerformed(ActionEvent e) { - if (e.getSource() == runButton) { - sp.setIntProperty("TRAIL_CODE", - noTrail.isSelected() ? 0 : - (emphTrail.isSelected() ? 1 : - (onlyTrail.isSelected() ? 2 : - (automata.isSelected() ? 3 : 0)))); - sp.setIntProperty("DOT_SIZE", - small.isSelected() ? 0 : - (large.isSelected() ? 1 : 0)); - sp.setIntProperty("TRAIL_STYLE", - color.isSelected() ? 0 : - (bold.isSelected() ? 1 : 0)); - sp.setBooleanProperty("SPIDER_DEBUG", debugBox.isSelected()); - sp.setStringProperty("FORMAT", (String) formatBox.getSelectedItem()); - sp.setIntProperty("PROCESSES", Integer.parseInt( - ((String) processBox.getSelectedItem()).trim())); - sp.setStringProperty("VARIABLES", variablesText.getText()); - ok = true; - } - dispose(); - } -} +/* Copyright 2007 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + * Dialog for setting SpinSpider options + */ + +package com.spinroot.jspin; + +import javax.swing.*; +import javax.swing.border.Border; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyEvent; + +class SpiderOptions extends JDialog implements ActionListener { + private JCheckBox debugBox; + private JRadioButton noTrail, emphTrail, onlyTrail, small, large, bold, color, automata; + private ButtonGroup trailGroup, dotGroup, styleGroup; + private JButton runButton, cancelButton; + private JLabel processLabel, variablesLabel, dotLabel, formatLabel, styleLabel; + private JComboBox formatBox, processBox; + private JTextArea variablesText; + private JPanel OKPanel, formatPanel, leftPanel, neverPanel, processPanel, + variablesPanel, trailPanel, sizePanel, boxPanel, stylePanel; + private Border border; + + private boolean ok; + private SpiderFile sp; + + SpiderOptions(JFrame parent, SpiderFile sp, java.awt.Font font) { + super(parent, true); + this.sp = sp; + + border = BorderFactory.createEtchedBorder(); + + formatLabel = new JLabel(Config.Format, JLabel.CENTER); + formatBox = new JComboBox(); + formatBox.setEditable(false); + formatBox.addItem(Config.DOT); + formatBox.addItem(Config.PNG); + formatBox.addItem(Config.FSM); + formatBox.addItem(Config.PS); + formatBox.setSelectedItem(sp.getStringProperty("FORMAT")); + + int trailCode = sp.getIntProperty("TRAIL_CODE"); + noTrail = new JRadioButton(Config.NoTrail, trailCode == 0); + noTrail.setMnemonic(Config.NoTrailMN); + emphTrail = new JRadioButton(Config.EmphTrail, trailCode == 1); + emphTrail.setMnemonic(Config.EmphTrailMN); + onlyTrail = new JRadioButton(Config.OnlyTrail, trailCode == 2); + onlyTrail.setMnemonic(Config.OnlyTrailMN); + automata = new JRadioButton(Config.Automata, trailCode == 3); + automata.setMnemonic(Config.AutomataMN); + trailGroup = new ButtonGroup(); + trailGroup.add(noTrail); + trailGroup.add(emphTrail); + trailGroup.add(onlyTrail); + trailGroup.add(automata); + + dotLabel = new JLabel(Config.DotSize, JLabel.CENTER); + int dotSize = sp.getIntProperty("DOT_SIZE"); + small = new JRadioButton(Config.DotSmall, dotSize == 0); + small.setMnemonic(Config.DotSmallMN); + large = new JRadioButton(Config.DotLarge, dotSize == 1); + large.setMnemonic(Config.DotLargeMN); + dotGroup = new ButtonGroup(); + dotGroup.add(small); + dotGroup.add(large); + + styleLabel = new JLabel(Config.TrailStyle, JLabel.CENTER); + int trailStyle = sp.getIntProperty("TRAIL_STYLE"); + color = new JRadioButton(Config.TrailColor, trailStyle == 0); + color.setMnemonic(Config.TrailColorMN); + bold = new JRadioButton(Config.TrailBold, trailStyle == 1); + bold.setMnemonic(Config.TrailBoldMN); + styleGroup = new ButtonGroup(); + styleGroup.add(color); + styleGroup.add(bold); + + debugBox = new JCheckBox(Config.Debug, + sp.getBooleanProperty("SPIDER_DEBUG")); + debugBox.setMnemonic(Config.DebugMN); + + processLabel = new JLabel(Config.Processes, JLabel.CENTER); + processBox = new JComboBox(); + processBox.setEditable(false); + for (int i = 0; i < Config.MAX_PROCESS; i++) + processBox.addItem(" " + (i + 1)); + processBox.setSelectedIndex(sp.getIntProperty("PROCESSES") - 1); + + variablesLabel = new JLabel(Config.Variables, JLabel.CENTER); + variablesText = new JTextArea(sp.getStringProperty("VARIABLES")); + variablesText.setFont(font); + + runButton = new JButton(Config.Run); + cancelButton = new JButton(Config.Cancel); + runButton.setMnemonic(Config.RunMN); + runButton.addActionListener(this); + cancelButton.addActionListener(this); + + trailPanel = new JPanel(); + trailPanel.setLayout(new java.awt.GridLayout(4, 1)); + trailPanel.setBorder(border); + trailPanel.add(noTrail); + trailPanel.add(emphTrail); + trailPanel.add(onlyTrail); + trailPanel.add(automata); + + sizePanel = new JPanel(); + sizePanel.setLayout(new java.awt.GridLayout(3, 1)); + sizePanel.setBorder(border); + sizePanel.add(dotLabel); + sizePanel.add(small); + sizePanel.add(large); + + stylePanel = new JPanel(); + stylePanel.setLayout(new java.awt.GridLayout(3, 1)); + stylePanel.setBorder(border); + stylePanel.add(styleLabel); + stylePanel.add(color); + stylePanel.add(bold); + + formatPanel = new JPanel(); + formatPanel.setLayout(new java.awt.GridLayout(2, 1)); + formatPanel.setBorder(border); + formatPanel.add(formatLabel); + formatPanel.add(formatBox); + + leftPanel = new JPanel(); + leftPanel.setLayout(new java.awt.BorderLayout()); + leftPanel.setBorder(border); + leftPanel.add(formatPanel, java.awt.BorderLayout.NORTH); + leftPanel.add(sizePanel, java.awt.BorderLayout.CENTER); + leftPanel.add(stylePanel, java.awt.BorderLayout.SOUTH); + leftPanel.setPreferredSize(new java.awt.Dimension(100, 0)); + + processPanel = new JPanel(); + processPanel.setLayout(new java.awt.GridLayout(2, 1)); + processPanel.setBorder(border); + processPanel.add(processLabel); + processPanel.add(processBox); + + boxPanel = new JPanel(); + boxPanel.setLayout(new java.awt.BorderLayout()); + boxPanel.setBorder(border); + boxPanel.add(debugBox, java.awt.BorderLayout.CENTER); + + neverPanel = new JPanel(); + neverPanel.setLayout(new java.awt.BorderLayout()); + neverPanel.setBorder(border); + neverPanel.add(trailPanel, java.awt.BorderLayout.CENTER); + neverPanel.add(processPanel, java.awt.BorderLayout.NORTH); + neverPanel.add(boxPanel, java.awt.BorderLayout.SOUTH); + + variablesPanel = new JPanel(); + variablesPanel.setLayout(new java.awt.BorderLayout()); + variablesPanel.setBorder(border); + variablesPanel.add(variablesLabel, java.awt.BorderLayout.NORTH); + variablesPanel.add(variablesText, java.awt.BorderLayout.CENTER); + + OKPanel = new JPanel(); + OKPanel.setLayout(new java.awt.GridLayout(1, 5)); + OKPanel.setBorder(border); + OKPanel.add(new JLabel(" ")); + OKPanel.add(runButton); + OKPanel.add(new JLabel(" ")); + OKPanel.add(cancelButton); + OKPanel.add(new JLabel(" ")); + + getRootPane().setDefaultButton(runButton); + getRootPane().registerKeyboardAction(this, + KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), + JComponent.WHEN_IN_FOCUSED_WINDOW); + + getContentPane().setLayout(new java.awt.BorderLayout()); + getContentPane().add(neverPanel, java.awt.BorderLayout.EAST); + getContentPane().add(variablesPanel, java.awt.BorderLayout.CENTER); + getContentPane().add(leftPanel, java.awt.BorderLayout.WEST); + getContentPane().add(OKPanel, java.awt.BorderLayout.SOUTH); + + setTitle(Config.SPIDER_TITLE); + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + setSize(400, 300); + setLocationRelativeTo(null); + validate(); + } + + boolean showDialog() { + ok = false; + setVisible(true); + return ok; + } + + public void actionPerformed(ActionEvent e) { + if (e.getSource() == runButton) { + sp.setIntProperty("TRAIL_CODE", + noTrail.isSelected() ? 0 : + (emphTrail.isSelected() ? 1 : + (onlyTrail.isSelected() ? 2 : + (automata.isSelected() ? 3 : 0)))); + sp.setIntProperty("DOT_SIZE", + small.isSelected() ? 0 : + (large.isSelected() ? 1 : 0)); + sp.setIntProperty("TRAIL_STYLE", + color.isSelected() ? 0 : + (bold.isSelected() ? 1 : 0)); + sp.setBooleanProperty("SPIDER_DEBUG", debugBox.isSelected()); + sp.setStringProperty("FORMAT", (String) formatBox.getSelectedItem()); + sp.setIntProperty("PROCESSES", Integer.parseInt( + ((String) processBox.getSelectedItem()).trim())); + sp.setStringProperty("VARIABLES", variablesText.getText()); + ok = true; + } + dispose(); + } +} diff --git a/jspin/UndoRedo.java b/src/main/java/com/spinroot/jspin/UndoRedo.java similarity index 87% rename from jspin/UndoRedo.java rename to src/main/java/com/spinroot/jspin/UndoRedo.java index 3d1c47e..0cfdb20 100644 --- a/jspin/UndoRedo.java +++ b/src/main/java/com/spinroot/jspin/UndoRedo.java @@ -1,83 +1,88 @@ -/* Copyright 2003-4 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ -/* - Class for undo/redo. - Extracted from TextComponentDemo.java in java.sun.com. -*/ -package jspin; -import javax.swing.*; -import javax.swing.undo.*; -import javax.swing.event.*; -import java.awt.event.*; -class UndoRedo { - UndoAction undoAction = new UndoAction(); - RedoAction redoAction = new RedoAction(); - UndoManager undo = new UndoManager(); - MyUndoableEditListener myundoable = new MyUndoableEditListener(); - - class UndoAction extends AbstractAction { - public UndoAction() { - super(Config.Undo); - setEnabled(false); - } - - public void actionPerformed(ActionEvent e) { - try { - undo.undo(); - } catch (CannotUndoException ex) { - System.out.println("Unable to undo: " + ex); - ex.printStackTrace(); - } - updateUndoState(); - redoAction.updateRedoState(); - } - - protected void updateUndoState() { - if (undo.canUndo()) { - setEnabled(true); - putValue(Action.NAME, undo.getUndoPresentationName()); - } else { - setEnabled(false); - putValue(Action.NAME, "Undo"); - } - } - } - - class RedoAction extends AbstractAction { - public RedoAction() { - super(Config.Redo); - setEnabled(false); - } - - public void actionPerformed(ActionEvent e) { - try { - undo.redo(); - } catch (CannotRedoException ex) { - System.out.println("Unable to redo: " + ex); - ex.printStackTrace(); - } - updateRedoState(); - undoAction.updateUndoState(); - } - - protected void updateRedoState() { - if (undo.canRedo()) { - setEnabled(true); - putValue(Action.NAME, undo.getRedoPresentationName()); - } else { - setEnabled(false); - putValue(Action.NAME, "Redo"); - } - } - } - - protected class MyUndoableEditListener - implements UndoableEditListener { - public void undoableEditHappened(UndoableEditEvent e) { - //Remember the edit and update the menus. - undo.addEdit(e.getEdit()); - undoAction.updateUndoState(); - redoAction.updateRedoState(); - } - } - -} +/* Copyright 2003-4 by Mordechai (Moti) Ben-Ari. See copyright.txt. */ +/* + Class for undo/redo. + Extracted from TextComponentDemo.java in java.sun.com. +*/ +package com.spinroot.jspin; + +import javax.swing.*; +import javax.swing.event.UndoableEditEvent; +import javax.swing.event.UndoableEditListener; +import javax.swing.undo.CannotRedoException; +import javax.swing.undo.CannotUndoException; +import javax.swing.undo.UndoManager; +import java.awt.event.ActionEvent; + +class UndoRedo { + UndoAction undoAction = new UndoAction(); + RedoAction redoAction = new RedoAction(); + UndoManager undo = new UndoManager(); + MyUndoableEditListener myundoable = new MyUndoableEditListener(); + + class UndoAction extends AbstractAction { + public UndoAction() { + super(Config.Undo); + setEnabled(false); + } + + public void actionPerformed(ActionEvent e) { + try { + undo.undo(); + } catch (CannotUndoException ex) { + System.out.println("Unable to undo: " + ex); + ex.printStackTrace(); + } + updateUndoState(); + redoAction.updateRedoState(); + } + + protected void updateUndoState() { + if (undo.canUndo()) { + setEnabled(true); + putValue(Action.NAME, undo.getUndoPresentationName()); + } else { + setEnabled(false); + putValue(Action.NAME, "Undo"); + } + } + } + + class RedoAction extends AbstractAction { + public RedoAction() { + super(Config.Redo); + setEnabled(false); + } + + public void actionPerformed(ActionEvent e) { + try { + undo.redo(); + } catch (CannotRedoException ex) { + System.out.println("Unable to redo: " + ex); + ex.printStackTrace(); + } + updateRedoState(); + undoAction.updateUndoState(); + } + + protected void updateRedoState() { + if (undo.canRedo()) { + setEnabled(true); + putValue(Action.NAME, undo.getRedoPresentationName()); + } else { + setEnabled(false); + putValue(Action.NAME, "Redo"); + } + } + } + + protected class MyUndoableEditListener + implements UndoableEditListener { + public void undoableEditHappened(UndoableEditEvent e) { + //Remember the edit and update the menus. + undo.addEdit(e.getEdit()); + undoAction.updateUndoState(); + redoAction.updateRedoState(); + } + } + +} diff --git a/jspin/jSpin.java b/src/main/java/com/spinroot/jspin/jSpin.java similarity index 66% rename from jspin/jSpin.java rename to src/main/java/com/spinroot/jspin/jSpin.java index 7e9f2a2..05943c9 100644 --- a/jspin/jSpin.java +++ b/src/main/java/com/spinroot/jspin/jSpin.java @@ -1,836 +1,818 @@ -/* - jSpin - Development environment for Spin - Copyright 2003-10 by Mordechai (Moti) Ben-Ari. - -This program 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. -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. -*/ - -package jspin; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.border.*; - -public class jSpin extends JFrame implements ActionListener { - // Contained objects. Create only after initializing configuration. - private Editor editor; - private RunSpin runSpin; - private filterSpin.Filter filter; - private UndoRedo undoredo; - private SpiderFile sp; - private java.util.Properties spiderProperties; - - // User interface components - private JTextArea editorArea = new JTextArea(); - private JTextArea trailArea = new JTextArea(); - private JTextArea messageArea = new JTextArea(); - private JTextField LTLField = new JTextField(); - - private JFileChooser PMLfileChooser; - private JFileChooser PRPfileChooser; - private JFileChooser OUTfileChooser; - private java.awt.Font font; - - private JScrollPane editorScrollPane = new JScrollPane(editorArea); - private JScrollPane trailScrollPane = new JScrollPane(trailArea); - private JScrollPane messageScrollPane = new JScrollPane(messageArea); - private JSplitPane topSplitPane; - private JSplitPane mainSplitPane; - - private JMenuBar menuBar = new JMenuBar(); - - private JMenu menuFile = new JMenu(); - private JMenuItem menuItemNew = new JMenuItem(Config.New); - private JMenuItem menuItemOpen = new JMenuItem(Config.Open); - private JMenuItem menuItemSave = new JMenuItem(Config.Save); - private JMenuItem menuItemSaveAs = new JMenuItem(Config.SaveAs); - private JMenuItem menuItemSwitch = new JMenuItem(Config.Switch); - private JMenuItem menuItemExit = new JMenuItem(Config.Exit); - - private JMenu menuEditor = new JMenu(); - private JMenuItem menuItemCopy = new JMenuItem(Config.Copy); - private JMenuItem menuItemCut = new JMenuItem(Config.Cut); - private JMenuItem menuItemPaste = new JMenuItem(Config.Paste); - private JMenuItem menuItemFind = new JMenuItem(Config.Find); - private JMenuItem menuItemFindAgain = new JMenuItem(Config.FindAgain); - - private JMenu menuSpin = new JMenu(); - private JMenuItem menuItemCheck = new JMenuItem(Config.Check); - private JMenuItem menuItemRandom = new JMenuItem(Config.Random); - private JMenuItem menuItemInter = new JMenuItem(Config.Inter); - private JMenuItem menuItemVerify = new JMenuItem(Config.Verify); - private JMenuItem menuItemTrail = new JMenuItem(Config.Trail); - private JMenuItem menuItemStop = new JMenuItem(Config.Stop); - - private JMenu menuLTLConvert = new JMenu(); - private JMenuItem menuItemTranslate = new JMenuItem(Config.LTLTranslate); - private JMenuItem menuItemClear = new JMenuItem(Config.LTLClear); - private JMenuItem menuItemLoad = new JMenuItem(Config.LTLLoad); - private JMenuItem menuItemName = new JMenuItem(Config.LTLName); - private boolean ltlInternal; - - private JMenu menuOptions = new JMenu(); - private JMenuItem menuItemOptionsCheck = new JMenuItem(Config.Check); - private JMenuItem menuItemOptionsCommon = new JMenuItem(Config.Common); - private JMenuItem menuItemOptionsRandom = new JMenuItem(Config.Random); - private JMenuItem menuItemOptionsInter = new JMenuItem(Config.Inter); - private JMenuItem menuItemOptionsVerify = new JMenuItem(Config.Verify); - private JMenuItem menuItemOptionsC = new JMenuItem(Config.OptionsC); - private JMenuItem menuItemOptionsPan = new JMenuItem(Config.OptionsPan); - private JMenuItem menuItemOptionsTrail = new JMenuItem(Config.Trail); - private JMenuItem menuItemDefault = new JMenuItem(Config.Default); - private JMenuItem menuItemOptionsSaveInstall = new JMenuItem(Config.SaveInstall); - private JMenuItem menuItemOptionsSaveCurrent = new JMenuItem(Config.SaveCurrent); - - private JMenu menuSettings = new JMenu(); - private JMenuItem menuItemMaxSteps = new JMenuItem(Config.MaxSteps); - private JMenuItem menuItemMaxDepth = new JMenuItem(Config.MaxDepth); - private JMenuItem menuItemSeed = new JMenuItem(Config.Seed); - private JCheckBoxMenuItem menuItemNegate = new JCheckBoxMenuItem(Config.Negate); - private JCheckBoxMenuItem menuItemFair = new JCheckBoxMenuItem(Config.Fair); - private JRadioButtonMenuItem menuItemSafety = new JRadioButtonMenuItem(Config.Safety, false); - private JRadioButtonMenuItem menuItemAcceptance = new JRadioButtonMenuItem(Config.Acceptance, false); - private JRadioButtonMenuItem menuItemNonProgress = new JRadioButtonMenuItem(Config.NonProgress, false); - private ButtonGroup buttonGroup = new ButtonGroup(); - - private JMenu menuOutput = new JMenu(); - private JMenuItem menuItemMax = new JMenuItem(Config.Max); - private JMenuItem menuItemVarWidth = new JMenuItem(Config.VarWidth); - private JMenuItem menuItemStWidth = new JMenuItem(Config.StWidth); - private JMenuItem menuItemExcludedV = new JMenuItem(Config.ExcludedV); - private JMenuItem menuItemExcludedS = new JMenuItem(Config.ExcludedS); - private JCheckBoxMenuItem menuItemRaw = new JCheckBoxMenuItem(Config.Raw); - private JMenuItem menuItemDisplayRaw = new JMenuItem(Config.DisplayRaw); - private JMenuItem menuItemSaveSpin = new JMenuItem(Config.SaveSpin); - - private JMenu menuSpider = new JMenu(); - private JMenuItem menuItemSpider = new JMenuItem(Config.Spider); - private JMenuItem menuItemSpiderDisplay = new JMenuItem(Config.SpiderDisplay); - - private JMenu menuHelp = new JMenu(); - private JMenuItem menuItemHelp = new JMenuItem(Config.Help); - private JMenuItem menuItemAbout = new JMenuItem(Config.About); - - private JToolBar toolBar = new JToolBar(); - - private JButton toolOpen = new JButton(Config.Open); - private JButton toolCheck = new JButton(Config.Check); - private JButton toolRandom = new JButton(Config.Random); - private JButton toolInter = new JButton(Config.Inter); - private JButton toolVerify = new JButton(Config.Verify); - private JButton toolTrail = new JButton(Config.Trail); - private JButton toolStop = new JButton(Config.Stop); - - private JButton toolSpider = new JButton(Config.Spider); - - private JLabel toolLabelFair = new JLabel(Config.Fair); - private JCheckBox toolCheckFair = new JCheckBox(); - private JComboBox toolMode = new JComboBox(); - private JButton toolMax = new JButton(Config.Max); - private boolean maxedDivider; - private int currentDivider; - - private JLabel LTLLabel = new JLabel(Config.LTLFormula); - private JButton LTLTranslateButton = new JButton(Config.LTLTranslate); - private JButton LTLClearButton = new JButton(Config.LTLClear); - private JButton LTLLoadButton = new JButton(Config.LTLLoad); - private JButton LTLNameButton = new JButton(Config.LTLName); - - public void actionPerformed(ActionEvent e) { - // File menu actions - if (e.getSource() == menuItemNew) { - editor.lastFile = editor.file; - clearAreas(); - editor.newFile(); - } - else if ((e.getSource() == menuItemOpen) || (e.getSource() == toolOpen)) { - if(PMLfileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - editor.lastFile = editor.file; - clearAreas(); - editor.openFile(PMLfileChooser.getSelectedFile(), true); - } - } - else if (e.getSource() == menuItemSave) { - if (editor.file != null) - editor.saveFile(null); - else { - if(PMLfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { - editor.saveFile(PMLfileChooser.getSelectedFile()); - } - } - } - else if (e.getSource() == menuItemSaveAs) { - if(PMLfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) - editor.lastFile = editor.file; - editor.saveFile(PMLfileChooser.getSelectedFile()); - } - else if (e.getSource() == menuItemSwitch) { - if (editor.lastFile != null) { - java.io.File temp = editor.lastFile; - if (editor.file != null) - editor.saveFile(null); - else { - if(PMLfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { - editor.saveFile(PMLfileChooser.getSelectedFile()); - } - } - editor.lastFile = editor.file; - editor.openFile(temp, true); - } - } - else if (e.getSource() == menuItemExit) { - runSpin.killSpin(); - System.exit(0); - } - - // Editor menu actions - else if (e.getSource() == menuItemCut) - editor.cut(); - else if (e.getSource() == menuItemCopy) - editor.copy(); - else if (e.getSource() == menuItemPaste) - editor.paste(); - else if (e.getSource() == menuItemFind) - editor.find(); - else if (e.getSource() == menuItemFindAgain) - editor.findAgain(); - - // Spin menu actions - else if ((e.getSource() == menuItemCheck) || (e.getSource() == toolCheck)) { - trailArea.setText(""); - runSpin.runAndWait(trailArea, false, - Config.getStringProperty("SPIN"), - Config.getStringProperty("CHECK_OPTIONS") + " " + - editor.fileName); - } - else if ((e.getSource() == menuItemRandom) || (e.getSource() == toolRandom)) { - int seed = Config.getIntProperty("SEED"); - trailArea.setText(""); - runSpin.run(trailArea, true, - Config.getStringProperty("SPIN"), - Config.getStringProperty("COMMON_OPTIONS") + " " + - Config.getStringProperty("RANDOM_OPTIONS") + " " + - (seed != 0 ? ("-n" + seed + " ") : "") + - " -u" + Config.getStringProperty("MAX_STEPS") + " " + - editor.fileName); - isSpinRunning(); - } - else if ((e.getSource() == menuItemInter) || (e.getSource() == toolInter)) { - trailArea.setText(""); - runSpin.run(trailArea, true, - Config.getStringProperty("SPIN"), - Config.getStringProperty("COMMON_OPTIONS") + " " + - Config.getStringProperty("INTERACTIVE_OPTIONS") + " " + - editor.fileName); - isSpinRunning(); - } - else if ((e.getSource() == menuItemVerify) || (e.getSource() == toolVerify)) { - trailArea.setText(""); - if (!ltlInternal && !LTLField.getText().equals("") && - !(new java.io.File(editor.LTLFileName).exists())) - append(messageArea, "WARNING: Correctness property has not been translated\n"); - runSpin.runAndWait(trailArea, false, - Config.getStringProperty("SPIN"), - Config.getStringProperty("VERIFY_OPTIONS") + " " + - ((ltlInternal || LTLField.getText().equals("")) ? "" : "-N " + " " + - editor.LTLFileName + " ") + editor.fileName); - if (trailArea.getText().indexOf("Error: syntax error") != -1) - return; - String mode = Config.getStringProperty("VERIFY_MODE"); - String CModeOptions = mode.equals(Config.Safety) ? " -DSAFETY " : - (mode.equals(Config.NonProgress) ? " -DNP " : ""); - runSpin.runAndWait(messageArea, false, - Config.getStringProperty("C_COMPILER"), - CModeOptions + " " + - Config.getStringProperty("C_COMPILER_OPTIONS") ); - String panModeOptions = mode.equals(Config.Acceptance) ? " -a " : - (mode.equals(Config.NonProgress) ? " -l " : ""); - if (!mode.equals(Config.Safety) && Config.getBooleanProperty("FAIRNESS")) - panModeOptions = " -f " + panModeOptions; - runSpin.run(trailArea, true, - editor.root + java.io.File.separator + - Config.getStringProperty("PAN"), - panModeOptions + - " -m" + Config.getStringProperty("MAX_DEPTH") + " " + - ((!ltlInternal || LTLField.getText().equals("")) ? - "" : "-N " + LTLField.getText() + " ") + - Config.getStringProperty("PAN_OPTIONS") ); - isSpinRunning(); - } - else if ((e.getSource() == menuItemTrail) || (e.getSource() == toolTrail)) { - runSpin.run(trailArea, true, - Config.getStringProperty("SPIN"), - Config.getStringProperty("COMMON_OPTIONS") + " " + - Config.getStringProperty("TRAIL_OPTIONS") + - " -u" + Config.getStringProperty("MAX_STEPS") + " " + - editor.fileName); - isSpinRunning(); - } - else if ((e.getSource() == menuItemStop) || (e.getSource() == toolStop)) - runSpin.killSpin(); - - // Options menu actions - else if (e.getSource() == menuItemOptionsCommon) - new Options(); - else if ((e.getSource() == menuItemOptionsCheck) || - (e.getSource() == menuItemOptionsRandom) || - (e.getSource() == menuItemOptionsInter) || - (e.getSource() == menuItemOptionsVerify) || - (e.getSource() == menuItemOptionsC) || - (e.getSource() == menuItemOptionsPan) || - (e.getSource() == menuItemOptionsTrail)) - changeOption(e.getActionCommand().toUpperCase().replace(' ','_') + "_OPTIONS", false); - else if (e.getSource() == menuItemDefault) - Config.setDefaultProperties(); - - else if ((e.getSource() == menuItemOptionsSaveInstall) || - (e.getSource() == menuItemOptionsSaveCurrent)) { - // Save current directory and divider locations - Config.setStringProperty("SOURCE_DIRECTORY", - PMLfileChooser.getCurrentDirectory().getAbsolutePath()); - Config.setIntProperty("LR_DIVIDER", topSplitPane.getDividerLocation()); - Config.setIntProperty("TB_DIVIDER", mainSplitPane.getDividerLocation()); - boolean currentConfig = e.getSource() == menuItemOptionsSaveCurrent; - Config.saveFile(currentConfig); - append(messageArea, - "Saved jSpin configuration file config.cfg in " + - (currentConfig ? "current" : "installation") + " directory\n"); - } - - // Settings menu actions - else if (e.getSource() == menuItemMaxSteps) - changeOption("MAX_STEPS", true); - else if (e.getSource() == menuItemMaxDepth) - changeOption("MAX_DEPTH", true); - else if (e.getSource() == menuItemSeed) - changeOption("SEED", true); - else if (e.getSource() == menuItemNegate) { - boolean negate = !Config.getBooleanProperty("NEGATE_LTL"); - Config.setBooleanProperty("NEGATE_LTL", negate); - menuItemNegate.setSelected(negate); - } - else if ((e.getSource() == menuItemFair) || (e.getSource() == toolCheckFair)) { - boolean fair = !Config.getBooleanProperty("FAIRNESS"); - Config.setBooleanProperty("FAIRNESS", fair); - menuItemFair.setSelected(fair); - toolCheckFair.setSelected(fair); - } - else if ((e.getSource() == menuItemSafety) || - (e.getSource() == menuItemAcceptance) || - (e.getSource() == menuItemNonProgress)) - changeMode(e.getActionCommand()); - else if (e.getSource() == toolMode) - changeMode(((String)((JComboBox)e.getSource()).getSelectedItem())); - - // Output menu actions - else if ((e.getSource() == menuItemMax) || - (e.getSource() == toolMax)) { - if (maxedDivider) - topSplitPane.setDividerLocation(currentDivider); - else { - currentDivider = topSplitPane.getDividerLocation(); - topSplitPane.setDividerLocation(Config.getIntProperty("MIN_DIVIDER")); - } - maxedDivider = ! maxedDivider; - } - else if (e.getSource() == menuItemExcludedV) - new Excluded(editor, font, filter, true); - else if (e.getSource() == menuItemExcludedS) - new Excluded(editor, font, filter, false); - else if (e.getSource() == menuItemStWidth) - changeOption("STATEMENT_WIDTH", true); - else if (e.getSource() == menuItemVarWidth) - changeOption("VARIABLE_WIDTH", true); - else if (e.getSource() == menuItemSaveSpin) { - java.io.File outFile = new java.io.File(editor.OUTFileName); - OUTfileChooser.setSelectedFile(outFile); - if(OUTfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) - editor.writeFile(OUTfileChooser.getSelectedFile(), trailArea); - } - else if (e.getSource() == menuItemRaw) { - boolean raw = !Config.getBooleanProperty("RAW"); - Config.setBooleanProperty("RAW", raw); - menuItemRaw.setSelected(raw); - } - else if (e.getSource() == menuItemDisplayRaw) - displayFile(editor.root + java.io.File.separator + editor.fileRoot + ".raw"); - - // Spider menu actions - else if ((e.getSource() == menuItemSpider) || (e.getSource() == toolSpider)) { - if (editor.file == null) { - jSpin.append(messageArea, Config.OPEN_FILE); - return; - } - // Read Spider properties from the file for this program - sp = new SpiderFile(spiderProperties, - editor.root + java.io.File.separator + editor.fileRoot); - sp.init(); - if (new SpiderOptions(this, sp, font).showDialog()) { - sp.saveFile(); - new Thread() { // Run in thread to display progress - public void run() { - spinSpider.SpinSpider spd = - new spinSpider.SpinSpider( - editor.root + java.io.File.separator + editor.fileRoot, - editor.extension, - sp.getStringProperty("FORMAT"), - sp.getIntProperty("PROCESSES"), - stringToArray(sp.getStringProperty("VARIABLES")), - sp.getBooleanProperty("SPIDER_DEBUG"), - sp.getIntProperty("TRAIL_CODE"), - sp.getIntProperty("DOT_SIZE"), - sp.getIntProperty("TRAIL_STYLE"), - messageArea, - Config.getProperties()); - if (!spd.runSpider()) return; - // If PNG format, display in a frame - if (sp.getStringProperty("FORMAT").equals(Config.PNG)) { - // Draw automata if requested - if (sp.getIntProperty("TRAIL_CODE") == 3) - new spinSpider.DrawAutomata(spd).drawAutomata(); - new DisplayImage(editor.root + java.io.File.separator + editor.fileRoot + - spinSpider.Config.names[sp.getIntProperty("TRAIL_CODE")] + ".png"); - } - } - }.start(); - } - } - else if (e.getSource() == menuItemSpiderDisplay) - displayFile(editor.root + java.io.File.separator + editor.fileRoot + ".dbg"); - - // Help menu actions - else if (e.getSource() == menuItemHelp) - displayFile(Config.helpFileName); - else if (e.getSource() == menuItemAbout) - displayFile(Config.aboutFileName); - - // LTL actions - else if ((e.getSource() == LTLTranslateButton) || (e.getSource() == menuItemTranslate)) { - editor.modifiedLTL(); - if (LTLField.getText().equals("")) - return; - ltlInternal = false; - String quote = Config.getBooleanProperty("SINGLE_QUOTE") ? "'" : "\""; - String negate = Config.getBooleanProperty("NEGATE_LTL") ? "!" : ""; - runSpin.runAndWait(trailArea, false, - Config.getStringProperty("SPIN"), - Config.getStringProperty("TRANSLATE_OPTIONS") + " " + - quote + negate + "(" + LTLField.getText() + ")" + quote ); - editor.writeFile(new java.io.File(editor.LTLFileName), trailArea); - } - else if ((e.getSource() == LTLClearButton) || (e.getSource() == menuItemClear)) { - LTLField.setText(""); - menuBar.revalidate(); - } - else if ((e.getSource() == LTLLoadButton) || (e.getSource() == menuItemLoad)) { - PRPfileChooser.setCurrentDirectory( - PMLfileChooser.getCurrentDirectory()); - if(PRPfileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { - editor.openFile(PRPfileChooser.getSelectedFile(), false); - } - } - else if ((e.getSource() == LTLNameButton) || (e.getSource() == menuItemName)) { - ltlInternal = true; - } - if (editor != null) editor.focus(false); - } - - // Display the contents of a file in the trail area - private void displayFile(String fn) { - trailArea.setText(editor.readFile(new java.io.File(fn))); - trailArea.setCaretPosition(0); - } - - // Convert String to array of Strings - private static String[] stringToArray(String s) { - java.util.StringTokenizer st = new java.util.StringTokenizer(s); - int count = st.countTokens(); - String[] sa = new String[count]; - for (int i = 0; i < count; i++) - sa[i] = st.nextToken(); - return sa; - } - - // Append and move caret to end - public static void append(JTextArea area, String s) { - if (s != null) area.append(s); - int last = area.getText().length(); - try { - area.scrollRectToVisible(area.modelToView(last)); - area.setCaretPosition(last); - } - catch (javax.swing.text.BadLocationException e) { - System.err.println("Error setting caret position when writing\n" + s + "\n"); - } - } - - // Clear all areas before opening file or creating new file - private void clearAreas() { - messageArea.setText(""); - trailArea.setText(""); - LTLField.setText(""); - } - - // Change verification mode: - // radio buttons in menu, combo box in toolbar and properties - private void changeMode(String mode) { - toolMode.setSelectedItem(mode); - if (mode.equals(Config.Safety)) - menuItemSafety.setSelected(true); - else if (mode.equals(Config.Acceptance)) - menuItemAcceptance.setSelected(true); - else if (mode.equals(Config.NonProgress)) - menuItemNonProgress.setSelected(true); - Config.setStringProperty("VERIFY_MODE", mode); - } - - // Display an option pane to edit an option string - private void changeOption(String property, boolean number) { - String s = Config.getStringProperty(property); - String answer = JOptionPane.showInputDialog(property, s); - if (answer == null) return; - if (!number || (number && checkInt(answer))) - Config.setStringProperty(property, answer); - else - JOptionPane.showMessageDialog(null, - answer + " is not an integer", "Format error", - JOptionPane.ERROR_MESSAGE); - } - - // Some option panes need to be positive integers - private boolean checkInt(String property) { - try { - Integer.parseInt(property); - return true; - } - catch (NumberFormatException e) { - return false; - } - } - - // Create a thread to check if Spin is running - // Enables user interface to continue running and press Stop - void isSpinRunning() { - Thread th = new Thread () { - public void run() { - while (runSpin.isRunning()) { - try { - Thread.sleep(Config.getIntProperty("POLLING_DELAY")); - } catch (InterruptedException e) {} - } - append(messageArea, "done!\n"); - } - }; - th.start(); - } - - // Initialize menus - private void initMenuItem( - JMenu menu, JMenuItem item, int mnemonic, String accelerator) { - menu.add(item); - item.addActionListener(this); - item.setMnemonic(mnemonic); - if (accelerator != null) - item.setAccelerator(KeyStroke.getKeyStroke(accelerator)); - } - - private void initMenus() { - menuBar.setBorder(new LineBorder(java.awt.Color.BLUE)); - - menuBar.add(menuFile); - menuFile.setText(Config.File); - menuFile.setMnemonic(Config.FileMN); - initMenuItem(menuFile, menuItemNew, Config.NewMN, Config.NewAC); - initMenuItem(menuFile, menuItemOpen, Config.OpenMN, Config.OpenAC); - initMenuItem(menuFile, menuItemSave, Config.SaveMN, Config.SaveAC); - initMenuItem(menuFile, menuItemSaveAs, Config.SaveAsMN, Config.SaveAsAC); - menuFile.addSeparator(); - initMenuItem(menuFile, menuItemSwitch, Config.SwitchMN, Config.SwitchAC); - menuFile.addSeparator(); - initMenuItem(menuFile, menuItemExit, Config.ExitMN, Config.ExitAC); - - undoredo = new UndoRedo(); - menuBar.add(menuEditor); - menuEditor.setText(Config.Editor); - menuEditor.setMnemonic(Config.EditorMN); - JMenuItem menuItemUndo = menuEditor.add(undoredo.undoAction); - JMenuItem menuItemRedo = menuEditor.add(undoredo.redoAction); - initMenuItem(menuEditor, menuItemUndo, Config.UndoMN, Config.UndoAC); - initMenuItem(menuEditor, menuItemRedo, Config.RedoMN, Config.RedoAC); - menuEditor.addSeparator(); - initMenuItem(menuEditor, menuItemCopy, Config.CopyMN, Config.CopyAC); - initMenuItem(menuEditor, menuItemCut, Config.CutMN, Config.CutAC); - initMenuItem(menuEditor, menuItemPaste, Config.PasteMN, Config.PasteAC); - menuEditor.addSeparator(); - initMenuItem(menuEditor, menuItemFind, Config.FindMN, Config.FindAC); - initMenuItem(menuEditor, menuItemFindAgain, Config.FindAgainMN, Config.FindAgainAC); - - menuBar.add(menuSpin); - menuSpin.setText(Config.Spin); - menuSpin.setMnemonic(Config.SpinMN); - initMenuItem(menuSpin, menuItemCheck, Config.CheckMN, Config.CheckAC); - menuSpin.addSeparator(); - initMenuItem(menuSpin, menuItemRandom, Config.RandomMN, Config.RandomAC); - initMenuItem(menuSpin, menuItemInter, Config.InterMN, Config.InterAC); - initMenuItem(menuSpin, menuItemTrail, Config.TrailMN, Config.TrailAC); - menuSpin.addSeparator(); - initMenuItem(menuSpin, menuItemVerify, Config.VerifyMN, Config.VerifyAC); - initMenuItem(menuSpin, menuItemStop, Config.StopMN, Config.StopAC); - - menuBar.add(menuLTLConvert); - menuLTLConvert.setText(Config.LTLConvert); - menuLTLConvert.setMnemonic(Config.LTLConvertMN); - initMenuItem(menuLTLConvert, menuItemTranslate, Config.LTLTranslateMN, Config.LTLTranslateAC); - initMenuItem(menuLTLConvert, menuItemClear, Config.LTLClearMN, Config.LTLClearAC); - initMenuItem(menuLTLConvert, menuItemLoad, Config.LTLLoadMN, Config.LTLLoadAC); - if (Config.getIntProperty("VERSION") >= 6) { - menuLTLConvert.addSeparator(); - initMenuItem(menuLTLConvert, menuItemName, Config.LTLName1MN, Config.LTLNameAC); - } - - menuBar.add(menuOptions); - menuOptions.setText(Config.Options); - menuOptions.setMnemonic(Config.OptionsMN); - initMenuItem(menuOptions, menuItemOptionsCommon, Config.CommonMN, Config.CommonAC); - menuOptions.addSeparator(); - initMenuItem(menuOptions, menuItemOptionsCheck, Config.CheckMN, Config.CheckAC); - initMenuItem(menuOptions, menuItemOptionsRandom, Config.RandomMN, Config.OptionsRandomAC); - initMenuItem(menuOptions, menuItemOptionsInter, Config.InterMN, Config.OptionsInterAC); - initMenuItem(menuOptions, menuItemOptionsVerify, Config.VerifyMN, Config.VerifyAC); - initMenuItem(menuOptions, menuItemOptionsC, Config.OptionsCMN, Config.OptionsCAC); - initMenuItem(menuOptions, menuItemOptionsPan, Config.OptionsPanMN, Config.OptionsPanAC); - initMenuItem(menuOptions, menuItemOptionsTrail, Config.TrailMN, Config.OptionsTrailAC); - menuOptions.addSeparator(); - initMenuItem(menuOptions, menuItemDefault, Config.DefaultMN, Config.DefaultAC); - initMenuItem(menuOptions, menuItemOptionsSaveInstall, Config.SaveInstallMN, Config.OptionsSaveInstallAC); - initMenuItem(menuOptions, menuItemOptionsSaveCurrent, Config.SaveCurrentMN, Config.OptionsSaveCurrentAC); - - menuBar.add(menuSettings); - menuSettings.setText(Config.Settings); - menuSettings.setMnemonic(Config.SettingsMN); - initMenuItem(menuSettings, menuItemMaxSteps, Config.MaxStepsMN, Config.MaxStepsAC); - initMenuItem(menuSettings, menuItemMaxDepth, Config.MaxDepthMN, Config.MaxDepthAC); - menuSettings.addSeparator(); - initMenuItem(menuSettings, menuItemSeed, Config.SeedMN, Config.SeedAC); - menuSettings.addSeparator(); - initMenuItem(menuSettings, menuItemNegate, Config.NegateMN, Config.NegateAC); - menuItemNegate.setSelected(Config.getBooleanProperty("NEGATE_LTL")); - menuSettings.addSeparator(); - initMenuItem(menuSettings, menuItemFair, Config.FairMN, Config.FairAC); - menuItemFair.setSelected(Config.getBooleanProperty("FAIRNESS")); - menuSettings.addSeparator(); - initMenuItem(menuSettings, menuItemSafety, Config.SafetyMN, Config.SafetyAC); - initMenuItem(menuSettings, menuItemAcceptance, Config.AcceptanceMN, Config.AcceptanceAC); - initMenuItem(menuSettings, menuItemNonProgress, Config.NonProgressMN, Config.NonProgressAC); - buttonGroup.add(menuItemSafety); - buttonGroup.add(menuItemAcceptance); - buttonGroup.add(menuItemNonProgress); - - menuBar.add(menuOutput); - menuOutput.setText(Config.Output); - menuOutput.setMnemonic(Config.OutputMN); - initMenuItem(menuOutput, menuItemMax, Config.MaxMN, Config.MaxAC); - menuOutput.addSeparator(); - initMenuItem(menuOutput, menuItemExcludedV, Config.ExcludedVMN, Config.ExcludedVAC); - initMenuItem(menuOutput, menuItemExcludedS, Config.ExcludedSMN, Config.ExcludedSAC); - menuOutput.addSeparator(); - initMenuItem(menuOutput, menuItemStWidth, Config.StWidthMN, Config.StWidthAC); - initMenuItem(menuOutput, menuItemVarWidth, Config.VarWidthMN, Config.VarWidthAC); - menuOutput.addSeparator(); - initMenuItem(menuOutput, menuItemSaveSpin, Config.SaveSpinMN, Config.SaveSpinAC); - menuOutput.addSeparator(); - initMenuItem(menuOutput, menuItemRaw, Config.RawMN, Config.RawAC); - initMenuItem(menuOutput, menuItemDisplayRaw, Config.DisplayRawMN, Config.DisplayRawAC); - menuItemRaw.setSelected(Config.getBooleanProperty("RAW")); - - menuBar.add(menuSpider); - menuSpider.setText(Config.Spider); - menuSpider.setMnemonic(Config.SpiderMN); - initMenuItem(menuSpider, menuItemSpider, Config.SpiderMN, Config.SpiderAC); - menuSpider.addSeparator(); - initMenuItem(menuSpider, menuItemSpiderDisplay, Config.SpiderDisplayMN, Config.SpiderDisplayAC); - - menuBar.add(menuHelp); - menuHelp.setText(Config.Help); - menuHelp.setMnemonic(Config.HelpMN); - initMenuItem(menuHelp, menuItemHelp, Config.HelpMN, Config.HelpAC); - initMenuItem(menuHelp, menuItemAbout, Config.AboutMN, Config.AboutAC); - - menuBar.add(new JLabel(" ")); - menuBar.add(new JSeparator(SwingConstants.VERTICAL)); - menuBar.add(LTLLabel); - LTLField.setColumns(Config.LTL_COLUMNS); - LTLField.setPreferredSize(new java.awt.Dimension(250,30)); - menuBar.add(LTLField); - } - - private void initToolButton(JButton item, int mnemonic) { - item.setMaximumSize(new java.awt.Dimension(75,40)); - toolBar.add(item); - if (mnemonic != -1) item.setMnemonic(mnemonic); - item.addActionListener(this); - } - - // Initialize toolbar - private void initToolBar() { - toolBar.setLayout(new BoxLayout(toolBar, BoxLayout.X_AXIS)); - toolBar.setFloatable(false); - toolBar.setBorder(new LineBorder(java.awt.Color.BLUE)); - - toolBar.add(toolOpen); - initToolButton(toolOpen, -1); - toolBar.addSeparator(); - initToolButton(toolCheck, Config.CheckMN); - initToolButton(toolRandom, Config.RandomMN); - initToolButton(toolInter, Config.InterMN); - initToolButton(toolTrail, Config.TrailMN); - toolBar.addSeparator(); - - toolBar.add(toolLabelFair); - toolBar.add(toolCheckFair); - toolCheckFair.setSelected(Config.getBooleanProperty("FAIRNESS")); -// toolCheckFair.setMnemonic(Config.FairMN); -// toolLabelFair.setDisplayedMnemonic(Config.FairMN); - toolCheckFair.addActionListener(this); - toolMode.setMaximumSize(new java.awt.Dimension(110,50)); - toolMode.setEditable(false); - toolMode.addItem(Config.Safety); - toolMode.addItem(Config.Acceptance); - toolMode.addItem(Config.NonProgress); - toolMode.addActionListener(this); - toolBar.add(toolMode); - toolBar.addSeparator(); - - initToolButton(toolVerify, Config.VerifyMN); - initToolButton(toolStop, Config.StopMN); - toolBar.addSeparator(); - - if (Config.getIntProperty("VERSION") >= 6) { - initToolButton(LTLTranslateButton, Config.LTLTranslateMN); - initToolButton(LTLLoadButton, Config.LTLLoadMN); - initToolButton(LTLNameButton, Config.LTLNameMN); - } else { - initToolButton(LTLTranslateButton, Config.LTLTranslateMN); - initToolButton(LTLClearButton, Config.LTLClearMN); - initToolButton(LTLLoadButton, Config.LTLLoadMN); - } - - toolBar.addSeparator(); - initToolButton(toolSpider, -1); - toolBar.addSeparator(); - initToolButton(toolMax, Config.MaxMN); - } - - private JFileChooser newChooser(String title, String e1, String e2, String e3) { - JFileChooser fileChooser = new JFileChooser(Config.getStringProperty("SOURCE_DIRECTORY")); - fileChooser.setFileFilter(new JSpinFileFilter(title, e1, e2, e3)); - return fileChooser; - } - - // Initialization, optionally with initial source file - private void init(String file) { - Config.init(); - spiderProperties = new java.util.Properties(); - - // For Spin 6 default is internal LTL - if (Config.getIntProperty("VERSION") >= 6) - ltlInternal = true; - else - ltlInternal = false; - - // Set properties of text areas - font = new java.awt.Font( - Config.getStringProperty("FONT_FAMILY"), - Config.getIntProperty("FONT_STYLE"), - Config.getIntProperty("FONT_SIZE")); - javax.swing.UIManager.put("TextField.font", font); - editorArea.setFont(font); - editorArea.setTabSize(Config.getIntProperty("TAB_SIZE")); - trailArea.setFont(font); - trailArea.setLineWrap(Config.getBooleanProperty("WRAP")); - trailArea.setWrapStyleWord(true); - messageArea.setFont(font); - LTLField.setFont(font); - - // Create menus and toolbar - initMenus(); - initToolBar(); - changeMode(Config.getStringProperty("VERIFY_MODE")); - setJMenuBar(menuBar); - - // Set up frame with panes - topSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, editorScrollPane, trailScrollPane); - mainSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topSplitPane, messageScrollPane); - topSplitPane.setOneTouchExpandable(true); - mainSplitPane.setOneTouchExpandable(true); - topSplitPane.setDividerLocation(Config.getIntProperty("LR_DIVIDER")); - currentDivider = Config.getIntProperty("LR_DIVIDER"); - mainSplitPane.setDividerLocation(Config.getIntProperty("TB_DIVIDER")); - JPanel contentPane = new JPanel(); - contentPane.setLayout(new java.awt.BorderLayout()); - contentPane.add(toolBar, java.awt.BorderLayout.NORTH); - contentPane.add(mainSplitPane, java.awt.BorderLayout.CENTER); - setContentPane(contentPane); - - // Create objects - filter = new filterSpin.Filter(); - editor = new Editor(editorScrollPane, editorArea, messageArea, - LTLField, undoredo.myundoable, filter); - runSpin = new RunSpin(editor, messageArea, filter); - PMLfileChooser = newChooser("Promela source files", ".PML", ".PROM", ".H"); - PRPfileChooser = newChooser("LTL property files", ".PRP", null, null); - OUTfileChooser = newChooser("Spin display output files", ".OUT", null, null); - - // Window listener: kill Spin process if window closed - addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { - runSpin.killSpin(); - System.exit(0); - } - }); - - // Configuration JFrame and make visible - setFont(font); - setTitle(Config.SOFTWARE_NAME); - setSize(Config.getIntProperty("WIDTH"), Config.getIntProperty("HEIGHT")); - setLocationRelativeTo(null); - setVisible(true); - - // Open file if given as command argument - if (file != "") - editor.openFile(new java.io.File(file), true); - else - editor.newFile(); - } - - public static void main(java.lang.String[] args) { - // Check Java version before executing - String version = System.getProperty("java.version"); - if (version.compareTo(Config.JAVA_VERSION) < 0) { - JOptionPane.showMessageDialog(null, - "Your Java version is " + version + "\n" + - "jSpin needs least " + Config.JAVA_VERSION, "Version error", - JOptionPane.ERROR_MESSAGE); - System.exit(1); - } - final String a = (args.length>0) ? args[0] : ""; - javax.swing.SwingUtilities.invokeLater( - new Runnable() { - public void run() { - jSpin jspin = new jSpin(); - jspin.init(a); - } - }); - } - -} +/* + jSpin - Development environment for Spin + Copyright 2003-10 by Mordechai (Moti) Ben-Ari. + +This program 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. +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. +*/ + +package com.spinroot.jspin; + +import com.spinroot.spinSpider.DrawAutomata; +import com.spinroot.spinSpider.SpinSpider; + +import javax.swing.*; +import javax.swing.border.LineBorder; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.util.Objects; + +public class jSpin extends JFrame implements ActionListener { + // Contained objects. Create only after initializing configuration. + private Editor editor; + private RunSpin runSpin; + private com.spinroot.filterSpin.Filter filter; + private UndoRedo undoredo; + private SpiderFile sp; + private java.util.Properties spiderProperties; + + // User interface components + private JTextArea editorArea = new JTextArea(); + private JTextArea trailArea = new JTextArea(); + private JTextArea messageArea = new JTextArea(); + private JTextField LTLField = new JTextField(); + + private JFileChooser PMLfileChooser; + private JFileChooser PRPfileChooser; + private JFileChooser OUTfileChooser; + private java.awt.Font font; + + private JScrollPane editorScrollPane = new JScrollPane(editorArea); + private JScrollPane trailScrollPane = new JScrollPane(trailArea); + private JScrollPane messageScrollPane = new JScrollPane(messageArea); + private JSplitPane topSplitPane; + private JSplitPane mainSplitPane; + + private JMenuBar menuBar = new JMenuBar(); + + private JMenu menuFile = new JMenu(); + private JMenuItem menuItemNew = new JMenuItem(Config.New); + private JMenuItem menuItemOpen = new JMenuItem(Config.Open); + private JMenuItem menuItemSave = new JMenuItem(Config.Save); + private JMenuItem menuItemSaveAs = new JMenuItem(Config.SaveAs); + private JMenuItem menuItemSwitch = new JMenuItem(Config.Switch); + private JMenuItem menuItemExit = new JMenuItem(Config.Exit); + + private JMenu menuEditor = new JMenu(); + private JMenuItem menuItemCopy = new JMenuItem(Config.Copy); + private JMenuItem menuItemCut = new JMenuItem(Config.Cut); + private JMenuItem menuItemPaste = new JMenuItem(Config.Paste); + private JMenuItem menuItemFind = new JMenuItem(Config.Find); + private JMenuItem menuItemFindAgain = new JMenuItem(Config.FindAgain); + + private JMenu menuSpin = new JMenu(); + private JMenuItem menuItemCheck = new JMenuItem(Config.Check); + private JMenuItem menuItemRandom = new JMenuItem(Config.Random); + private JMenuItem menuItemInter = new JMenuItem(Config.Inter); + private JMenuItem menuItemVerify = new JMenuItem(Config.Verify); + private JMenuItem menuItemTrail = new JMenuItem(Config.Trail); + private JMenuItem menuItemStop = new JMenuItem(Config.Stop); + + private JMenu menuLTLConvert = new JMenu(); + private JMenuItem menuItemTranslate = new JMenuItem(Config.LTLTranslate); + private JMenuItem menuItemClear = new JMenuItem(Config.LTLClear); + private JMenuItem menuItemLoad = new JMenuItem(Config.LTLLoad); + private JMenuItem menuItemName = new JMenuItem(Config.LTLName); + private boolean ltlInternal; + + private JMenu menuOptions = new JMenu(); + private JMenuItem menuItemOptionsCheck = new JMenuItem(Config.Check); + private JMenuItem menuItemOptionsCommon = new JMenuItem(Config.Common); + private JMenuItem menuItemOptionsRandom = new JMenuItem(Config.Random); + private JMenuItem menuItemOptionsInter = new JMenuItem(Config.Inter); + private JMenuItem menuItemOptionsVerify = new JMenuItem(Config.Verify); + private JMenuItem menuItemOptionsC = new JMenuItem(Config.OptionsC); + private JMenuItem menuItemOptionsPan = new JMenuItem(Config.OptionsPan); + private JMenuItem menuItemOptionsTrail = new JMenuItem(Config.Trail); + private JMenuItem menuItemDefault = new JMenuItem(Config.Default); + private JMenuItem menuItemOptionsSaveInstall = new JMenuItem(Config.SaveInstall); + private JMenuItem menuItemOptionsSaveCurrent = new JMenuItem(Config.SaveCurrent); + + private JMenu menuSettings = new JMenu(); + private JMenuItem menuItemMaxSteps = new JMenuItem(Config.MaxSteps); + private JMenuItem menuItemMaxDepth = new JMenuItem(Config.MaxDepth); + private JMenuItem menuItemSeed = new JMenuItem(Config.Seed); + private JCheckBoxMenuItem menuItemNegate = new JCheckBoxMenuItem(Config.Negate); + private JCheckBoxMenuItem menuItemFair = new JCheckBoxMenuItem(Config.Fair); + private JRadioButtonMenuItem menuItemSafety = new JRadioButtonMenuItem(Config.Safety, false); + private JRadioButtonMenuItem menuItemAcceptance = new JRadioButtonMenuItem(Config.Acceptance, false); + private JRadioButtonMenuItem menuItemNonProgress = new JRadioButtonMenuItem(Config.NonProgress, false); + private ButtonGroup buttonGroup = new ButtonGroup(); + + private JMenu menuOutput = new JMenu(); + private JMenuItem menuItemMax = new JMenuItem(Config.Max); + private JMenuItem menuItemVarWidth = new JMenuItem(Config.VarWidth); + private JMenuItem menuItemStWidth = new JMenuItem(Config.StWidth); + private JMenuItem menuItemExcludedV = new JMenuItem(Config.ExcludedV); + private JMenuItem menuItemExcludedS = new JMenuItem(Config.ExcludedS); + private JCheckBoxMenuItem menuItemRaw = new JCheckBoxMenuItem(Config.Raw); + private JMenuItem menuItemDisplayRaw = new JMenuItem(Config.DisplayRaw); + private JMenuItem menuItemSaveSpin = new JMenuItem(Config.SaveSpin); + + private JMenu menuSpider = new JMenu(); + private JMenuItem menuItemSpider = new JMenuItem(Config.Spider); + private JMenuItem menuItemSpiderDisplay = new JMenuItem(Config.SpiderDisplay); + + private JMenu menuHelp = new JMenu(); + private JMenuItem menuItemHelp = new JMenuItem(Config.Help); + private JMenuItem menuItemAbout = new JMenuItem(Config.About); + + private JToolBar toolBar = new JToolBar(); + + private JButton toolOpen = new JButton(Config.Open); + private JButton toolCheck = new JButton(Config.Check); + private JButton toolRandom = new JButton(Config.Random); + private JButton toolInter = new JButton(Config.Inter); + private JButton toolVerify = new JButton(Config.Verify); + private JButton toolTrail = new JButton(Config.Trail); + private JButton toolStop = new JButton(Config.Stop); + + private JButton toolSpider = new JButton(Config.Spider); + + private JLabel toolLabelFair = new JLabel(Config.Fair); + private JCheckBox toolCheckFair = new JCheckBox(); + private JComboBox toolMode = new JComboBox(); + private JButton toolMax = new JButton(Config.Max); + private boolean maxedDivider; + private int currentDivider; + + private JLabel LTLLabel = new JLabel(Config.LTLFormula); + private JButton LTLTranslateButton = new JButton(Config.LTLTranslate); + private JButton LTLClearButton = new JButton(Config.LTLClear); + private JButton LTLLoadButton = new JButton(Config.LTLLoad); + private JButton LTLNameButton = new JButton(Config.LTLName); + + // Convert String to array of Strings + private static String[] stringToArray(String s) { + java.util.StringTokenizer st = new java.util.StringTokenizer(s); + int count = st.countTokens(); + String[] sa = new String[count]; + for (int i = 0; i < count; i++) + sa[i] = st.nextToken(); + return sa; + } + + // Append and move caret to end + public static void append(JTextArea area, String s) { + if (s != null) area.append(s); + int last = area.getText().length(); + try { + area.scrollRectToVisible(area.modelToView(last)); + area.setCaretPosition(last); + } catch (javax.swing.text.BadLocationException e) { + System.err.println("Error setting caret position when writing\n" + s + "\n"); + } + } + + public static void main(String[] args) { + // Check Java version before executing + String version = System.getProperty("java.version"); + if (version.compareTo(Config.JAVA_VERSION) < 0) { + JOptionPane.showMessageDialog(null, + "Your Java version is " + version + "\n" + + "jSpin needs least " + Config.JAVA_VERSION, "Version error", + JOptionPane.ERROR_MESSAGE); + System.exit(1); + } + final String a = (args.length > 0) ? args[0] : ""; + javax.swing.SwingUtilities.invokeLater( + () -> { + jSpin jspin = new jSpin(); + jspin.init(a); + }); + } + + public void actionPerformed(ActionEvent e) { + // File menu actions + if (e.getSource() == menuItemNew) { + editor.setLastFile(editor.getFile()); + clearAreas(); + editor.newFile(); + } else if ((e.getSource() == menuItemOpen) || (e.getSource() == toolOpen)) { + if (PMLfileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + editor.setLastFile(editor.getFile()); + clearAreas(); + editor.openFile(PMLfileChooser.getSelectedFile(), true); + } + } else if (e.getSource() == menuItemSave) { + if (editor.getFile() != null) + editor.saveFile(null); + else { + if (PMLfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { + editor.saveFile(PMLfileChooser.getSelectedFile()); + } + } + } else if (e.getSource() == menuItemSaveAs) { + if (PMLfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) + editor.setLastFile(editor.getFile()); + editor.saveFile(PMLfileChooser.getSelectedFile()); + } else if (e.getSource() == menuItemSwitch) { + if (editor.getLastFile() != null) { + java.io.File temp = editor.getLastFile(); + if (editor.getFile() != null) + editor.saveFile(null); + else { + if (PMLfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { + editor.saveFile(PMLfileChooser.getSelectedFile()); + } + } + editor.setLastFile(editor.getFile()); + editor.openFile(temp, true); + } + } else if (e.getSource() == menuItemExit) { + runSpin.killSpin(); + System.exit(0); + } + + // Editor menu actions + else if (e.getSource() == menuItemCut) + editor.cut(); + else if (e.getSource() == menuItemCopy) + editor.copy(); + else if (e.getSource() == menuItemPaste) + editor.paste(); + else if (e.getSource() == menuItemFind) + editor.find(); + else if (e.getSource() == menuItemFindAgain) + editor.findAgain(); + + // Spin menu actions + else if ((e.getSource() == menuItemCheck) || (e.getSource() == toolCheck)) { + trailArea.setText(""); + runSpin.runAndWait(trailArea, false, + Config.getSpin(), + Config.getStringProperty("CHECK_OPTIONS") + " " + + editor.getFileName()); + } else if ((e.getSource() == menuItemRandom) || (e.getSource() == toolRandom)) { + int seed = Config.getIntProperty("SEED"); + trailArea.setText(""); + runSpin.run(trailArea, true, + Config.getSpin(), + Config.getStringProperty("COMMON_OPTIONS") + " " + + Config.getStringProperty("RANDOM_OPTIONS") + " " + + (seed != 0 ? ("-n" + seed + " ") : "") + + " -u" + Config.getStringProperty("MAX_STEPS") + " " + + editor.getFileName()); + isSpinRunning(); + } else if ((e.getSource() == menuItemInter) || (e.getSource() == toolInter)) { + trailArea.setText(""); + runSpin.run(trailArea, true, + Config.getSpin(), + Config.getStringProperty("COMMON_OPTIONS") + " " + + Config.getStringProperty("INTERACTIVE_OPTIONS") + " " + + editor.getFileName()); + isSpinRunning(); + } else if ((e.getSource() == menuItemVerify) || (e.getSource() == toolVerify)) { + trailArea.setText(""); + if (!ltlInternal && !LTLField.getText().equals("") && + !(new java.io.File(editor.getLTLFileName()).exists())) + append(messageArea, "WARNING: Correctness property has not been translated\n"); + runSpin.runAndWait(trailArea, false, + Config.getSpin(), + Config.getStringProperty("VERIFY_OPTIONS") + " " + + ((ltlInternal || LTLField.getText().equals("")) ? "" : "-N " + " " + + editor.getLTLFileName() + " ") + editor.getFileName()); + if (trailArea.getText().contains("Error: syntax error")) + return; + String mode = Config.getStringProperty("VERIFY_MODE"); + String CModeOptions = mode.equals(Config.Safety) ? " -DSAFETY " : + (mode.equals(Config.NonProgress) ? " -DNP " : ""); + runSpin.runAndWait(messageArea, false, + Config.getStringProperty("C_COMPILER"), + CModeOptions + " " + + Config.getStringProperty("C_COMPILER_OPTIONS")); + String panModeOptions = mode.equals(Config.Acceptance) ? " -a " : + (mode.equals(Config.NonProgress) ? " -l " : ""); + if (!mode.equals(Config.Safety) && Config.getBooleanProperty("FAIRNESS")) + panModeOptions = " -f " + panModeOptions; + runSpin.run(trailArea, true, + editor.getRoot() + java.io.File.separator + + Config.getStringProperty("PAN"), + panModeOptions + + " -m" + Config.getStringProperty("MAX_DEPTH") + " " + + ((!ltlInternal || LTLField.getText().equals("")) ? + "" : "-N " + LTLField.getText() + " ") + + Config.getStringProperty("PAN_OPTIONS")); + isSpinRunning(); + } else if ((e.getSource() == menuItemTrail) || (e.getSource() == toolTrail)) { + runSpin.run(trailArea, true, + Config.getSpin(), + Config.getStringProperty("COMMON_OPTIONS") + " " + + Config.getStringProperty("TRAIL_OPTIONS") + + " -u" + Config.getStringProperty("MAX_STEPS") + " " + + editor.getFileName()); + isSpinRunning(); + } else if ((e.getSource() == menuItemStop) || (e.getSource() == toolStop)) + runSpin.killSpin(); + + // Options menu actions + else if (e.getSource() == menuItemOptionsCommon) + new Options(); + else if ((e.getSource() == menuItemOptionsCheck) || + (e.getSource() == menuItemOptionsRandom) || + (e.getSource() == menuItemOptionsInter) || + (e.getSource() == menuItemOptionsVerify) || + (e.getSource() == menuItemOptionsC) || + (e.getSource() == menuItemOptionsPan) || + (e.getSource() == menuItemOptionsTrail)) + changeOption(e.getActionCommand().toUpperCase().replace(' ', '_') + "_OPTIONS", false); + else if (e.getSource() == menuItemDefault) + Config.setDefaultProperties(); + + else if ((e.getSource() == menuItemOptionsSaveInstall) || + (e.getSource() == menuItemOptionsSaveCurrent)) { + // Save current directory and divider locations + Config.setStringProperty("SOURCE_DIRECTORY", + PMLfileChooser.getCurrentDirectory().getAbsolutePath()); + Config.setIntProperty("LR_DIVIDER", topSplitPane.getDividerLocation()); + Config.setIntProperty("TB_DIVIDER", mainSplitPane.getDividerLocation()); + boolean currentConfig = e.getSource() == menuItemOptionsSaveCurrent; + Config.saveFile(currentConfig); + append(messageArea, + "Saved jSpin configuration file config.cfg in " + + (currentConfig ? "current" : "installation") + " directory\n"); + } + + // Settings menu actions + else if (e.getSource() == menuItemMaxSteps) + changeOption("MAX_STEPS", true); + else if (e.getSource() == menuItemMaxDepth) + changeOption("MAX_DEPTH", true); + else if (e.getSource() == menuItemSeed) + changeOption("SEED", true); + else if (e.getSource() == menuItemNegate) { + boolean negate = !Config.getBooleanProperty("NEGATE_LTL"); + Config.setBooleanProperty("NEGATE_LTL", negate); + menuItemNegate.setSelected(negate); + } else if ((e.getSource() == menuItemFair) || (e.getSource() == toolCheckFair)) { + boolean fair = !Config.getBooleanProperty("FAIRNESS"); + Config.setBooleanProperty("FAIRNESS", fair); + menuItemFair.setSelected(fair); + toolCheckFair.setSelected(fair); + } else if ((e.getSource() == menuItemSafety) || + (e.getSource() == menuItemAcceptance) || + (e.getSource() == menuItemNonProgress)) + changeMode(e.getActionCommand()); + else if (e.getSource() == toolMode) + changeMode(((String) ((JComboBox) e.getSource()).getSelectedItem())); + + // Output menu actions + else if ((e.getSource() == menuItemMax) || + (e.getSource() == toolMax)) { + if (maxedDivider) + topSplitPane.setDividerLocation(currentDivider); + else { + currentDivider = topSplitPane.getDividerLocation(); + topSplitPane.setDividerLocation(Config.getIntProperty("MIN_DIVIDER")); + } + maxedDivider = !maxedDivider; + } else if (e.getSource() == menuItemExcludedV) + new Excluded(editor, font, filter, true); + else if (e.getSource() == menuItemExcludedS) + new Excluded(editor, font, filter, false); + else if (e.getSource() == menuItemStWidth) + changeOption("STATEMENT_WIDTH", true); + else if (e.getSource() == menuItemVarWidth) + changeOption("VARIABLE_WIDTH", true); + else if (e.getSource() == menuItemSaveSpin) { + java.io.File outFile = new java.io.File(editor.getOUTFileName()); + OUTfileChooser.setSelectedFile(outFile); + if (OUTfileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) + editor.writeFile(OUTfileChooser.getSelectedFile(), trailArea); + } else if (e.getSource() == menuItemRaw) { + boolean raw = !Config.getBooleanProperty("RAW"); + Config.setBooleanProperty("RAW", raw); + menuItemRaw.setSelected(raw); + } else if (e.getSource() == menuItemDisplayRaw) + displayFile(editor.getRoot() + java.io.File.separator + editor.getFileRoot() + ".raw"); + + // Spider menu actions + else if ((e.getSource() == menuItemSpider) || (e.getSource() == toolSpider)) { + if (editor.getFile() == null) { + jSpin.append(messageArea, Config.OPEN_FILE); + return; + } + // Read Spider properties from the file for this program + sp = new SpiderFile(spiderProperties, + editor.getRoot() + java.io.File.separator + editor.getFileRoot()); + sp.init(); + if (new SpiderOptions(this, sp, font).showDialog()) { + sp.saveFile(); + // Run in thread to display progress + new Thread(() -> { + SpinSpider spd = + new SpinSpider( + editor.getRoot() + File.separator + editor.getFileRoot(), + editor.getExtension(), + sp.getStringProperty("FORMAT"), + sp.getIntProperty("PROCESSES"), + stringToArray(sp.getStringProperty("VARIABLES")), + sp.getBooleanProperty("SPIDER_DEBUG"), + sp.getIntProperty("TRAIL_CODE"), + sp.getIntProperty("DOT_SIZE"), + sp.getIntProperty("TRAIL_STYLE"), + messageArea, + Config.getProperties()); + if (!spd.runSpider()) return; + // If PNG format, display in a frame + if (sp.getStringProperty("FORMAT").equals(Config.PNG)) { + // Draw automata if requested + if (sp.getIntProperty("TRAIL_CODE") == 3) + new DrawAutomata(spd).drawAutomata(); + new DisplayImage(editor.getRoot() + File.separator + editor.getFileRoot() + + com.spinroot.spinSpider.Config.names[sp.getIntProperty("TRAIL_CODE")] + ".png"); + } + }).start(); + } + } else if (e.getSource() == menuItemSpiderDisplay) + displayFile(editor.getRoot() + java.io.File.separator + editor.getFileRoot() + ".dbg"); + + // Help menu actions + else if (e.getSource() == menuItemHelp) + displayFile(Config.helpFileName); + else if (e.getSource() == menuItemAbout) + displayFile(Config.aboutFileName); + + // LTL actions + else if ((e.getSource() == LTLTranslateButton) || (e.getSource() == menuItemTranslate)) { + editor.modifiedLTL(); + if (LTLField.getText().equals("")) + return; + ltlInternal = false; + String quote = Config.getBooleanProperty("SINGLE_QUOTE") ? "'" : "\""; + String negate = Config.getBooleanProperty("NEGATE_LTL") ? "!" : ""; + runSpin.runAndWait(trailArea, false, + Config.getSpin(), + Config.getStringProperty("TRANSLATE_OPTIONS") + " " + + quote + negate + "(" + LTLField.getText() + ")" + quote); + editor.writeFile(new java.io.File(editor.getLTLFileName()), trailArea); + } else if ((e.getSource() == LTLClearButton) || (e.getSource() == menuItemClear)) { + LTLField.setText(""); + menuBar.revalidate(); + } else if ((e.getSource() == LTLLoadButton) || (e.getSource() == menuItemLoad)) { + PRPfileChooser.setCurrentDirectory( + PMLfileChooser.getCurrentDirectory()); + if (PRPfileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + editor.openFile(PRPfileChooser.getSelectedFile(), false); + } + } else if ((e.getSource() == LTLNameButton) || (e.getSource() == menuItemName)) { + ltlInternal = true; + } + if (editor != null) editor.focus(false); + } + + // Display the contents of a file in the trail area + private void displayFile(String fn) { + trailArea.setText(editor.readFile(new java.io.File(fn))); + trailArea.setCaretPosition(0); + } + + // Clear all areas before opening file or creating new file + private void clearAreas() { + messageArea.setText(""); + trailArea.setText(""); + LTLField.setText(""); + } + + // Change verification mode: + // radio buttons in menu, combo box in toolbar and properties + private void changeMode(String mode) { + toolMode.setSelectedItem(mode); + if (mode.equals(Config.Safety)) + menuItemSafety.setSelected(true); + else if (mode.equals(Config.Acceptance)) + menuItemAcceptance.setSelected(true); + else if (mode.equals(Config.NonProgress)) + menuItemNonProgress.setSelected(true); + Config.setStringProperty("VERIFY_MODE", mode); + } + + // Display an option pane to edit an option string + private void changeOption(String property, boolean number) { + String s = Config.getStringProperty(property); + String answer = JOptionPane.showInputDialog(property, s); + if (answer == null) return; + if (!number || (number && checkInt(answer))) + Config.setStringProperty(property, answer); + else + JOptionPane.showMessageDialog(null, + answer + " is not an integer", "Format error", + JOptionPane.ERROR_MESSAGE); + } + + // Some option panes need to be positive integers + private boolean checkInt(String property) { + try { + Integer.parseInt(property); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + // Create a thread to check if Spin is running + // Enables user interface to continue running and press Stop + void isSpinRunning() { + Thread th = new Thread(() -> { + while (runSpin.isRunning()) { + try { + Thread.sleep(Config.getIntProperty("POLLING_DELAY")); + } catch (InterruptedException e) { + } + } + append(messageArea, "done!\n"); + }); + th.start(); + } + + // Initialize menus + private void initMenuItem( + JMenu menu, JMenuItem item, int mnemonic, String accelerator) { + menu.add(item); + item.addActionListener(this); + item.setMnemonic(mnemonic); + if (accelerator != null) + item.setAccelerator(KeyStroke.getKeyStroke(accelerator)); + } + + private void initMenus() { + menuBar.setBorder(new LineBorder(java.awt.Color.BLUE)); + + menuBar.add(menuFile); + menuFile.setText(Config.File); + menuFile.setMnemonic(Config.FileMN); + initMenuItem(menuFile, menuItemNew, Config.NewMN, Config.NewAC); + initMenuItem(menuFile, menuItemOpen, Config.OpenMN, Config.OpenAC); + initMenuItem(menuFile, menuItemSave, Config.SaveMN, Config.SaveAC); + initMenuItem(menuFile, menuItemSaveAs, Config.SaveAsMN, Config.SaveAsAC); + menuFile.addSeparator(); + initMenuItem(menuFile, menuItemSwitch, Config.SwitchMN, Config.SwitchAC); + menuFile.addSeparator(); + initMenuItem(menuFile, menuItemExit, Config.ExitMN, Config.ExitAC); + + undoredo = new UndoRedo(); + menuBar.add(menuEditor); + menuEditor.setText(Config.Editor); + menuEditor.setMnemonic(Config.EditorMN); + JMenuItem menuItemUndo = menuEditor.add(undoredo.undoAction); + JMenuItem menuItemRedo = menuEditor.add(undoredo.redoAction); + initMenuItem(menuEditor, menuItemUndo, Config.UndoMN, Config.UndoAC); + initMenuItem(menuEditor, menuItemRedo, Config.RedoMN, Config.RedoAC); + menuEditor.addSeparator(); + initMenuItem(menuEditor, menuItemCopy, Config.CopyMN, Config.CopyAC); + initMenuItem(menuEditor, menuItemCut, Config.CutMN, Config.CutAC); + initMenuItem(menuEditor, menuItemPaste, Config.PasteMN, Config.PasteAC); + menuEditor.addSeparator(); + initMenuItem(menuEditor, menuItemFind, Config.FindMN, Config.FindAC); + initMenuItem(menuEditor, menuItemFindAgain, Config.FindAgainMN, Config.FindAgainAC); + + menuBar.add(menuSpin); + menuSpin.setText(Config.Spin); + menuSpin.setMnemonic(Config.SpinMN); + initMenuItem(menuSpin, menuItemCheck, Config.CheckMN, Config.CheckAC); + menuSpin.addSeparator(); + initMenuItem(menuSpin, menuItemRandom, Config.RandomMN, Config.RandomAC); + initMenuItem(menuSpin, menuItemInter, Config.InterMN, Config.InterAC); + initMenuItem(menuSpin, menuItemTrail, Config.TrailMN, Config.TrailAC); + menuSpin.addSeparator(); + initMenuItem(menuSpin, menuItemVerify, Config.VerifyMN, Config.VerifyAC); + initMenuItem(menuSpin, menuItemStop, Config.StopMN, Config.StopAC); + + menuBar.add(menuLTLConvert); + menuLTLConvert.setText(Config.LTLConvert); + menuLTLConvert.setMnemonic(Config.LTLConvertMN); + initMenuItem(menuLTLConvert, menuItemTranslate, Config.LTLTranslateMN, Config.LTLTranslateAC); + initMenuItem(menuLTLConvert, menuItemClear, Config.LTLClearMN, Config.LTLClearAC); + initMenuItem(menuLTLConvert, menuItemLoad, Config.LTLLoadMN, Config.LTLLoadAC); + if (Config.getIntProperty("VERSION") >= 6) { + menuLTLConvert.addSeparator(); + initMenuItem(menuLTLConvert, menuItemName, Config.LTLName1MN, Config.LTLNameAC); + } + + menuBar.add(menuOptions); + menuOptions.setText(Config.Options); + menuOptions.setMnemonic(Config.OptionsMN); + initMenuItem(menuOptions, menuItemOptionsCommon, Config.CommonMN, Config.CommonAC); + menuOptions.addSeparator(); + initMenuItem(menuOptions, menuItemOptionsCheck, Config.CheckMN, Config.CheckAC); + initMenuItem(menuOptions, menuItemOptionsRandom, Config.RandomMN, Config.OptionsRandomAC); + initMenuItem(menuOptions, menuItemOptionsInter, Config.InterMN, Config.OptionsInterAC); + initMenuItem(menuOptions, menuItemOptionsVerify, Config.VerifyMN, Config.VerifyAC); + initMenuItem(menuOptions, menuItemOptionsC, Config.OptionsCMN, Config.OptionsCAC); + initMenuItem(menuOptions, menuItemOptionsPan, Config.OptionsPanMN, Config.OptionsPanAC); + initMenuItem(menuOptions, menuItemOptionsTrail, Config.TrailMN, Config.OptionsTrailAC); + menuOptions.addSeparator(); + initMenuItem(menuOptions, menuItemDefault, Config.DefaultMN, Config.DefaultAC); + initMenuItem(menuOptions, menuItemOptionsSaveInstall, Config.SaveInstallMN, Config.OptionsSaveInstallAC); + initMenuItem(menuOptions, menuItemOptionsSaveCurrent, Config.SaveCurrentMN, Config.OptionsSaveCurrentAC); + + menuBar.add(menuSettings); + menuSettings.setText(Config.Settings); + menuSettings.setMnemonic(Config.SettingsMN); + initMenuItem(menuSettings, menuItemMaxSteps, Config.MaxStepsMN, Config.MaxStepsAC); + initMenuItem(menuSettings, menuItemMaxDepth, Config.MaxDepthMN, Config.MaxDepthAC); + menuSettings.addSeparator(); + initMenuItem(menuSettings, menuItemSeed, Config.SeedMN, Config.SeedAC); + menuSettings.addSeparator(); + initMenuItem(menuSettings, menuItemNegate, Config.NegateMN, Config.NegateAC); + menuItemNegate.setSelected(Config.getBooleanProperty("NEGATE_LTL")); + menuSettings.addSeparator(); + initMenuItem(menuSettings, menuItemFair, Config.FairMN, Config.FairAC); + menuItemFair.setSelected(Config.getBooleanProperty("FAIRNESS")); + menuSettings.addSeparator(); + initMenuItem(menuSettings, menuItemSafety, Config.SafetyMN, Config.SafetyAC); + initMenuItem(menuSettings, menuItemAcceptance, Config.AcceptanceMN, Config.AcceptanceAC); + initMenuItem(menuSettings, menuItemNonProgress, Config.NonProgressMN, Config.NonProgressAC); + buttonGroup.add(menuItemSafety); + buttonGroup.add(menuItemAcceptance); + buttonGroup.add(menuItemNonProgress); + + menuBar.add(menuOutput); + menuOutput.setText(Config.Output); + menuOutput.setMnemonic(Config.OutputMN); + initMenuItem(menuOutput, menuItemMax, Config.MaxMN, Config.MaxAC); + menuOutput.addSeparator(); + initMenuItem(menuOutput, menuItemExcludedV, Config.ExcludedVMN, Config.ExcludedVAC); + initMenuItem(menuOutput, menuItemExcludedS, Config.ExcludedSMN, Config.ExcludedSAC); + menuOutput.addSeparator(); + initMenuItem(menuOutput, menuItemStWidth, Config.StWidthMN, Config.StWidthAC); + initMenuItem(menuOutput, menuItemVarWidth, Config.VarWidthMN, Config.VarWidthAC); + menuOutput.addSeparator(); + initMenuItem(menuOutput, menuItemSaveSpin, Config.SaveSpinMN, Config.SaveSpinAC); + menuOutput.addSeparator(); + initMenuItem(menuOutput, menuItemRaw, Config.RawMN, Config.RawAC); + initMenuItem(menuOutput, menuItemDisplayRaw, Config.DisplayRawMN, Config.DisplayRawAC); + menuItemRaw.setSelected(Config.getBooleanProperty("RAW")); + + menuBar.add(menuSpider); + menuSpider.setText(Config.Spider); + menuSpider.setMnemonic(Config.SpiderMN); + initMenuItem(menuSpider, menuItemSpider, Config.SpiderMN, Config.SpiderAC); + menuSpider.addSeparator(); + initMenuItem(menuSpider, menuItemSpiderDisplay, Config.SpiderDisplayMN, Config.SpiderDisplayAC); + + menuBar.add(menuHelp); + menuHelp.setText(Config.Help); + menuHelp.setMnemonic(Config.HelpMN); + initMenuItem(menuHelp, menuItemHelp, Config.HelpMN, Config.HelpAC); + initMenuItem(menuHelp, menuItemAbout, Config.AboutMN, Config.AboutAC); + + menuBar.add(new JLabel(" ")); + menuBar.add(new JSeparator(SwingConstants.VERTICAL)); + menuBar.add(LTLLabel); + LTLField.setColumns(Config.LTL_COLUMNS); + LTLField.setPreferredSize(new java.awt.Dimension(250, 30)); + menuBar.add(LTLField); + } + + private void initToolButton(JButton item, int mnemonic) { + item.setMaximumSize(new java.awt.Dimension(75, 40)); + toolBar.add(item); + if (mnemonic != -1) item.setMnemonic(mnemonic); + item.addActionListener(this); + } + + // Initialize toolbar + private void initToolBar() { + toolBar.setLayout(new BoxLayout(toolBar, BoxLayout.X_AXIS)); + toolBar.setFloatable(false); + toolBar.setBorder(new LineBorder(java.awt.Color.BLUE)); + + toolBar.add(toolOpen); + initToolButton(toolOpen, -1); + toolBar.addSeparator(); + initToolButton(toolCheck, Config.CheckMN); + initToolButton(toolRandom, Config.RandomMN); + initToolButton(toolInter, Config.InterMN); + initToolButton(toolTrail, Config.TrailMN); + toolBar.addSeparator(); + + toolBar.add(toolLabelFair); + toolBar.add(toolCheckFair); + toolCheckFair.setSelected(Config.getBooleanProperty("FAIRNESS")); +// toolCheckFair.setMnemonic(Config.FairMN); +// toolLabelFair.setDisplayedMnemonic(Config.FairMN); + toolCheckFair.addActionListener(this); + toolMode.setMaximumSize(new java.awt.Dimension(110, 50)); + toolMode.setEditable(false); + toolMode.addItem(Config.Safety); + toolMode.addItem(Config.Acceptance); + toolMode.addItem(Config.NonProgress); + toolMode.addActionListener(this); + toolBar.add(toolMode); + toolBar.addSeparator(); + + initToolButton(toolVerify, Config.VerifyMN); + initToolButton(toolStop, Config.StopMN); + toolBar.addSeparator(); + + if (Config.getIntProperty("VERSION") >= 6) { + initToolButton(LTLTranslateButton, Config.LTLTranslateMN); + initToolButton(LTLLoadButton, Config.LTLLoadMN); + initToolButton(LTLNameButton, Config.LTLNameMN); + } else { + initToolButton(LTLTranslateButton, Config.LTLTranslateMN); + initToolButton(LTLClearButton, Config.LTLClearMN); + initToolButton(LTLLoadButton, Config.LTLLoadMN); + } + + toolBar.addSeparator(); + initToolButton(toolSpider, -1); + toolBar.addSeparator(); + initToolButton(toolMax, Config.MaxMN); + } + + private JFileChooser newChooser(String title, String e1, String e2, String e3) { + JFileChooser fileChooser = new JFileChooser(Config.getStringProperty("SOURCE_DIRECTORY")); + fileChooser.setFileFilter(new JSpinFileFilter(title, e1, e2, e3)); + return fileChooser; + } + + // Initialization, optionally with initial source file + private void init(String file) { + Config.init(); + spiderProperties = new java.util.Properties(); + + // For Spin 6 default is internal LTL + ltlInternal = Config.getIntProperty("VERSION") >= 6; + + // Set properties of text areas + font = new java.awt.Font( + Config.getStringProperty("FONT_FAMILY"), + Config.getIntProperty("FONT_STYLE"), + Config.getIntProperty("FONT_SIZE")); + javax.swing.UIManager.put("TextField.font", font); + editorArea.setFont(font); + editorArea.setTabSize(Config.getIntProperty("TAB_SIZE")); + trailArea.setFont(font); + trailArea.setLineWrap(Config.getBooleanProperty("WRAP")); + trailArea.setWrapStyleWord(true); + messageArea.setFont(font); + LTLField.setFont(font); + + // Create menus and toolbar + initMenus(); + initToolBar(); + changeMode(Config.getStringProperty("VERIFY_MODE")); + setJMenuBar(menuBar); + + // Set up frame with panes + topSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, editorScrollPane, trailScrollPane); + mainSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topSplitPane, messageScrollPane); + topSplitPane.setOneTouchExpandable(true); + mainSplitPane.setOneTouchExpandable(true); + topSplitPane.setDividerLocation(Config.getIntProperty("LR_DIVIDER")); + currentDivider = Config.getIntProperty("LR_DIVIDER"); + mainSplitPane.setDividerLocation(Config.getIntProperty("TB_DIVIDER")); + JPanel contentPane = new JPanel(); + contentPane.setLayout(new java.awt.BorderLayout()); + contentPane.add(toolBar, java.awt.BorderLayout.NORTH); + contentPane.add(mainSplitPane, java.awt.BorderLayout.CENTER); + setContentPane(contentPane); + + // Create objects + filter = new com.spinroot.filterSpin.Filter(); + editor = new Editor(editorScrollPane, editorArea, messageArea, + LTLField, undoredo.myundoable, filter); + runSpin = new RunSpin(editor, messageArea, filter); + PMLfileChooser = newChooser("Promela source files", ".PML", ".PROM", ".H"); + PRPfileChooser = newChooser("LTL property files", ".PRP", null, null); + OUTfileChooser = newChooser("Spin display output files", ".OUT", null, null); + + // Window listener: kill Spin process if window closed + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + runSpin.killSpin(); + System.exit(0); + } + }); + + // Configuration JFrame and make visible + setFont(font); + setTitle(Config.SOFTWARE_NAME); + setSize(Config.getIntProperty("WIDTH"), Config.getIntProperty("HEIGHT")); + setLocationRelativeTo(null); + setVisible(true); + + // Open file if given as command argument + if (!Objects.equals(file, "")) { + editor.openFile(new java.io.File(file), true); + } else { + editor.newFile(); + } + } + +} diff --git a/src/main/java/com/spinroot/spinSpider/Config.java b/src/main/java/com/spinroot/spinSpider/Config.java new file mode 100644 index 0000000..2561ec8 --- /dev/null +++ b/src/main/java/com/spinroot/spinSpider/Config.java @@ -0,0 +1,72 @@ +/* + Config - configuration constants and file + Copyright 2005-10 by Mordechai (Moti) Ben-Ari. See SpinSpider.java +*/ +package com.spinroot.spinSpider; + +public class Config { + public static final String[] names = {"", "-trail-1", "-trail-2", "-automata"}; + static final String VERSION = "6.0"; + // Properties data structure is used for command names + // Initialize properties from file or create file or from defaults + static final String CONFIG_FILE = "config.cfg"; + static final int MAX_STACK = 1000; // Stack for processing -DCHECK file + static final int INITIAL = 100; // For ArrayLists + static final int DELTA = 1000; // For node offset in automata + static final String TITLE = + "SpinSpider Version " + VERSION + + " Copyright 2005-7 (GNU GPL) by Moti Ben-Ari."; + static final String USAGE = + "Usage java com.spinroot.spinSpider.SpinSpider arguments file\n\n" + + " file Promela source file\n\n" + + " -p number of processes (must be >= 1)\n" + + " -vname name of a variable (one parameter per variable)\n\n" + + " -dot dot format\n" + + " -Txxx dot format and run DOT to convert to xxx format\n" + + " (default is png)\n" + + " -fsm fsm format\n\n" + + " -t1 use trail file to emphasize a path\n" + + " -t2 use trail file to draw a path\n" + + " -a draw automata corresponding to source\n\n" + + " -small size of dot graph is smaller\n" + + " -bold bold style instead of color for path\n" + + " -debug write internal tables to file.dbg"; + static final String dotTrailBold = " style = bold"; + static final String dotTrailColor = " color = red"; + static final String[] smallDotPrologue = { + "\tgraph [size=\"12.5,7.5\",ranksep=.20];", + "\tnode [shape=box,fontname=Helvetica,fontsize=10];", + "\tnode [width=1.25,height=0.75,fixedsize=true];" + }; + static final String[] largeDotPrologue = { + "\tgraph [size=\"16,12\",ranksep=.25];", + "\tnode [shape=box,fontname=Helvetica,fontsize=14];", + "\tnode [width=1.6,height=1.2,fixedsize=true];" + }; + static final String[] automataDotPrologue = { + "\tgraph [size=\"16,12\",ranksep=.4];", + "\tnode [shape=circle,fontname=Helvetica,fontsize=14];", + "\tedge [fontname=Helvetica,fontsize=14];" + }; + + static public void setDefaultProperties( + java.util.Properties properties) { + // Spin version: format changed with Spin 6 + properties.put("VERSION", "6"); + + properties.put("C_COMPILER", "c:\\mingw\\bin\\gcc.exe"); + properties.put("SPIN", "bin\\spin.exe"); + properties.put("PAN", "pan.exe"); + properties.put("DOT", "bin\\dot.exe"); + } + + static public void init(java.util.Properties properties) { + setDefaultProperties(properties); + try { + properties.load(new java.io.FileInputStream(CONFIG_FILE)); + } catch (java.io.IOException e1) { + System.err.println("Cannot open configuration file; using defaults"); + } + } + +} diff --git a/src/main/java/com/spinroot/spinSpider/DrawAutomata.java b/src/main/java/com/spinroot/spinSpider/DrawAutomata.java new file mode 100644 index 0000000..e833f4a --- /dev/null +++ b/src/main/java/com/spinroot/spinSpider/DrawAutomata.java @@ -0,0 +1,113 @@ +/* Copyright 2007 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* + * Draw the automata representation of a Promela program. +*/ + +package com.spinroot.spinSpider; + +import java.io.*; + +public class DrawAutomata { + SpinSpider spd; + + public DrawAutomata(SpinSpider s) { + spd = s; + } + + // Extract an int value that appears between "from" and "to" in "s" + private static int extract(String s, String from, String to) { + return + Integer.parseInt( + s.substring(s.indexOf(from) + from.length(), s.indexOf(to)) + .trim()); + } + + public void drawAutomata() { + BufferedReader statementReader = null; + PrintWriter graphWriter = null; + String s = ""; + String fn = spd.fileName + Config.names[3]; + + spd.progress("Drawing automata"); + try { + statementReader = new BufferedReader( + new FileReader(spd.fileName + ".dbg")); + } catch (IOException e) { + spd.fileError(".dbg"); + } + try { + graphWriter = new PrintWriter( + new FileWriter(fn + ".dot")); + } catch (IOException e) { + spd.fileError(".dot"); + } + + // Write dot prologue + graphWriter.println("digraph \"" + fn + "\"" + " {"); + for (int i = 0; i < Config.automataDotPrologue.length; i++) + graphWriter.println(Config.automataDotPrologue[i]); + + // Skip over first parts of debug files + while (true) { + try { + s = statementReader.readLine(); + } catch (IOException e) { + spd.fileError(".dbg"); + } + if (s == null) + spd.fileError(".dbg"); + else if (s.equals("Statements from -d file")) + break; + } + + // Extract data from each line and write nodes and edges + // Use DELTA to create unique node numbers for each process + int process = 0, proc, line, source, target; + boolean endState = false, atomic = false, previousAtomic = false; + String emphasize = spd.trailStyle == 0 ? Config.dotTrailColor : Config.dotTrailBold; + while (true) { + try { + s = statementReader.readLine(); + } catch (IOException e) { + spd.fileError(".dbg"); + } + if (s == null) break; + if (s.indexOf("process") == -1) break; + proc = extract(s, "process=", ", source"); + // New process + if (proc != process) { + process = proc; + endState = false; + } + source = extract(s, "source=", ", target") + process * Config.DELTA; + line = extract(s, "line=", "."); + graphWriter.println(source + " [label=" + line + "]"); + target = extract(s, "target=", ", id") + process * Config.DELTA; + if ((target == process * Config.DELTA) && !endState) { + endState = true; + graphWriter.println(target + " [label=0]"); + } + atomic = s.indexOf("atomic,") != -1; + graphWriter.println(source + " -> " + target + + " [label=\"" + s.substring(s.indexOf('.') + 1) + "\"" + + (atomic || previousAtomic ? emphasize : "") + "]"); + previousAtomic = atomic; + } + + try { + statementReader.close(); + } catch (IOException e) { + spd.fileError(".dbg"); + } + graphWriter.println("}"); + graphWriter.close(); + + // Call dot to format dot file + if (!spd.format.equals("dot")) + spd.runProcess(spd.properties.getProperty("DOT") + + " -T" + spd.format + + " -o " + fn + "." + spd.format + " " + + fn + ".dot", null); + } + +} diff --git a/src/main/java/com/spinroot/spinSpider/Read.java b/src/main/java/com/spinroot/spinSpider/Read.java new file mode 100644 index 0000000..bd33772 --- /dev/null +++ b/src/main/java/com/spinroot/spinSpider/Read.java @@ -0,0 +1,240 @@ +/* Copyright 2006-10 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* + * Read the data files +*/ + +package com.spinroot.spinSpider; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +class Read { + SpinSpider spd; + String fileName; + Properties properties; + + Read(SpinSpider s, String f, Properties p) { + spd = s; + fileName = f; + properties = p; + } + + // Extract an int value that appears between "from" and "to" in "s" + private static int extract(String s, String from, String to) { + return + Integer.parseInt( + s.substring(s.indexOf(from) + from.length(), s.indexOf(to)) + .trim()); + } + + // Read the state transitions output by -DCHECK and never claim + // Thanks to Gerard Holzmann for showing me how to do this. + void readCheckFile() { + BufferedReader checkReader = null; + String s = ""; // Read line to s + String[] tokens; // For tokenizing + // Stack of states traversed + int[] stack = new int[Config.MAX_STACK]; + int newState = 0; // State number in "New" + int depth = 0; // Stack depth + boolean needNew = false; // Need state information after "New" + int offset = 0; // Offset of variables after procs + + spd.progress("Reading -DCHECK file"); + try { + checkReader = new BufferedReader( + new FileReader(fileName + ".chk")); + } catch (IOException e) { + spd.fileError(".chk"); + } + + while (true) { + try { + s = checkReader.readLine(); + } catch (IOException e) { + spd.fileError(".chk"); + } + if ((s == null) || s.indexOf("Spin Version") != -1) break; + + tokens = s.trim().split("\\s"); + // "New" indicates a new state + // Push on the stack + // Immediately thereafter the *spd* output will appear + if ((tokens.length > 2) && tokens[0].equals("New")) { + newState = Integer.parseInt(tokens[2]); + stack[depth] = newState; + needNew = true; + } + // "Down" for a program (not a claim) indicates a transition + // to the new state that was just pushed on the stack + else if ((tokens.length > 3) && (tokens[1].equals("Down"))) { + if (tokens[3].equals("program") && (newState > 0)) + spd.transitions.add( + new Transition(stack[depth - 1], newState)); + depth++; + stack[depth] = stack[depth - 1]; + } + // "Up" - pop the stack + else if ((tokens.length > 1) && tokens[1].equals("Up")) { + depth--; + } + // "Old" - just a transition, no need to push a new state + else if ((tokens.length > 2) && tokens[0].equals("Old")) { + newState = Integer.parseInt(tokens[2]); + spd.transitions.add( + new Transition(stack[depth], newState)); + } + // "Stack" - have never occurred + // When it does you'll have to figure out what to do! + else if ((tokens.length > 2) && tokens[0].equals("Stack")) { + // For now, I don't know why this is here..... + System.out.println("Stack line = " + s); + System.exit(3); + } + // "*spd*" - The data created by the never claim + else if (needNew && (tokens.length > 1) && + tokens[0].equals("*spd*")) { + // The first time, set the number of processes and variables + if (State.numProcs == 0) { + State.numProcs = Integer.parseInt(tokens[1]); + offset = State.numProcs + 3; + State.numVars = Integer.parseInt(tokens[offset - 1]); + } + // Parse the pc values and the values of the variables + // and construct a new state + needNew = false; + int[] st = new int[State.numProcs]; + String[] vn = new String[State.numVars]; + String[] vr = new String[State.numVars]; + for (int proc = 0; proc < State.numProcs; proc++) + st[proc] = Integer.parseInt(tokens[proc + 2]); + for (int var = 0; var < State.numVars; var++) { + vn[var] = tokens[offset + 2 * var]; + vr[var] = tokens[offset + 2 * var + 1]; + } + + spd.states.add(new State(st, vn, vr)); + } + } + try { + checkReader.close(); + } catch (IOException e) { + spd.fileError(".chk"); + } + } + + // Create statement database from -d file + void createStatements() { + BufferedReader statementReader = null; + String s = ""; + int proc = 0; // For detecting change of process + int countStatements = 0; // Count statements per process + spd.progress("Reading -d file"); + try { + statementReader = new BufferedReader( + new FileReader(fileName + ".d")); + } catch (IOException e) { + spd.fileError(".d"); + } + + while (true) { + try { + s = statementReader.readLine(); + } catch (IOException e) { + spd.fileError(".d"); + } + if (s == null) { + if (spd.trailCode != 3) + spd.fileError(".d (the never claim may be missing)"); + break; + } + + // Start of never claim - terminate processing + else if (s.indexOf("claim never") != -1) { + spd.statementsPerProcess.add( + new Integer(countStatements)); + break; + } + + // Beginning of transitions of a process - store and reset count + else if (s.indexOf("proctype") != -1) { + if (proc != 0) + spd.statementsPerProcess.add( + new Integer(countStatements)); + countStatements = 0; + proc++; + } + + // Entry for each transition + else if (s.indexOf("-> state") != -1) { + countStatements++; + // For Spin 6 the format for the line number is different + int arrow = s.indexOf("=>"); + int lineNumber; + if (Integer.valueOf(properties.getProperty("VERSION")).intValue() >= 6) + lineNumber = s.lastIndexOf(':', arrow) + 1; + else + lineNumber = s.lastIndexOf("line ", arrow) + 5; + + spd.statements.add(new Statement( + proc - 1, // process number + extract(s, "state", "-(tr"), // source state + extract(s, "-> state", "[id"), // target state + extract(s, "[id", "tp"), // id number for trail + s.indexOf("[A") != -1, // atomic for automata + // source line number + Integer.parseInt(s.substring(lineNumber, arrow - 1)), + s.substring(arrow + 2).trim())); // source statement + } + } + try { + statementReader.close(); + } catch (IOException e) { + spd.fileError(".d"); + } + } + + // Read the trail file whose entries are - + // "sequence number : process number : transition id" + // Sequence number = -2 means there is a never claim + // In that case, ignore its transitions (process number 0) + void readTrail() { + BufferedReader trailReader = null; + boolean claim = false; + String s = ""; + spd.progress("Reading trail file"); + try { + trailReader = new BufferedReader( + new FileReader(fileName + ".pml.trail")); + } catch (IOException e) { + spd.fileError(".pml.trail"); + return; + } + + while (true) { + try { + s = trailReader.readLine(); + } catch (IOException e) { + spd.fileError(".pml.tral"); + } + if (s == null) break; + String[] t = s.split(":"); + if (t[0].startsWith("-2")) { + claim = true; + continue; + } + if ((t[0].charAt(0) == '-')) continue; + if (claim && (t[1].charAt(0) == '0')) continue; + Trail tr = new Trail(Integer.valueOf(t[2]).intValue()); + spd.trails.add(tr); + } + try { + trailReader.close(); + } catch (IOException e) { + spd.fileError(".pml.trail"); + } + } + +} diff --git a/src/main/java/com/spinroot/spinSpider/SetTrail.java b/src/main/java/com/spinroot/spinSpider/SetTrail.java new file mode 100644 index 0000000..c0a85ae --- /dev/null +++ b/src/main/java/com/spinroot/spinSpider/SetTrail.java @@ -0,0 +1,67 @@ +/* Copyright 2006 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* + * Use the trail file to give attributes to states and transitions +*/ + +package com.spinroot.spinSpider; + +class SetTrail { + SpinSpider spd; + + SetTrail(SpinSpider s) { + spd = s; + } + + // Traverse the state diagram according to the trail file + void setTrail() { + int i = 0; + if (spd.states.size() == 0) return; + + // Start from first state + spd.states.get(i).inTrail = true; + // For each line in the trail, find a statement with matching id + for (Trail tr : spd.trails) { + Statement st = null; + for (Statement stmt : spd.statements) + if (stmt.id == tr.id) { + st = stmt; + break; + } + // Set trail flag for the state obtained by taking + // this transition in the trail + i = findNewState(i, st); + spd.states.get(i).inTrail = true; + } + } + + // Starting from state "index", find where the state where + // statement "stmt" goes to + private int findNewState(int index, Statement stmt) { + boolean ok; + State currentState = spd.states.get(index); + for (State s : spd.states) { + ok = true; + // For each process, the location is the same, + // except for the process executed by this statement, + // in which case the new state is reached by the statement + for (int i = 0; i < s.s.length; i++) { + if (i == stmt.process) ok = ok && (s.s[i] == stmt.targetState); + if (i != stmt.process) ok = ok && (s.s[i] == currentState.s[i]); + } + + // Flag the transition + if (ok) { + boolean foundTransition = false; + for (Transition tr : spd.transitions) + if ((tr.head == index) && (tr.tail == spd.states.indexOf(s))) { + tr.inTrail = true; + foundTransition = true; + } + if (foundTransition) + return spd.states.indexOf(s); + else continue; + } + } + return 0; + } +} diff --git a/spinSpider/SpinSpider.java b/src/main/java/com/spinroot/spinSpider/SpinSpider.java similarity index 51% rename from spinSpider/SpinSpider.java rename to src/main/java/com/spinroot/spinSpider/SpinSpider.java index 665ca03..d17ae38 100644 --- a/spinSpider/SpinSpider.java +++ b/src/main/java/com/spinroot/spinSpider/SpinSpider.java @@ -1,286 +1,286 @@ -/* - SpinSpider - Use Spin to Create State Transition Diagrams - Copyright 2005 by Mordechai (Moti) Ben-Ari. - -This program 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. -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. -*/ - -//package jspin.spinSpider; -package spinSpider; - -import java.io.*; -import java.util.ArrayList; -import java.util.Properties; - -public class SpinSpider { - - // The following two variables are passed from jSpin - // For standalone execution, properties is set in the main method - // and output is to standard output - Properties properties; - private javax.swing.JTextArea area; - - String fileName; // File name (without extension) - String extension; // Extension of Promela file name - String format; // Graph format (dot/fsm/png ...) - int trailCode; // Use trail file to draw or emphasize a computation - int dotSize; // Size of dot graph - int trailStyle; // Style of trail in dot graph color/bold - private boolean debug; // Write debug file - // For writing never claim: - private int numProcs; // Number of processes - - // write never claim if numProcs > 0 - private String[] vars; // Names of variables - - // Databases - ArrayList states = - new ArrayList(Config.INITIAL); - ArrayList statements = - new ArrayList(Config.INITIAL); - ArrayList transitions = - new ArrayList(Config.INITIAL); - ArrayList trails = - new ArrayList(Config.INITIAL); - - // For FSM we need to compute the number of statements per process - ArrayList statementsPerProcess = - new ArrayList(Config.INITIAL); - - public SpinSpider( - String fileName, - String extension, - String format, - int numProcs, - String[] vars, - boolean debug, - int trailCode, - int dotSize, - int trailStyle, - javax.swing.JTextArea area, - Properties properties) { - this.fileName = fileName; - this.extension = extension; - this.format = format; - this.numProcs = numProcs; - this.vars = vars; - this.debug = debug; - this.trailCode = trailCode; - this.dotSize = dotSize; - this.trailStyle = trailStyle; - this.area = area; - this.properties = properties; - State.numProcs = 0; - State.numVars = 0; - } - - // Create array of tokens from a string for ProcessBuilder - private static String[] stringToArray(String s) { - java.util.StringTokenizer st = new java.util.StringTokenizer(s); - int count = st.countTokens(); - String[] sa = new String[count]; - for (int i = 0; i < count; i++) - sa[i] = st.nextToken(); - return sa; - } - - // Build a process and run it - // command is the command string with parameters - // ext is the extension for redirecting standard output - // if null, output is sent to System.out - void runProcess(String command, String ext) { - PrintWriter outWriter = null; - progress("Running " + command); - if (ext != null) - try { - outWriter = new PrintWriter(new FileWriter(fileName + ext)); - } catch (IOException e) { fileError(ext); } - try { - ProcessBuilder pb = new ProcessBuilder(stringToArray(command)); - File pf = new File(fileName).getParentFile(); - if (pf != null) pb.directory(pf.getCanonicalFile()); - pb.redirectErrorStream(true); - Process p = pb.start(); - BufferedReader input = - new BufferedReader(new InputStreamReader(p.getInputStream())); - String s; - while (true) { - s = input.readLine(); - if (s == null) break; - if (ext == null) System.out.println(s); - else outWriter.println(s); - } - p.waitFor(); - if (ext != null) outWriter.close(); - } catch (IOException e) { - progress("IO exception " + e.getMessage() + - " while executing " + command); - } catch (InterruptedException e) { - progress("Interrupted exception while executing " + command); - } - } - - // This method runs SpinSpider - public boolean runSpider() { - progress(Config.TITLE); - // Create objects for reading and writing files - Write write = new Write(this, fileName); - Read read = new Read(this, fileName, properties); - - // Write never claim if requested - String never = ""; - if (trailCode != 3) { - if (!write.writeNeverClaim(numProcs, vars)) return false; - never = " -N " + fileName + ".nvr "; - } - - // Run Spin and C compiler - runProcess(properties.getProperty("SPIN") + - " -a -o3 " + never + fileName + extension, null); - runProcess(properties.getProperty("C_COMPILER") + - " -DCHECK -DSAFETY -DPRINTF -DNOREDUCE -o pan pan.c", null); - - // Run pan twice: once for -DCHECK file and once for -d file - String pan = ""; - try { - File f = new File(fileName).getParentFile(); - if (f != null) - pan = f.getCanonicalPath() + java.io.File.separator; - } catch(IOException e) {}; - pan = pan + properties.getProperty("PAN"); - if (trailCode != 3) runProcess(pan, ".chk"); - runProcess(pan + " -d", ".d"); - - // Read the file created by -d - read.createStatements(); - // Read the file created by -DCHECK and never claim - if (trailCode != 3) read.readCheckFile(); - - // Read the trail file - if ((trailCode == 1) || (trailCode == 2)) { - read.readTrail(); - new SetTrail(this).setTrail(); - } - - // Write output files - if (debug || (trailCode == 3)) - write.writeDebug(); - if (format.equals("fsm")) - write.writeFSMGraph(); - else - write.writeDotGraph(); - - progress("Done"); - return true; - } - - // Display progress messages in text area of jSpin or on standard output - void progress(String s) { - if (s == null) - return; - if (area == null) { - System.out.println(s); - return; - } - area.append(s + '\n'); - int last = area.getText().length(); - try { - area.scrollRectToVisible(area.modelToView(last)); - area.setCaretPosition(last); - } - catch (javax.swing.text.BadLocationException e) { - System.err.println( - "Error setting caret position when writing\n" + s + "\n"); - } - } - - // Print error message and exit - static void error(String e) { - System.err.println(e); - System.exit(1); - } - - // Print file error message and exit - void fileError(String ext) { - String s = "FILE ERROR " + fileName + ext; - if (area == null) error(s); else progress(s); - } - - // Main method for running independently of jSpin - public static void main(String[] args) { - if (args.length == 0) error(Config.USAGE); - File file = new File(args[args.length-1]); - String fileName = file.getName(); - String root; - String extension = ""; - if (fileName.lastIndexOf('.') != -1) { - extension = fileName.substring(fileName.lastIndexOf('.')); - } - if (file.getParentFile() == null) - root = ""; - else - root = file.getParentFile().getAbsolutePath(); - fileName = root + File.separator + - fileName.substring(0, fileName.lastIndexOf('.')); - - boolean debug = false; - boolean automata = false; - int trailCode = 0; - int dotSize = 1; - int trailStyle = 0; - String format = "png"; - int numProcs = 0; - // Variable names for automatic writing of never claim - ArrayList vars = new ArrayList(Config.INITIAL); - - for (int i = 0; i < args.length-1; i++) - if (args[i].equals("-dot")) format = "dot"; - else if (args[i].equals("-fsm")) format = "fsm"; - else if (args[i].equals("-a")) automata = true; - else if (args[i].equals("-debug")) debug = true; - else if (args[i].equals("-small")) dotSize = 0; - else if (args[i].equals("-bold")) trailStyle = 1; - else if (args[i].equals("-t1")) trailCode = 1; - else if (args[i].equals("-t2")) trailCode = 2; - else if (args[i].startsWith("-T")) - format = args[i].substring(2); - else if (args[i].startsWith("-p")) - try { - numProcs = Integer.parseInt(args[i].substring(2)); - } catch (NumberFormatException e) { - error(Config.USAGE); - } - else if (args[i].startsWith("-v")) - vars.add(args[i].substring(2)); - else error(Config.USAGE); - - if (!automata && (numProcs <= 0)) error(Config.USAGE); - - String[] varArray = new String[vars.size()]; - varArray = vars.toArray(varArray); - - Properties properties = new Properties(); - Config.init(properties); - if (automata) { - debug = true; - trailCode = 3; - } - SpinSpider spd = new SpinSpider( - fileName, extension, format, numProcs, varArray, - debug, trailCode, dotSize, trailStyle, - null, properties); - if (!spd.runSpider()) return; - if (automata) - new DrawAutomata(spd).drawAutomata(); - } -} +/* + SpinSpider - Use Spin to Create State Transition Diagrams + Copyright 2005 by Mordechai (Moti) Ben-Ari. + +This program 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. +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. +*/ + +//package com.spinroot.jspin.com.spinroot.spinSpider; +package com.spinroot.spinSpider; + +import java.io.*; +import java.util.ArrayList; +import java.util.Properties; + +public class SpinSpider { + + // The following two variables are passed from jSpin + // For standalone execution, properties is set in the main method + // and output is to standard output + Properties properties; + String fileName; // File name (without extension) + String extension; // Extension of Promela file name + String format; // Graph format (dot/fsm/png ...) + int trailCode; // Use trail file to draw or emphasize a computation + int dotSize; // Size of dot graph + int trailStyle; // Style of trail in dot graph color/bold + // Databases + ArrayList states = + new ArrayList<>(Config.INITIAL); + ArrayList statements = + new ArrayList<>(Config.INITIAL); + ArrayList transitions = + new ArrayList<>(Config.INITIAL); + ArrayList trails = + new ArrayList<>(Config.INITIAL); + // For FSM we need to compute the number of statements per process + ArrayList statementsPerProcess = + new ArrayList<>(Config.INITIAL); + private javax.swing.JTextArea area; + private boolean debug; // Write debug file + // For writing never claim: + private int numProcs; // Number of processes - + // write never claim if numProcs > 0 + private String[] vars; // Names of variables + + public SpinSpider( + String fileName, + String extension, + String format, + int numProcs, + String[] vars, + boolean debug, + int trailCode, + int dotSize, + int trailStyle, + javax.swing.JTextArea area, + Properties properties) { + this.fileName = fileName; + this.extension = extension; + this.format = format; + this.numProcs = numProcs; + this.vars = vars; + this.debug = debug; + this.trailCode = trailCode; + this.dotSize = dotSize; + this.trailStyle = trailStyle; + this.area = area; + this.properties = properties; + State.numProcs = 0; + State.numVars = 0; + } + + // Create array of tokens from a string for ProcessBuilder + private static String[] stringToArray(String s) { + java.util.StringTokenizer st = new java.util.StringTokenizer(s); + int count = st.countTokens(); + String[] sa = new String[count]; + for (int i = 0; i < count; i++) + sa[i] = st.nextToken(); + return sa; + } + + // Print error message and exit + static void error(String e) { + System.err.println(e); + System.exit(1); + } + + // Main method for running independently of jSpin + public static void main(String[] args) { + if (args.length == 0) error(Config.USAGE); + File file = new File(args[args.length - 1]); + String fileName = file.getName(); + String root; + String extension = ""; + if (fileName.lastIndexOf('.') != -1) { + extension = fileName.substring(fileName.lastIndexOf('.')); + } + if (file.getParentFile() == null) + root = ""; + else + root = file.getParentFile().getAbsolutePath(); + fileName = root + File.separator + + fileName.substring(0, fileName.lastIndexOf('.')); + + boolean debug = false; + boolean automata = false; + int trailCode = 0; + int dotSize = 1; + int trailStyle = 0; + String format = "png"; + int numProcs = 0; + // Variable names for automatic writing of never claim + ArrayList vars = new ArrayList(Config.INITIAL); + + for (int i = 0; i < args.length - 1; i++) + if (args[i].equals("-dot")) format = "dot"; + else if (args[i].equals("-fsm")) format = "fsm"; + else if (args[i].equals("-a")) automata = true; + else if (args[i].equals("-debug")) debug = true; + else if (args[i].equals("-small")) dotSize = 0; + else if (args[i].equals("-bold")) trailStyle = 1; + else if (args[i].equals("-t1")) trailCode = 1; + else if (args[i].equals("-t2")) trailCode = 2; + else if (args[i].startsWith("-T")) + format = args[i].substring(2); + else if (args[i].startsWith("-p")) + try { + numProcs = Integer.parseInt(args[i].substring(2)); + } catch (NumberFormatException e) { + error(Config.USAGE); + } + else if (args[i].startsWith("-v")) + vars.add(args[i].substring(2)); + else error(Config.USAGE); + + if (!automata && (numProcs <= 0)) error(Config.USAGE); + + String[] varArray = new String[vars.size()]; + varArray = vars.toArray(varArray); + + Properties properties = new Properties(); + Config.init(properties); + if (automata) { + debug = true; + trailCode = 3; + } + SpinSpider spd = new SpinSpider( + fileName, extension, format, numProcs, varArray, + debug, trailCode, dotSize, trailStyle, + null, properties); + if (!spd.runSpider()) return; + if (automata) + new DrawAutomata(spd).drawAutomata(); + } + + // Build a process and run it + // command is the command string with parameters + // ext is the extension for redirecting standard output + // if null, output is sent to System.out + void runProcess(String command, String ext) { + PrintWriter outWriter = null; + progress("Running " + command); + if (ext != null) + try { + outWriter = new PrintWriter(new FileWriter(fileName + ext)); + } catch (IOException e) { + fileError(ext); + } + try { + ProcessBuilder pb = new ProcessBuilder(stringToArray(command)); + File pf = new File(fileName).getParentFile(); + if (pf != null) pb.directory(pf.getCanonicalFile()); + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader input = + new BufferedReader(new InputStreamReader(p.getInputStream())); + String s; + while (true) { + s = input.readLine(); + if (s == null) break; + if (ext == null) System.out.println(s); + else outWriter.println(s); + } + p.waitFor(); + if (ext != null) outWriter.close(); + } catch (IOException e) { + progress("IO exception " + e.getMessage() + + " while executing " + command); + } catch (InterruptedException e) { + progress("Interrupted exception while executing " + command); + } + } + + // This method runs SpinSpider + public boolean runSpider() { + progress(Config.TITLE); + // Create objects for reading and writing files + Write write = new Write(this, fileName); + Read read = new Read(this, fileName, properties); + + // Write never claim if requested + String never = ""; + if (trailCode != 3) { + if (!write.writeNeverClaim(numProcs, vars)) return false; + never = " -N " + fileName + ".nvr "; + } + + // Run Spin and C compiler + runProcess(properties.getProperty("SPIN") + + " -a -o3 " + never + fileName + extension, null); + runProcess(properties.getProperty("C_COMPILER") + + " -DCHECK -DSAFETY -DPRINTF -DNOREDUCE -o pan pan.c", null); + + // Run pan twice: once for -DCHECK file and once for -d file + String pan = ""; + try { + File f = new File(fileName).getParentFile(); + if (f != null) + pan = f.getCanonicalPath() + java.io.File.separator; + } catch (IOException e) { + } + pan = pan + properties.getProperty("PAN"); + if (trailCode != 3) runProcess(pan, ".chk"); + runProcess(pan + " -d", ".d"); + + // Read the file created by -d + read.createStatements(); + // Read the file created by -DCHECK and never claim + if (trailCode != 3) read.readCheckFile(); + + // Read the trail file + if ((trailCode == 1) || (trailCode == 2)) { + read.readTrail(); + new SetTrail(this).setTrail(); + } + + // Write output files + if (debug || (trailCode == 3)) + write.writeDebug(); + if (format.equals("fsm")) + write.writeFSMGraph(); + else + write.writeDotGraph(); + + progress("Done"); + return true; + } + + // Display progress messages in text area of jSpin or on standard output + void progress(String s) { + if (s == null) + return; + if (area == null) { + System.out.println(s); + return; + } + area.append(s + '\n'); + int last = area.getText().length(); + try { + area.scrollRectToVisible(area.modelToView(last)); + area.setCaretPosition(last); + } catch (javax.swing.text.BadLocationException e) { + System.err.println( + "Error setting caret position when writing\n" + s + "\n"); + } + } + + // Print file error message and exit + void fileError(String ext) { + String s = "FILE ERROR " + fileName + ext; + if (area == null) error(s); + else progress(s); + } +} diff --git a/spinSpider/State.java b/src/main/java/com/spinroot/spinSpider/State.java similarity index 64% rename from spinSpider/State.java rename to src/main/java/com/spinroot/spinSpider/State.java index 7d76d13..d3dbcd3 100644 --- a/spinSpider/State.java +++ b/src/main/java/com/spinroot/spinSpider/State.java @@ -1,35 +1,36 @@ -/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* - * Definine a state of the state transition diagram -*/ - -package spinSpider; -class State { - // Static variables - // The number of processes and variables is - // the same for all *spd* lines printed out - static int numProcs; - static int numVars; - - // Variables for each state - int[] s; // pc_value for each process - String[] vname; // Name for each variable - String[] v; // Value for each variable - boolean inTrail; // Is this state in the trail? - - public State(int[] st, String[] vn, String[] vr) { - s = st; - vname = vn; - v = vr; - inTrail = false; - } - - public String toString() { - String str = "("; - for (int proc = 0; proc < numProcs; proc++) - str = str + ((proc == 0) ? "" : ",") + s[proc]; - for (int var = 0; var < numVars; var++) - str = str + "," + vname[var] + "=" + v[var]; - return str + ")" + (inTrail ? " *" : ""); - } -} +/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* + * Definine a state of the state transition diagram +*/ + +package com.spinroot.spinSpider; + +class State { + // Static variables + // The number of processes and variables is + // the same for all *spd* lines printed out + static int numProcs; + static int numVars; + + // Variables for each state + int[] s; // pc_value for each process + String[] vname; // Name for each variable + String[] v; // Value for each variable + boolean inTrail; // Is this state in the trail? + + public State(int[] st, String[] vn, String[] vr) { + s = st; + vname = vn; + v = vr; + inTrail = false; + } + + public String toString() { + StringBuilder str = new StringBuilder("("); + for (int proc = 0; proc < numProcs; proc++) + str.append((proc == 0) ? "" : ",").append(s[proc]); + for (int var = 0; var < numVars; var++) + str.append(",").append(vname[var]).append("=").append(v[var]); + return str + ")" + (inTrail ? " *" : ""); + } +} diff --git a/spinSpider/Statement.java b/src/main/java/com/spinroot/spinSpider/Statement.java similarity index 63% rename from spinSpider/Statement.java rename to src/main/java/com/spinroot/spinSpider/Statement.java index 939b5b1..df55205 100644 --- a/spinSpider/Statement.java +++ b/src/main/java/com/spinroot/spinSpider/Statement.java @@ -1,39 +1,40 @@ -/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* - * Process a source statement -*/ - -package spinSpider; -class Statement { - int process; // Process where the statement is declared - int sourceState; // Source state - int targetState; // Target state - int id; // Used for trail - boolean atomic; // Atomic statement (for automata) - int line; // Line number of source statement - String source; // Source code statement - - public Statement(int p, int s, int t, int i, boolean a, int l, String src) { - process = p; - sourceState = s; - id = i; - targetState = t; - atomic = a; - line = l; - if (src.indexOf("printf") != -1) // Remove printf and quotes - src = src.substring(src.indexOf("printf")+8, src.indexOf("\\n")); - src = src.replaceAll("[()]", ""); // Remove parentheses - source = src.trim(); - } - - public String toString() { - return - "process=" + process + - ", source=" + sourceState + - ", target=" + targetState + - ", id=" + id + - (atomic ? ", atomic" : "") + - ", line=" + line + - "." + source; - } +/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* + * Process a source statement +*/ + +package com.spinroot.spinSpider; + +class Statement { + int process; // Process where the statement is declared + int sourceState; // Source state + int targetState; // Target state + int id; // Used for trail + boolean atomic; // Atomic statement (for automata) + int line; // Line number of source statement + String source; // Source code statement + + public Statement(int p, int s, int t, int i, boolean a, int l, String src) { + process = p; + sourceState = s; + id = i; + targetState = t; + atomic = a; + line = l; + if (src.indexOf("printf") != -1) // Remove printf and quotes + src = src.substring(src.indexOf("printf") + 8, src.indexOf("\\n")); + src = src.replaceAll("[()]", ""); // Remove parentheses + source = src.trim(); + } + + public String toString() { + return + "process=" + process + + ", source=" + sourceState + + ", target=" + targetState + + ", id=" + id + + (atomic ? ", atomic" : "") + + ", line=" + line + + "." + source; + } } \ No newline at end of file diff --git a/spinSpider/Trail.java b/src/main/java/com/spinroot/spinSpider/Trail.java similarity index 87% rename from spinSpider/Trail.java rename to src/main/java/com/spinroot/spinSpider/Trail.java index 97fa504..4df4c2d 100644 --- a/spinSpider/Trail.java +++ b/src/main/java/com/spinroot/spinSpider/Trail.java @@ -1,16 +1,17 @@ -/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* Transitions obtained by processing New/Old/Up/Down in -DCHECK file - */ - -package spinSpider; -class Trail { - int id; - - public Trail(int i) { - id = i; - } - - public String toString() { - return "id " + id; - } -}; +/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* Transitions obtained by processing New/Old/Up/Down in -DCHECK file + */ + +package com.spinroot.spinSpider; + +class Trail { + int id; + + public Trail(int i) { + id = i; + } + + public String toString() { + return "id " + id; + } +} diff --git a/spinSpider/Transition.java b/src/main/java/com/spinroot/spinSpider/Transition.java similarity index 61% rename from spinSpider/Transition.java rename to src/main/java/com/spinroot/spinSpider/Transition.java index 93f999c..79ff828 100644 --- a/spinSpider/Transition.java +++ b/src/main/java/com/spinroot/spinSpider/Transition.java @@ -1,21 +1,22 @@ -/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ -/* - * Defining a transition of the state transition diagram -*/ - -package spinSpider; -class Transition { - int head; // head state - int tail; // tail state - boolean inTrail; // Is this transition in the trail? - - public Transition(int h, int t) { - head = h; - tail = t; - inTrail = false; - } - - public String toString() { - return head + " -> " + tail + (inTrail ? " *" : ""); - } -} +/* Copyright 2005-6 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* + * Defining a transition of the state transition diagram +*/ + +package com.spinroot.spinSpider; + +class Transition { + final int head; // head state + final int tail; // tail state + boolean inTrail; // Is this transition in the trail? + + public Transition(int head, int tail) { + this.head = head; + this.tail = tail; + inTrail = false; + } + + public String toString() { + return head + " -> " + tail + (inTrail ? " *" : ""); + } +} diff --git a/src/main/java/com/spinroot/spinSpider/Write.java b/src/main/java/com/spinroot/spinSpider/Write.java new file mode 100644 index 0000000..f3a2d6e --- /dev/null +++ b/src/main/java/com/spinroot/spinSpider/Write.java @@ -0,0 +1,270 @@ +/* Copyright 2005-7 by Mordechai (Moti) Ben-Ari. See copyright.txt */ +/* + * Write the output in different formats +*/ + +package com.spinroot.spinSpider; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; + +public class Write { + SpinSpider spd; + + Write(SpinSpider s, String f) { + spd = s; + } + + // Write the never claim from the number of processes and + // the names of the variables + boolean writeNeverClaim(int numProcs, String[] vars) { + PrintWriter neverWriter = null; + spd.progress("Writing never claim"); + if (vars.length == 0) { + spd.progress("No variables for never claim"); + return false; + } + try { + neverWriter = new PrintWriter(new FileWriter(spd.fileName + ".nvr")); + } catch (IOException e) { + spd.fileError(".nvr"); + } + + neverWriter.print("never {\n\tdo\n\t:: printf(\"*spd* " + numProcs); + for (int i = 0; i < numProcs; i++) + neverWriter.print(" %d"); + neverWriter.print(" " + vars.length); + for (int i = 0; i < vars.length; i++) + neverWriter.print(" " + vars[i] + " %d"); + neverWriter.print("\\n\",\n\t\t"); + for (int i = 0; i < numProcs; i++) + neverWriter.print("pc_value(" + i + "), "); + for (int i = 0; i < vars.length; i++) + neverWriter.print((i == 0 ? "" : ", ") + vars[i]); + neverWriter.println(")\n\tod\n}"); + neverWriter.close(); + return true; + } + + // Write the graph in dot format - nodes and edges + // trailCode = 0 (no trail), 1 (emphasize trail), 2 (just trail) + void writeDotGraph() { + PrintWriter graphWriter = null; + String fn = spd.fileName + Config.names[spd.trailCode]; + String label; // Building the label in this string + int numStates = 0; // For printing a node number + String[] dotPrologue = + spd.dotSize == 0 ? Config.smallDotPrologue : Config.largeDotPrologue; + String dotTrail = + spd.trailStyle == 0 ? Config.dotTrailColor : Config.dotTrailBold; + + spd.progress("Writing dot file"); + try { + graphWriter = new PrintWriter(new FileWriter(fn + ".dot")); + } catch (IOException e) { + spd.fileError(".dot"); + } + + // Write dot prologue + graphWriter.println("digraph \"" + fn + "\"" + " {"); + for (int i = 0; i < dotPrologue.length; i++) + graphWriter.println(dotPrologue[i]); + + // Write states + for (State st : spd.states) { + label = (numStates++) + " [label=\""; + for (int proc = 0; proc < State.numProcs; proc++) + for (Statement t : spd.statements) + if ((t.process == proc) && + (t.sourceState == st.s[proc])) + label = label + t.line + ". " + t.source + "\\n"; + for (int var = 0; var < State.numVars; var++) + label = label + " " + st.v[var]; + graphWriter.print(label + "\""); + if ((spd.trailCode == 1) && st.inTrail) + graphWriter.print(dotTrail); + if ((spd.trailCode == 2) && !st.inTrail) + graphWriter.print(" style = invis "); + graphWriter.println("];"); + } + + // Write transitions + for (Transition t : spd.transitions) { + graphWriter.print(t.head + " -> " + t.tail); + if ((spd.trailCode == 1) && t.inTrail) + graphWriter.print(" [" + dotTrail + "]"); + if ((spd.trailCode == 2) && !t.inTrail) + graphWriter.print(" [ style = invis ]"); + graphWriter.println(";"); + } + graphWriter.println("}"); + graphWriter.close(); + if ((spd.trailCode != 3) && !spd.format.equals("dot")) + spd.runProcess(spd.properties.getProperty("DOT") + + " -T" + spd.format + + " -o " + fn + "." + spd.format + " " + + fn + ".dot", null); + } + + // Write the graph in fsm format + // This format is used by tools developed at the + // Eindhoven University of Technology + void writeFSMGraph() { + int offset; + PrintWriter graphWriter = null; + spd.progress("Writing fsm file"); + try { + graphWriter = new PrintWriter(new FileWriter(spd.fileName + ".fsm")); + } catch (IOException e) { + spd.fileError(".fsm"); + } + + // If the program terminates there is an end statement + // that is not a "source" in the -d file + // Add dummy statements at the end of the "statements" data structure + // spp1 is the original statementsPerProcess + // spp2 is statementsPerProcess with added dummy statements + int[] spp1 = new int[spd.statementsPerProcess.size()]; + int[] spp2 = new int[spd.statementsPerProcess.size()]; + for (int i = 0; i < spp1.length; i++) { + spp1[i] = spd.statementsPerProcess.get(i).intValue(); + spp2[i] = spp1[i]; + } + boolean[] endStates = new boolean[State.numProcs]; + for (int i = 0; i < spd.statements.size(); i++) { + Statement st = spd.statements.get(i); + if ((st.targetState == 0) && (!endStates[st.process])) { + spd.statements.add(new Statement(st.process, 0, 0, 0, false, 0, "")); + spp2[st.process]++; + endStates[st.process] = true; + } + } + + // Compute fan in and fan out of each node + int[] fanIn = new int[spd.states.size()]; + int[] fanOut = new int[spd.states.size()]; + for (int i = 0; i < spd.transitions.size(); i++) { + fanIn[spd.transitions.get(i).tail]++; + fanOut[spd.transitions.get(i).head]++; + } + // Compute the maximum fan in and fan out in the diagram + int maxFanIn = 0, maxFanOut = 0; + for (int i = 0; i < spd.states.size(); i++) { + if (fanIn[i] > maxFanIn) maxFanIn = fanIn[i]; + if (fanOut[i] > maxFanOut) maxFanOut = fanOut[i]; + } + maxFanIn++; + maxFanOut++; + + // Processes: + // "p" + number of process + "(" + statements per process + ")" + // + "String" + list of statements + offset = 0; + for (int proc = 0; proc < State.numProcs; proc++) { + graphWriter.print("p" + (proc + 1) + + "(" + spp2[proc] + ") String"); + for (int stmt = 0; stmt < spp1[proc]; stmt++) { + Statement stm = spd.statements.get(offset + stmt); + graphWriter.print(" \"" + stm.line + "," + stm.source + "\""); + } + offset = offset + spp1[proc]; + if (spp2[proc] > spp1[proc]) + graphWriter.print(" \" end state \""); + graphWriter.println(); + } + + // Variables: + // name of variable + "(" + number of values + ")" + // + "Nat" + list of values + for (int var = 0; var < State.numVars; var++) { + int max = 0; + for (State st : spd.states) { + int val = Integer.parseInt(st.v[var]); + if (val > max) max = val; + } + graphWriter.print(spd.states.get(0).vname[var] + "(" + (max + 1) + ") Nat"); + for (int i = 0; i <= max; i++) + graphWriter.print(" \"" + i + "\""); + graphWriter.println(); + } + + // Fan in, fan out, node nr + graphWriter.print("fan_in(" + maxFanIn + ") Nat"); + for (int i = 0; i < maxFanIn; i++) + graphWriter.print(" \"" + i + "\""); + graphWriter.println(); + graphWriter.print("fan_out(" + maxFanOut + ") Nat"); + for (int i = 0; i < maxFanOut; i++) + graphWriter.print(" \"" + i + "\""); + graphWriter.println(); + graphWriter.println("node_nr(0)"); + graphWriter.println("---"); + + // States: + // Process location counters (relative to lists above!) + // Values of variables + // Fan-in and fan-out + int stateCount = 0; + for (State st : spd.states) { + offset = 0; + for (int proc = 0; proc < State.numProcs; proc++) { + boolean found = false; + for (int i = 0; i < spp1[proc]; i++) + if (spd.statements.get(offset + i).sourceState == st.s[proc]) { + graphWriter.print(i + " "); + found = true; + break; + } + if (!found) { + graphWriter.print((spp2[proc] - 1) + " "); + } + offset = offset + spp1[proc]; + } + for (int var = 0; var < State.numVars; var++) + graphWriter.print(st.v[var] + " "); + graphWriter.print(fanIn[stateCount] + " " + + fanOut[stateCount] + " " + (stateCount + 1)); + stateCount++; + graphWriter.println(); + } + graphWriter.println("---"); + + // Transitions + for (Transition t : spd.transitions) + graphWriter.println((t.head + 1) + " " + (t.tail + 1)); + graphWriter.close(); + } + + // Write debug file using toString defined in each class + void writeDebug() { + PrintWriter debugWriter = null; + spd.progress("Writing debug file"); + try { + debugWriter = new PrintWriter( + new FileWriter(spd.fileName + ".dbg")); + } catch (IOException e) { + spd.fileError(".dbg"); + } + + debugWriter.println("States"); + int n = 0; + for (State s : spd.states) + debugWriter.println((n++) + ". " + s); + + debugWriter.println("\nTransitions"); + for (Transition t : spd.transitions) + debugWriter.println(t); + + debugWriter.println("\nStatements from -d file"); + for (Statement st : spd.statements) + debugWriter.println(st); + + if (spd.trailCode > 0) { + debugWriter.println("\nTrail"); + for (Trail tr : spd.trails) + debugWriter.println(tr); + } + debugWriter.close(); + } +} diff --git a/txt/copyright.txt b/txt/copyright.txt index 25631ca..1bd8720 100644 --- a/txt/copyright.txt +++ b/txt/copyright.txt @@ -1,17 +1,17 @@ - jSpin - Java Graphical User Interface for Spin - SpinSpider - Automatic Generation of State Transition Diagrams - (See title bar for version number) - Copyright 2003-10 by Mordechai (Moti) Ben-Ari. - -This program 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. -This program 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 this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -02111-1307, USA. + jSpin - Java Graphical User Interface for Spin + SpinSpider - Automatic Generation of State Transition Diagrams + (See title bar for version number) + Copyright 2003-10 by Mordechai (Moti) Ben-Ari. + +This program 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. +This program 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 this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. diff --git a/txt/help.txt b/txt/help.txt index 6bf110d..5d7064c 100644 --- a/txt/help.txt +++ b/txt/help.txt @@ -1,80 +1,80 @@ - jSpin - Java Graphical User Interface for Spin - SpinSpider - Automatic Generation of State Transition Diagrams - (See title bar for version number) - Copyright 2003-10 by Mordechai (Moti) Ben-Ari. - -jSpin is a graphical user interface for the Spin Model Checker -that is used for verifying concurrent and distributed programs. -The Spin website is http://spinroot.com. -The jSpin website is -http://stwww.weizmann.ac.il/g-cs/benari/jspin/. - -PLEASE READ THE MANUALS jspin-user.pdf and spider-use.pdf!! -In particular, read the sections on installation, -configuration and troubleshooting. -This Help file presents a short description of the menus. - -File: -New, Open, Save, Save As, and Exit are standard. -Switch file closes the current file and opens the previous one. - -Editor: -Undo, Redo, Copy, Cut, Paste, Find and Find again are standard. - -Spin: -Run Spin in one of five modes: -Check runs a syntax check. -Random runs a random simulation. -Interactive runs an interactive simulation. -Verify runs an verification. -Guided runs a guided simulation using the trail file created -by the execution of the analyzer. - -Convert: -Load loads a .prp file into the LTL formula field: -Clear clears the field. -Translate translates it into a never claim stored in a .ltl file. -LTL Name selects an internal LTL formula to use for verification. - -Options - change the option strings used with Spin: -Common is used to select which data to display for Random, -Interactive and Trail: statements, local and global variables -and messages sent and received. -The next options are for running the Spin sequence: - Spin: Check, Random, Interactive, Verify, Trail. - C Compiler. - Pan. -Default restores the defaults of all options and settings. -Save saves the options, settings and the current directory for File/Open. - -Settings - change settings for verification and display: -Max steps for Random, Interactive and Trail modes. -Max depth for search depth when running the pan verifier. -Seed - if non-zero its value is used for Random simulation. -Weak fairness during verification. -Safety, Acceptance, Non-progress verification modes. - -Output - control display of filtered Spin output: -Maximize the right text area that displays the output. -Exclude variables - exclude (and include) these variables in the display. -Exclude statements - exclude (and include) these statements in the display. -Variable width - width of the columns used to display the variable values. -Save output - saves the filtered Spin output in a file with extension .out. -Raw output - saves the unfiltered Spin output in a file with extension .raw. -Display raw - displays this file for debugging purposes. - -SpinSpider: -Display debug - display the debug file created by SpinSpider. -SpiderSpider - popup SpinSpider dialog: - Format - graphical output format - Dot size - size parameter for dot - Trail style - emphasize with color or bold - Variables - a list of the variables in the program must be given - Processes - the number of processes - Radio buttons: - No trail - display state diagram without trail (if any) - Emphasize/only trail - a trail from a verification must exist - Automata - display the processes as automata - -Help: -Help and About are standard. + jSpin - Java Graphical User Interface for Spin + SpinSpider - Automatic Generation of State Transition Diagrams + (See title bar for version number) + Copyright 2003-10 by Mordechai (Moti) Ben-Ari. + +jSpin is a graphical user interface for the Spin Model Checker +that is used for verifying concurrent and distributed programs. +The Spin website is http://spinroot.com. +The jSpin website is +http://stwww.weizmann.ac.il/g-cs/benari/com.spinroot.jspin/. + +PLEASE READ THE MANUALS com.spinroot.jspin-user.pdf and spider-use.pdf!! +In particular, read the sections on installation, +configuration and troubleshooting. +This Help file presents a short description of the menus. + +File: +New, Open, Save, Save As, and Exit are standard. +Switch file closes the current file and opens the previous one. + +Editor: +Undo, Redo, Copy, Cut, Paste, Find and Find again are standard. + +Spin: +Run Spin in one of five modes: +Check runs a syntax check. +Random runs a random simulation. +Interactive runs an interactive simulation. +Verify runs an verification. +Guided runs a guided simulation using the trail file created +by the execution of the analyzer. + +Convert: +Load loads a .prp file into the LTL formula field: +Clear clears the field. +Translate translates it into a never claim stored in a .ltl file. +LTL Name selects an internal LTL formula to use for verification. + +Options - change the option strings used with Spin: +Common is used to select which data to display for Random, +Interactive and Trail: statements, local and global variables +and messages sent and received. +The next options are for running the Spin sequence: + Spin: Check, Random, Interactive, Verify, Trail. + C Compiler. + Pan. +Default restores the defaults of all options and settings. +Save saves the options, settings and the current directory for File/Open. + +Settings - change settings for verification and display: +Max steps for Random, Interactive and Trail modes. +Max depth for search depth when running the pan verifier. +Seed - if non-zero its value is used for Random simulation. +Weak fairness during verification. +Safety, Acceptance, Non-progress verification modes. + +Output - control display of filtered Spin output: +Maximize the right text area that displays the output. +Exclude variables - exclude (and include) these variables in the display. +Exclude statements - exclude (and include) these statements in the display. +Variable width - width of the columns used to display the variable values. +Save output - saves the filtered Spin output in a file with extension .out. +Raw output - saves the unfiltered Spin output in a file with extension .raw. +Display raw - displays this file for debugging purposes. + +SpinSpider: +Display debug - display the debug file created by SpinSpider. +SpiderSpider - popup SpinSpider dialog: + Format - graphical output format + Dot size - size parameter for dot + Trail style - emphasize with color or bold + Variables - a list of the variables in the program must be given + Processes - the number of processes + Radio buttons: + No trail - display state diagram without trail (if any) + Emphasize/only trail - a trail from a verification must exist + Automata - display the processes as automata + +Help: +Help and About are standard.