pntool-developers Mailing List for A Concurrency Tool Suite
Brought to you by:
compaqdrew,
miordache
You can subscribe to this list here.
2009 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
(69) |
Jul
(86) |
Aug
(33) |
Sep
|
Oct
|
Nov
|
Dec
|
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
|
Feb
|
Mar
|
Apr
(3) |
May
(3) |
Jun
(1) |
Jul
(10) |
Aug
(2) |
Sep
(1) |
Oct
|
Nov
|
Dec
|
2012 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
(2) |
Sep
|
Oct
|
Nov
|
Dec
|
From: <mio...@us...> - 2012-08-15 23:47:24
|
Revision: 265 http://pntool.svn.sourceforge.net/pntool/?rev=265&view=rev Author: miordache Date: 2012-08-15 23:47:15 +0000 (Wed, 15 Aug 2012) Log Message: ----------- version 1.2 Modified Paths: -------------- present_version/LICENSE/README.txt present_version/Makefile-linux.mak present_version/doc/GettingStarted.htm present_version/examples/README present_version/examples/inteq.sp present_version/newcodegen/Makefile-cygwin.mak present_version/newcodegen/Makefile-linux.mak present_version/newcodegen/ProcessTemplate.c present_version/newcodegen/SupervisorTemplate.c present_version/newcodegen/codegen.h present_version/newcodegen/filltmpl.lex present_version/newcodegen/plantCompiler.c present_version/newcodegen/spcommon.h present_version/newcodegen/supervisorCompiler.c present_version/parser/Makefile present_version/parser/actions.c present_version/parser/read.h present_version/parser/read.lex present_version/parser/read.y present_version/pnheaders/general.c present_version/pnheaders/insert.c present_version/pnheaders/insert.h present_version/pnheaders/main_function2.c present_version/pnheaders/pns.c present_version/pnheaders/pns.h present_version/spnbox/matrixmath.c present_version/spnbox/spnbox.h Added Paths: ----------- present_version/doc/format2.sp present_version/examples/reader.sp present_version/newcodegen/Makefile present_version/newcodegen/fl2str.lex Removed Paths: ------------- present_version/README.txt present_version/doc/format2.hl present_version/doc/input2.sp Modified: present_version/LICENSE/README.txt =================================================================== --- present_version/LICENSE/README.txt 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/LICENSE/README.txt 2012-08-15 23:47:15 UTC (rev 265) @@ -2,8 +2,6 @@ The software uses third-party code as follows. -ANTLR has been used to generate a translator for specifications written in a Petri net description language. ANTLR is released under the BSD license. See ANTLR3_LICENSE.txt. - LPSOLVE is used to solve the linear and integer linear programs of the spnbox functions. LPSOLVE is released under the LGPL license. MEMWATCH has been used to debug the spnbox functions. MEMWATCH is released under the GPL license. Modified: present_version/Makefile-linux.mak =================================================================== --- present_version/Makefile-linux.mak 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/Makefile-linux.mak 2012-08-15 23:47:15 UTC (rev 265) @@ -30,4 +30,3 @@ cd $(CODEGEN); make -f Makefile-linux.mak clean cd $(TRANSLATOR); make clean cd $(SPNBOX); make clean - Deleted: present_version/README.txt =================================================================== --- present_version/README.txt 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/README.txt 2012-08-15 23:47:15 UTC (rev 265) @@ -1,10 +0,0 @@ -After building the software you may use it as follows: - -1) Write the specification file. - -2) Copy ProcessTemplate.c, SupervisorTemplate.c, and spcommon.h from newcodegen to the working directory. These are skeleton files for the concurrency code. - -3) Run the concurrency software. This will build the source code files specified in the specification file. - -4) Build your application with the generated makefile. - Modified: present_version/doc/GettingStarted.htm =================================================================== --- present_version/doc/GettingStarted.htm 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/doc/GettingStarted.htm 2012-08-15 23:47:15 UTC (rev 265) @@ -9,24 +9,28 @@ <p><b>A Concurrency Tool Suite--Getting Started</b> -<p>The software is intended for Unix operating systems. If you use a Windows computer, you may download cygwin from <a href="http://www.cygwin.com">http://www.cygwin.com</a>. The cygwin program runs in Windows and emulates Linux. Thus, you may run the software in Windows by means of cygwin. +<p>The software is intended for Unix operating systems. It can be used also in Windows within the <a href="http://www.cygwin.com">cygwin</a> environment. +<ul> +<li>To build the software in Linux, open a terminal program and run <i>make -f Makefile-linux.mak</i> in the main directory of the source code. +<li>To build the software in cygwin, open a terminal program and run <i>make -f Makefile-cygwin.mak</i> in the main directory of the source code. If your gcc version supports the <i>-pthread</i> option, you may use <i>Makefile-linux.mak</i> instead of <i>Makefile-cygwin.mak</i>. +</ul> +The executable file of the program is called <i>ct</i>. It is generated in the same directory. -<p>To build the software, type the command "make" in the main directory of the source code. This will execute the commands of the file called "Makefile" and build an executable file called "ct.exe". In spite of its extension, this is not a Windows executable file. It can only be executed within cygwin or in Unix. +<p>To see the command line options of the program, run <i>./ct</i> in the terminal window. To generate a concurrent program based on a specification file <i>spec.sp</i> that is located in the same directory, run <i>./ct spec.sp</i>. -<p>If you run ct.exe you can see a description of its options. - -<p>In order to run the program on a specification file: +<p>In order to build an application using <i>ct</i>: <ul> -<li> Copy the files SupervisorTemplate.c ProcessTemplate.c and spcommon.h from the newcodegen directory to your working directory. -<li> Run ct.exe on your specification file. For instance, if spec.sp is the specification file, you could type "./ct.exe -d4 spec.sp". The d4 option can be used in order to have ct.exe display messages describing what it is doing. -<li>If the specification file is correct, ct.exe will exit normally and create a number of sources files allowing you to build your program. -<li> You can build your program using "make" and the makefile generated by ct.exe. For instance, to build the program from the source code generated for spec.sp, type "make -f spec.mak". -<li> The previous step will generate an executable file. When you run it, you can force it to terminate with Ctrl-c. This should terminate also all other processes (if any) started by the executable file. +<li>Run <i>ct</i> on the specification file. +<li>If the specification file is correct, <i>ct</i> will exit normally and generate a header file <i>spcommon.h</i>, several C files, and a make file. +<li>The application can be built using <i>make</i> and the make file generated by <i>ct</i>. For instance, if <i>ct</i> is run on a specification file <i>spec.sp</i>, it will generate several files including a make file <i>spec.mak</i>.Then, the application can be built with the command <i>make -f spec.mak</i>. +<li>The previous step will generate an executable file. When the executable file is run, it can be terminated at any point with the SIGINT signal (that is, with <i>Ctrl-c</i> when the program is run in the foreground). This should terminate the main process together with its child processes. (Only the child processes defined in the specification file will be terminated.) +<li>Due to the somewhat large number of files that is generated, it is recommended to use a separate directory for each specification file. </ul> -<p>To create your own specification files: +<p>To create specification files: <ul> -<li>Check format2.hl for a description of the specification format. +<li>See <i>format2.sp</i> in the <i>doc</i> directory for a description of the specification format. +<li>See also the <i>examples</i> directory. </ul> @@ -34,7 +38,7 @@ <hr> <!-- Created: Fri May 13 17:16:03 CDT 2011 --> <!-- hhmts start --> -Last modified: Fri May 13 17:43:01 CDT 2011 +Last modified: Tue Aug 14 16:40:10 CDT 2012 <!-- hhmts end --> </body> </html> Deleted: present_version/doc/format2.hl =================================================================== --- present_version/doc/format2.hl 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/doc/format2.hl 2012-08-15 23:47:15 UTC (rev 265) @@ -1,188 +0,0 @@ -// This file describes the specification language. -// July 6, 2011. - -// In this document both threads and processes are called processes. - -// The specification describes processes and how they should be coordinated. -// The program implementing the specification consists of a coordinator -// that runs the processes described in the specification and supervises -// their execution. The coordinator is called supervisor. - -// The specification defines groups of processes. A group may have any number -// of processes (0, 1, 2, ...). This number may change during the execution of -// the program. The specification determines the initial number of processes -// in a group and how this number may change. Processes in a group are -// identical in the sense that they have the same executable code. However, -// processes in the same group do not have to be in the same stage of -// execution. - -// A group of processes is implemented by means of executable programs if -// it is defined with the keyword "process". Otherwise, it is implemented -// by means of threads of the supervisor if it is defined with the keyword -// "thread". - -// The following defines a group or processes - -process p1 { - - // The following defines the Petri net representation of the process - - places: p1 p2 p3 - transitions: t0 - transitions: t1 t2 t3 t4 - - // The following describes the arcs connecting places and transitions - - (p1, t0) - (p1, t1, p3) - - // A semicolon must be used between instructions on the same row - - (p3, t4, p1); (t3, p3) - - // The following arc is conditional. The generated program will - // contain an "if(i >= 1)" instruction before attempting to fire t2. Thus, - // the variable i must be defined in the context of the C code associated - // with the place p2. - - (p2, t2) {i >= 1} - -} - -// The following defines a group or processes implemented as threads - - -thread t1 { - - // The following defines the Petri net representation of the process - - places: p1 p2 p3 - transitions: t1 t2 t3 t4 - - // The following describes the arcs connecting places and transitions - - (p1, t1) - (p1, t2, p3) - (p3, t3, p2); (p2, t4, p1); - -} - - -// The Petri net associated with a supervisor is generated automatically. -// However, the user has the option to specify additional components to be -// included in the Petri net of the supervisor. The following block defines -// such a component. - -supervisor sc { - places: p1 p2 - transitions: t1 - - (p1, t1, p2) -} - - -// The following synchronizes the transition t1 of process p1 with the -// transition t3 of the process t1. - -sync p1.t1 t1.t3 - -// Constraints can be described by means of inequalities - -2*p1.q.t2 - t1.p3 <= 1 // firing vector element: process.q.transition - // marking vector element: process.place - -t1.v.t1 <= t1.v.t2 // Parikh vector element: process.v.transition - - -// The following describes the initial number of processes in each group. -// It also describes the stage in which each process should be started. - -initialize: p1(p1:1, p2:2) -initialize: t1(p2:1) sc(p1:5) - -// The group p1 will have three processes: one starting in p1 and two starting -// in p2. The group t1 will have only one process and that process will start -// in p2. Now, sc is not a process group but a supervisor component. The -// initialization of sc requests that the Petri net of sc will have an initial -// marking with 5 tokens in p1. - -// By default, a group of processes is initialized with zero processes. - -// Transitions that should be live can be specified as follows. -// NOTE: Avoid this instruction when possible, since the synthesis of a -// deadlock prevention policy is computationally intensive and can take much -// time. - -live: t1.t2 // the supervisor should ensure that the transition t2 of the - // process group t1 is live. - - -// The following blocks are OPTIONAL. - -// A segment of code can be associated with each place. The following -// instruction defines the code of the place p3 of the process p1. - -p1.p3 { - i = i + 1; - j = 10*i; -} - -// Any instructions that a process should execute when it is started -// can be specified by means of a main block - -p1.main { - i = 0; - j = 1; -} - -// Header files and other definitions that should appear in the source file of -// a process can be specified by means of an include block - -p1.include { - #include"string.h" - #define MAX 10 - - int i, j; - - struct myarray { int i; float k; }; - - static struct myarray array[MAX]; -} - -// Instructions on how to build the executable file associated with a process -// can be specified in a build block. Note that the software will replace $$$ -// with the name of the file defining the process (without extension). - -p1.build { gcc -g -o $$$.exe $$$.c } - -// Copies of a process group can be specified as follows - -p1c = p1 // p1c is another process group - -// Note that p1 has been defined with the keyword 'process'. Thus, p1c will -// also be of the type 'process'. If the copy should have a different type, -// the desired type should be stated before the assignment. - -thread p1c2 = p1 - -// On the line above, p1c2 is defined as a copy of p1 of the type 'thread'. - -// Instructions that the supervisor should execute when it is started -// can be specified by means of a main block - -main { - fprintf(stdout, "The supervisor is starting ..."); -} - -// An include block can also be defined for the supervisor - -include { - #define MAX_INP 3 - #include"ctype.h" -} - - -// The build block of the supervisor can be used to specify additional -// command line parameters that should be used when building the program - -build { -I. } Added: present_version/doc/format2.sp =================================================================== --- present_version/doc/format2.sp (rev 0) +++ present_version/doc/format2.sp 2012-08-15 23:47:15 UTC (rev 265) @@ -0,0 +1,220 @@ +// This file describes the specification language. +// Creataed on July 6, 2011. Updated in July 2012. + +// In this document both threads and processes are called processes. + +// The specification describes processes and how they should be coordinated. +// The program implementing the specification consists of a coordinator +// that runs the processes described in the specification and supervises +// their execution. The coordinator is called supervisor. + +// The specification defines groups of processes. A group may have any number +// of processes (0, 1, 2, ...). This number may change during the execution of +// the program. The specification determines the initial number of processes +// in a group and how this number may change. Processes in a group are +// identical in the sense that they have the same executable code. However, +// processes in the same group do not have to be in the same stage of +// execution. + +// A group of processes is implemented by means of executable programs if +// it is defined with the keyword "process". Otherwise, it is implemented +// by means of threads of the supervisor if it is defined with the keyword +// "thread". + +// The following defines a group or processes + +process p1 { + + // The following defines the Petri net representation of the process + + places: p1 p2 p3 + transitions: t0 + transitions: t1 t2 t3 t4 + + // The following describes the arcs connecting places and transitions + + (p1, t0) + (p1, t1, p3) + + // A semicolon must be used between instructions on the same row + + (p3, t4, p1); (t3, p3) + + // The following arc is conditional. The generated program will + // contain an "if(i >= 1)" instruction before attempting to fire t2. Thus, + // the variable i must be defined in the context of the C code associated + // with the place p2. + + (p2, t2) {i >= 1} + +} + +// The following defines a group or processes implemented as threads + + +thread t1 { + + // The following defines the Petri net representation of the process + + places: p1 p2 p3 + transitions: t1 t2 t3 t4 + + // The following describes the arcs connecting places and transitions + + (p1, t1) + (p1, t2, p3) + (p3, t3, p2); (p2, t4, p1); + +} + + +// The Petri net associated with a supervisor is generated automatically. +// However, the user has the option to specify additional components to be +// included in the Petri net of the supervisor. The following block defines +// such a component. + +supervisor sc { + places: p1 p2 + transitions: t1 + + (p1, t1, p2) +} + + +// The following synchronizes the transition t1 of process p1 with the +// transition t3 of the process t1. + +sync p1.t1 t1.t3 + +// Constraints can be described by means of inequalities + +2*p1.q.t2 - t1.p3 <= 1 // firing vector element: process.q.transition + // marking vector element: process.place + +t1.v.t1 <= t1.v.t2 // Parikh vector element: process.v.transition + + +// The following describes the initial number of processes in each group. +// It also describes the stage in which each process should be started. + +initialize: p1(p1:1, p2:2) +initialize: t1(p2:1) sc(p1:5) + +// The group p1 will have three processes: one starting in p1 and two starting +// in p2. The group t1 will have only one process and that process will start +// in p2. Now, sc is not a process group but a supervisor component. The +// initialization of sc requests that the Petri net of sc will have an initial +// marking with 5 tokens in p1. + +// By default, a group of processes is initialized with zero processes. + +// Transitions that should be live can be specified as follows. +// NOTE: Avoid this instruction when possible, since the synthesis of a +// deadlock prevention policy is computationally intensive and can take much +// time. + +live: t1.t2 // the supervisor should ensure that the transition t2 of the + // process group t1 is live. + + +// The following blocks are OPTIONAL. + +// A segment of code can be associated with each place. The following +// instruction defines the code of the place p3 of the process p1. + +p1.p3 { + i = i + 1; + j = 10*i; +} + +// If several transitions could be fired from a place (that is, their +// conditions, if any, are satisfied and the supervisor could fire any of them) +// the next transition will be selected randomly. However, if the programmer +// defines a "select function" and assigns it to the place, the fired +// transition will be determined by the select function. Thus, conditions +// labeling a transition are implemented only if no select function is defined. +// The following line requests that p1_select() be called in order to +// determine the transition that should be fired from the place p1 of the +// process p1. Note the requirements on the select function below. + +p1.p1.select { p1_select(___TR); /* ___TR: defined in context of call */ } + +// Requirements on the select function: +// - It must return the number of transitions written to ___TR. +// - The select function should write to ___TR[0], ___TR[1], ... +// the ___TRData element of the selected transitions, in the order +// of preference. See the definition of the p1_select function in this file. +// - The parameters of the function may be arbitrary. +// - The code generator will write: +// ___i = [select function call] +// where [select function call] stands for whatever is written between +// braces in the select command. For instance, the select command above +// is implemented as +// ___i = p1_select(___TR); /* ___TR: defined in context of call */ + + +// Any instructions that a process should execute when it is started +// can be specified by means of a main block + +p1.main { + i = 0; + j = 1; +} + +// Header files and other definitions that should appear in the source file of +// a process can be specified by means of an include block + +p1.include { + #include"string.h" + #define MAX 10 + + int i, j; + + struct myarray { int i; float k; }; + + static struct myarray array[MAX]; + + static int p1_select(struct ___trans* ___TR) { + // Selects the transitions 0 and 1 and gives precedence to transition 1. + ___TR[0] = ___TRData[1]; ___TR[1] = ___TRData[0]; + return 2; // returns the number of entries written to ___TR + } +} + +// Instructions on how to build the executable file associated with a process +// can be specified in a build block. Note that the software will replace $$$ +// with the name of the file defining the process (without extension). + +p1.build { gcc -g -o $$$.exe $$$.c } + +// Copies of a process group can be specified as follows + +p1c = p1 // p1c is another process group + +// Note that p1 has been defined with the keyword 'process'. Thus, p1c will +// also be of the type 'process'. If the copy should have a different type, +// the desired type should be stated before the assignment. + +thread p1c2 = p1 + +// On the line above, p1c2 is defined as a copy of p1 of the type 'thread'. + +// Instructions that the supervisor should execute when it is started +// can be specified by means of a main block + +main { + fprintf(stdout, "The supervisor is starting ..."); +} + +// An include block can also be defined for the supervisor + +include { + #define MAX_INP 3 + #include"ctype.h" +} + + +// The build block of the supervisor can be used to specify additional +// command line parameters that should be used when building the program + +build { -I. } Deleted: present_version/doc/input2.sp =================================================================== --- present_version/doc/input2.sp 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/doc/input2.sp 2012-08-15 23:47:15 UTC (rev 265) @@ -1,343 +0,0 @@ -// THIS DOCUMENT DESCRIBES THE *OLD* VERSION OF THE SPECIFICATION LANGUAGE. -// SEE format2.hl FOR A DESCRIPTION OF THE CURRENT SPECIFICATION LANGUAGE. - -// FOR REFERENCE ONLY. ON ONE HAND, NOT ALL FEATURES HAVE BEEN IMPLEMENTED -// IN THE TRANSLATOR. ON THE OTHER HAND, SOME IMPLEMENTED FEATURES ARE NOT -// DESCRIBED HERE. THIS FILE MAY NOT DESCRIBE THE ENTIRE SYNTAX. SEE THE -// EXAMPLES FOR INFORMATION ON THE SYNTAX. - -// Version 2.1.1 - 04/21/2011 -// The keyword "init" was added for initialization code. -// Version 2.1 - 05/19/2009 -// Compared to version 2, the following keywords were added: -// "nondeterministic", "select", "uncontrollable", and "unobservable". -// The low level (PN level) specification language is illustrated on a -// specification of independent reader and writer processes with shared memory. -// The high level language has not been developed yet. - -// The concurrent programming tool operates as follows. -// -// Given a specification file (say input.sp), the tool generates -// - input.c containing the code of the supervisor; -// - input.mak a makefile; -// - additional c files, one for each process defined below. -// -// After the application is built, the user can start it by -// running the supervisor program (say input.exe). The supervisor program -// will start all other processes and ensure that they operate -// correctly. Terminating the supervisor program will also -// terminate children processes. - - -// The specification file consists of three parts containing -// - process-type declarations -// - definitions -// - process declarations and dependencies -// - instructions on supervisor design - -// 1. PROCESS-TYPE DECLARATIONS - -// Format: -// -// process type // Write here the name of the process type. - // Note that all processes of the same type have the same - // executable file. -// build command: // Write here the line(s) used to build the executable. - // For instance: 'make -f process_name.mak' or - // 'gcc -o process_name process_name.sp.c functions.c ...' - // Note that process_name.sp.c is the c file generated - // by the concurrent programing tool for the process_name - // type. -// include: // Write here what should be included at the beginning of - // process_name.sp.c, such as #include directives. -// extern process type // Declares a process type for which the tool should - // not generate code. Such a process type may describe - // hardware or software functions already implemented. - // If such external processes impose relevant - // constraints, the specification should - // describe them. This may help: - // - simplify some supervisory control methods - // - reveal potential deadlock situations - // A process may not be external unless all transitions - // unique to the process are uncontrollable and - // unobservable. - -process type READER - -build command: make -f reader.mak - -include: { - #include<stdio.h> - #include<string.h> - - int state = 0; /* variables can be declared here as well */ -} - - -init: { - // include here declarations and initialization code -} - -process type WRITER - -build command: make -f writer.mak - -include: #include "writer.h" - - -extern process type ARBITER // Note that no build or include commands follow - // the declaration of an external process type. - - -// 2. DEFINITIONS - -// This version of the specification format describes only a low level PN -// definition of the processes. - -// Format: - -// process_name.PN: -// places: list of place names -// transitions: list of transition names -// place.code: gives the C code associated with a place. The C code -// is not parsed here! Rather the "text" structure associated -// to the PN place is initialized with the position of the C code. -// *place: list of input transitions -// place*: list of the output transition of place -// ([place], transition, [place, ...])[.{c code}] where items between -// square brackets are optional. -// Note that the c code is not parsed but its position is copied to a "text" -// structure associated with the arc. - - - -ARBITER.PN: - -places: p1 p2 // place names do not have to start with a 'p' - -transitions: t1 t2 // transition names do not have to start with a 't' - -// Note the absence of place.code lines for an external process. - -*p1: t1 -p1*: t2 -*p2: t2 -p2*: t1 - - -// The format *place: input transition(s), place*: output transition(s) -// is ideal for representing a PN structure and this is what we need for an -// external process. However, the format it is ambiguous for the processes for -// which code should be generated. For instance, assume a transition t such -// that *t: p1 p2 and t*: p3 p4. Recall that each process of type X is a -// token in the underlying PN. Thus, assuming two processes, one in the stage -// p1 and one in the stage p2, it is not clear what action should be taken -// when t is fired. The following format will be used to describe the outcome -// of firing t. -// 1. The process in p1 goes to p3 and the one in p2 to p4 -// (p1, t, p3) (p2, t, p4) -// 2. The process in p1 goes to p3 and forks one child process in p4. The -// process in p2 terminates. -// (p1, t, p3, p4) (p2, t) -// 3. Both processes in p1 and p2 terminate and two new processes are created -// in p3 and p4. -// (p1, t) (p2, t) (t, p3) (t, p4) -// 4. ... -// ... - -READER.PN: - -places: p1 p1b p2 p3 - -transitions: t1 t2 t3 t4 ti t_end - -p1.code: initialize_r(); - -p1b.code: initialize_r_b(); - -p2.code: { - str = read_data(); -} - -p3.code: process_data(str); - -// The following lines describe the structure of the PN - -(p1b, ti, p1) -(p1, t1, p2).{i != 0} // the transition will be taken only if the condition - // between braces is TRUE. -// The expression between braces should only be copied; it does not have to -// be parsed. - -(p2, t2, p3) -(p3, t3, p1) -(p1, t_end).{exit_v == TRUE} -(p1, t4, p3) - -// Note that a process in p1 has three choices. -// if(i != 0) then fire t1 -// else if(exit_v == TRUE) then fire t_end -// else fire t4 - -// Instead of using the conditions above to determine which transitions to -// fire, a function to select them could be specified. - -select function p1.{select_t} // select_t is the name of the function - -// Thus, when there is a token in p1, the function select_f is invoked to -// to determine which transition should be fired. - -nondeterministic places: p1 - -// By default a place p is deterministic. For a deterministic place, one of the -// enabled output transition is selected and then the process waits until the -// supervisor permits its firing. However, if the place p is nondeterministic, -// a protocol such as the one below is used. -// -// 1. The select function is invoked to produce the list of enabled transitions -// in the order of firing preference (first in list is the transition the -// process is most interested to fire). -// 1.b. Optionally, the supervisor is inquired about the transitions it -// enables. However, note that the set of transitions enabled by the -// supervisor can change before the process asks the supervisor for -// permission to fire. -// 2. The list of transitions is sent to the supervisor. Then, the process -// sleeps until the supervisor replies. -// 4. The supervisor gives permission to fire one of the transitions on the -// list. -// -// The main difference between a deterministic and a nondetermistic place is -// as follows. For a deterministic place a transition is selected and then the -// process sleeps until it can continue by firing that transition. For a -// nondeterministic place the choice of the next transition depends on the -// transitions enabled by the supervisor. - - - -WRITER.PN: - -places: p pwr_1 pwr2 - -transitions: t1 t2 t3 t4 - -p.code: process_wrdata(); - -pwr_1.code: write_dest1(); - -pwr_2.code: write_dest2(); - -(p, t1, pwr_1).{dest == 1} -(p, t2, pwr_2) -(pwr_1, t3, p) -(pwr_2, t4, p) - - - -// 3. PROCESS DECLARATIONS - -READER r_group(p1:2, p3:1) // This declares a group of 2+1= 3 READER - // processes. Two processes begin in the state - // p1 and one in the state p3. - // The name of this group of processes is 'r_group'. - // They will be implemented by the READER.PN with - // initial marking m(p1) = 2 and m(p3) = 1. - -READER reader1(p1b) // This declares a single READER process that begins in - // the state p1b. The name of the process is reader1. - -WRITER writer1(p) - -WRITER w_group(p:2) - -ARBITER arbiter(p1) - - -// DEPENDENCIES (transitions that processes synchronize on their own) - -sync reader1.t1 arbiter.t1 - // mentions that the two transitions are synchronized - // (they take place simultaneously). - -sync writer1.t2 arbiter.t2 - -// Remark: all transitions of the external processes are considered to be -// uncontrollable and unobservable, excepting the transitions synchronized -// with transitions of internal processes. Such transitions have the type -// specified by the internal process. - - -// 4. INSTRUCTIONS ON THE DESIGN OF THE SUPERVISOR - -// These describe what the objectives of the supervisor. -// - 'start' commands describe what processes the supervisor should start -// - 'constraints' commands describe what constraints should be enforced -// Constraints have the form -// weighted sum <= free term -// Since we deal with integers, <, >, and >= are all equivalent to this -// form. For instance, a < b is the same as a <= b - 1. -// Disjunctive constraints are also allowed -// (weighted sum <= free term) || (weighted sum 2 <= free term 2) -// The keyword 'live' is used to introduce a list of transitions that -// should always be eventually firable. -// Similarly, the keywords "uncontrollable" and "unobservable" introduce -// lists of transitions that the supervisor should not attempt to control -// and observe, respectively. - -start r_group w_group reader1 writer1 // Unimplemented as of May 2011. - - -// CONSTRAINTS - -r_group.constraints: // these are constraints on the PN of r_group - -live: t2 t4 // requests that the transitions t2 and t4 of r_group be live - // (i.e. they never deadlock). - -uncontrollable: t1 t_end t4 - -unobservable: t1 t_end t4 - - -w_group.constraints: // these are constraints on the PN of w_group - -// Here are some constraints that two writers may not be at the same time -// in the same critical section. - -pwr_1 <= 1 // requests that the marking of pwr_1 does not exceed 1 -pwr_2 <= 1 // requests that the marking of pwr_2 does not exceed 1 - -live: all // requests all transitions of w_group to be live. - - -// NOTE: Some constraint features are not implemented as of May 2011. - -global.constraints: // these are constraints on all PNs - -(r_group.p2 <= 0) || (w_group.pwr_1 <= 0) - -// The line above requests that at all times either the place p2 of r_group -// has no tokens or the place pwr_1 of w_group has no tokens. That is, any -// number of readers may be at the same time in the critical section, but -// a reader and a writer may not be there at the same time. - -q.reader1.t1 - writer1.p <= 0 //'q.' denotes the firing vector. The constraint - // requires that t1 of reader1 may be fired only - // if there is one token in the place p of - // writer1. - -2*reader1.t1 - 2*reader1.t2 + w_group.pwr_2 <= 2 -// reader1.t1 denotes the number of firings of t1. This constraint is -// another way of requesting 2*reader1.p2 + w_group.pwr_2 <= 2 - - - -// More general constraints, such as requiring a certain language to be -// generated, will be implemented when the need will arise. - - - -// 5. OTHER COMMANDS - -print supervisor to debug.log // 'print supervisor to file_name' requests the - // PN produced by the supervisory control - // algorithms to be written to file_name. Modified: present_version/examples/README =================================================================== --- present_version/examples/README 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/examples/README 2012-08-15 23:47:15 UTC (rev 265) @@ -3,16 +3,19 @@ inteq.sp: a simple example illustrating how to write concurrent program specifications. It specifies a concurrent program for finding integer solutions to the equation w^2 = x^2 + y^2 + z^2. -The following files were converted to the present specification format by Micah Martin and Basil Hall. +test2.sp: This is a test file intended to check the code generation module. It generates a process that creates periodically a thread until it terminates. There are synchronizations between the process and the threads it generates. -test2.sp: This is a test file intended to check the code generation module. It generates a process that can creates periodically a thread until it terminates. There are synchronizations between the process and the threads it generates. +The test3 files below consider the dining philosopher problem. - -test3: A dining philosopher example. - test3a.sp: Tests that the deadlock prevention function works fine when no deadlock is possible. Only one philosopher with two resources. test3c.sp: A test involving 5 philosophers. test3d.sp: A test involving 5 philosophers. Here, the resources (chopsticks) are defined as supervisor components, not as threads. + + +reader.sp: this is a reader/deleter/inserter example. It illustrates more complex marking and firing vector constraints. + + +The examples test2.sp, test3a, test3c, and test3d were converted to the current specification format by Micah Martin and Basil Hall. Modified: present_version/examples/inteq.sp =================================================================== --- present_version/examples/inteq.sp 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/examples/inteq.sp 2012-08-15 23:47:15 UTC (rev 265) @@ -1,4 +1,4 @@ -// inteq.hl -- a concurrent program for finding integer solutions to the +// inteq.sp -- a concurrent program for finding integer solutions to the // equation w^2 = x^2 + y^2 + z^2 // Fastest if built with the option -s2 @@ -116,4 +116,6 @@ fprintf(stdout, "%d^2 = %d^2 + %d^2 + %d^2\n", w, x, y, z);fflush(0); } } -} \ No newline at end of file +} + +build { -lm } // so that math library is included by gcc; needed for sqrt Added: present_version/examples/reader.sp =================================================================== --- present_version/examples/reader.sp (rev 0) +++ present_version/examples/reader.sp 2012-08-15 23:47:15 UTC (rev 265) @@ -0,0 +1,56 @@ +// This implements the reader/deleter/inserter example + +thread READER { + places: pv pc pd; + transitions: tv tc td; + + (pv, tv, pc); (pc, tc, pd); (pd, td, pv); +} + + +READER.include { +#include<pthread.h> +} + + +READER.pv { + fprintf(stderr, "\n%s %x entering the pv block", ___INSTANCE, (int)pthread_self()); + sleep(1); +} + + +READER.pc { + fprintf(stderr, "\n%s %x entering the critical section", ___INSTANCE, (int)pthread_self()); + sleep(1); +} + + +READER.pd { + fprintf(stderr, "\n%s %x entering the pd block", ___INSTANCE, (int)pthread_self()); + sleep(1); +} + + +DELETER = READER // create a deleter thread group of identical structure +INSERTER = READER // create an inserter thread group of identical structure + +supervisor sc { + places: pa; + transitions: t0 t1 t2; + + (t1, pa); (pa, t0); +} + +initialize: READER(pv:5); +initialize: INSERTER(pv:3); +initialize: DELETER(pv:3); +// No initialize command needed for sc since its initial marking is zero. + +sync sc.t1 sc.t2 READER.tv + +sc.q.t1 <= DELETER.pv +3*sc.q.t2 + 3*sc.q.t0 <= 3 - DELETER.pv + 3*DELETER.pc +sc.pa <= 5 +6*DELETER.pc + READER.pc + INSERTER.pc <= 6 +INSERTER.pc <= 1 + Added: present_version/newcodegen/Makefile =================================================================== --- present_version/newcodegen/Makefile (rev 0) +++ present_version/newcodegen/Makefile 2012-08-15 23:47:15 UTC (rev 265) @@ -0,0 +1,28 @@ +COMPILER=gcc -g +PNDIR=../pnheaders/ + +static: plantCompiler.o filltmpl.fl.o supervisorCompiler.o templates.o + +compexample.o: compexample.c *.h $(PNDIR)*.h + $(COMPILER) -c -I$(PNDIR) compexample.c + +plantCompiler.o: plantCompiler.c *.h $(PNDIR)*.h + $(COMPILER) -c -I$(PNDIR) plantCompiler.c + +supervisorCompiler.o: supervisorCompiler.c *.h $(PNDIR)*.h + $(COMPILER) -c -D ___USE_PTHREAD_LIB -I$(PNDIR) supervisorCompiler.c + +filltmpl.fl.o: filltmpl.lex + flex -Pfl -ofilltmpl.fl.c filltmpl.lex + $(COMPILER) -c filltmpl.fl.c -I$(PNDIR) + +templates.o: fl2str SupervisorTemplate.c ProcessTemplate.c spcommon.h + ./fl2str templates.c SupervisorTemplate.c ProcessTemplate.c spcommon.h + $(COMPILER) -c templates.c + +fl2str: fl2str.lex + flex -ofl2str.yy.c fl2str.lex + $(COMPILER) -o fl2str fl2str.yy.c + +clean: + rm *.o obj/*.o || true \ No newline at end of file Modified: present_version/newcodegen/Makefile-cygwin.mak =================================================================== --- present_version/newcodegen/Makefile-cygwin.mak 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/newcodegen/Makefile-cygwin.mak 2012-08-15 23:47:15 UTC (rev 265) @@ -1,12 +1,8 @@ COMPILER=gcc -g PNDIR=../pnheaders/ -comp: plantCompiler.o compexample.o filltmpl.fl.o supervisorCompiler.o - make -f pnexample.mak -C$(PNDIR) - $(COMPILER) -o compexample plantCompiler.o compexample.o filltmpl.fl.o $(PNDIR)matrix.o $(PNDIR)general.o $(PNDIR)pns.o $(PNDIR)insert.o supervisorCompiler.o +static: plantCompiler.o filltmpl.fl.o supervisorCompiler.o templates.o -static: plantCompiler.o filltmpl.fl.o supervisorCompiler.o - compexample.o: compexample.c *.h $(PNDIR)*.h $(COMPILER) -c -I$(PNDIR) compexample.c @@ -18,7 +14,15 @@ filltmpl.fl.o: filltmpl.lex flex -Pfl -ofilltmpl.fl.c filltmpl.lex - $(COMPILER) -c filltmpl.fl.c + $(COMPILER) -c filltmpl.fl.c -I$(PNDIR) +templates.o: fl2str SupervisorTemplate.c ProcessTemplate.c spcommon.h + ./fl2str templates.c SupervisorTemplate.c ProcessTemplate.c spcommon.h + $(COMPILER) -c templates.c + +fl2str: fl2str.lex + flex -ofl2str.yy.c fl2str.lex + $(COMPILER) -o fl2str fl2str.yy.c + clean: - rm *.o || true + rm *.o obj/*.o || true \ No newline at end of file Modified: present_version/newcodegen/Makefile-linux.mak =================================================================== --- present_version/newcodegen/Makefile-linux.mak 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/newcodegen/Makefile-linux.mak 2012-08-15 23:47:15 UTC (rev 265) @@ -1,12 +1,8 @@ COMPILER=gcc -g PNDIR=../pnheaders/ -comp: plantCompiler.o compexample.o filltmpl.fl.o supervisorCompiler.o - make -f pnexample.mak -C$(PNDIR) - $(COMPILER) -o compexample plantCompiler.o compexample.o filltmpl.fl.o $(PNDIR)matrix.o $(PNDIR)general.o $(PNDIR)pns.o $(PNDIR)insert.o supervisorCompiler.o +static: plantCompiler.o filltmpl.fl.o supervisorCompiler.o templates.o -static: plantCompiler.o filltmpl.fl.o supervisorCompiler.o - compexample.o: compexample.c *.h $(PNDIR)*.h $(COMPILER) -c -I$(PNDIR) compexample.c @@ -18,7 +14,15 @@ filltmpl.fl.o: filltmpl.lex flex -Pfl -ofilltmpl.fl.c filltmpl.lex - $(COMPILER) -c filltmpl.fl.c + $(COMPILER) -c filltmpl.fl.c -I$(PNDIR) +templates.o: fl2str SupervisorTemplate.c ProcessTemplate.c spcommon.h + ./fl2str templates.c SupervisorTemplate.c ProcessTemplate.c spcommon.h + $(COMPILER) -c templates.c + +fl2str: fl2str.lex + flex -ofl2str.yy.c fl2str.lex + $(COMPILER) -o fl2str fl2str.yy.c + clean: - rm *.o || true + rm *.o obj/*.o || true \ No newline at end of file Modified: present_version/newcodegen/ProcessTemplate.c =================================================================== --- present_version/newcodegen/ProcessTemplate.c 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/newcodegen/ProcessTemplate.c 2012-08-15 23:47:15 UTC (rev 265) @@ -15,7 +15,7 @@ extern int ___debug; // corresponds to variable of supervisor #endif -#include"spcommon.h" +#include"spcommon.h"//--- ANY change on this line MUST be reflected in BOTH SupervisorTemplate.c and filltmpl.lex, in order that filltmpl.lex may be able to replace this line with the adequate include directive static void* ___main_function(void* ___v); @@ -76,7 +76,7 @@ #ifndef ___THREAD ___ctime += (int) getpid(); #else - ___ctime += (int) getpid() + (int)___pthr->id; + ___ctime += (int) getpid() + (int)(long)___pthr->id; // (long) avoids warning #ifndef SINGLE_READ_CHANNEL // block SIGUSR1 which may be used to notify main program of new messages sigemptyset(&___set); @@ -147,7 +147,7 @@ if(___pthr || ___pc) { asprintf(&___s2, "\nThe following parameters were received:\n"); if(___pthr) - asprintf(&___s3, "id = %d debug = %d initial state = %d", (int)___pthr->id, (int)___pthr->debug, (int)___pthr->state); + asprintf(&___s3, "id = %d debug = %d initial state = %d", (int)(long)___pthr->id, (int)___pthr->debug, (int)___pthr->state); if(___pc) asprintf(&___s4, " write end = %d", (int)___pc->pwrite); } Modified: present_version/newcodegen/SupervisorTemplate.c =================================================================== --- present_version/newcodegen/SupervisorTemplate.c 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/newcodegen/SupervisorTemplate.c 2012-08-15 23:47:15 UTC (rev 265) @@ -40,7 +40,7 @@ char* ___name; -#include"spcommon.h" +#include"spcommon.h"//--- ANY change on this line MUST be reflected in BOTH ProcessTemplate.c and filltmpl.lex, in order that filltmpl.lex may be able to replace this line with the adequate include directive // The following is used for unnamed pipe communication between plant // and supervisor. @@ -228,6 +228,8 @@ #ifdef ZERO_LABEL_TRANS + int ___i, ___flag, ___tr; + for(___flag = 1; ___flag; ) { ___flag = 0; for(___i = 0; ___i < ZERO_LABEL_TRANS; ___i++) { @@ -1238,19 +1240,19 @@ int main(int argc, char* argv[]) { int ___i, ___j; - char *___str, ___help_msg[] = "\nOptions: \n\ - -e: suppress error and status messages\n\ - -s: start the program right away without displaying introductory message\n\n\ + char *___str, ___help_msg[] = "\nCommand line options: \n\ + -d: display error and status messages\n\ + -s: start the program right away without displaying this introductory message\n\n\ Ctrl-C (SIGINT) can be used to stop the program. This will terminate all\n\ its processes.\n"; - ___debug = 1; + ___debug = 0; ___start_flag = (argc <= 1); for(___i = 1; ___i < argc; ___i++) { - if(!strcmp(argv[___i], "-e")) - ___debug = 0; + if(!strcmp(argv[___i], "-d")) + ___debug = 1; else if(!strcmp(argv[___i], "-h") || !strcmp(argv[___i], "--help")) { - fprintf(stdout, ___help_msg); + fputs(___help_msg, stdout); return 0; } else if(!strcmp(argv[___i], "-s")) { Modified: present_version/newcodegen/codegen.h =================================================================== --- present_version/newcodegen/codegen.h 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/newcodegen/codegen.h 2012-08-15 23:47:15 UTC (rev 265) @@ -1,6 +1,6 @@ /* codegen.h - This header file was created for the 2010 version of the code generation tools. + This header file was created for the 2010 version of the code generation tools. Updated in 2012. */ /* The code generation module expects processes satisfying the following @@ -11,9 +11,12 @@ from the supervisor. (NOT YET IMPLEMENTED.) - The supervisor format: It is assumed that each transition has a - unique label. Process transitions that are synchronized are assumed to - have the same label. The supervisor is connected to the plant using the - conventional parallel composition of PNs. + one label. (That is, though multiple transitions may share a common + label, the expectation is that exactly one label (no more, no less) + is assigned to each transition.) Process transitions that are + synchronized are assumed to have the same label. The supervisor is + connected to the plant using the conventional parallel composition of + PNs. - The select function: If defined, it should return the number of transitions selected. Let n be that number. The select function writes the @@ -35,9 +38,33 @@ #define DBG3 is_verbose()>=3 +#define LINEDIR "/*___LINEDIR*/" // Read lines below before changing! +// The string of LINEDIR is not completely arbitrary: FillTemplate assumes +// that the first character is not repeated, excepting the last character. +// LINEDIR is inserted within the text sent to FillTemplate in order to mark +// points at which #line directives should be inserted redirecting +// error messages from the compiler to the actual file that is compiled. -int FillTemplate(FILE* template, FILE* outp, ...); // in filltmpl.lex +struct input { // the nonzero field among 'buf' and 'file' is to be used + FILE *file; + char *buf; +}; + + +int FillTemplate(struct input template, FILE* outp, char* outpname, \ + char* inclname, char* preamble, ...); // in filltmpl.lex +// This function uses 'template' in order to generate a customized output file. +// 'outpname' denotes the name of the outp file. +// 'outp' is the file that FillTemplate writes. +// 'preamble', if nonzero, is written at the beginning of this file. +// If 'inclname' is nonzero, it is used to replace spcommon.h in +// #include"spcommon.h" with 'inclname'. +// This function expects cblock objects for the optional arguments. +// If no 'line' directives should be written, the 'file' field of +// the cblock object should be zero. + + FILE* searchTemplate(char* s); // in plantCompiler.c char* GetFileName(const char* s, const char *ext); Modified: present_version/newcodegen/filltmpl.lex =================================================================== --- present_version/newcodegen/filltmpl.lex 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/newcodegen/filltmpl.lex 2012-08-15 23:47:15 UTC (rev 265) @@ -5,33 +5,85 @@ %{ #include<stdio.h> #include<stdarg.h> + #include"pns.h" + #include"codegen.h" - int flag, skip, i, j; - va_list param; - FILE *out; - char *stmp, cc; + static const char lntxt[] = LINEDIR; + static int flag, skip, i, j, k, line, lntxtlen; + static va_list param; + static FILE *out; + static char *stmp, cc, *fileName; + static cblock bl; + static char *inclname; + void mfprint(char *str, ...) { // updates line based on the format string + int ii; + va_list par; + + for(ii = 0; str[ii]; ii++) + line += (str[ii] == '\n'); + + va_start(par, str); + vfprintf(out, str, par); + va_end(par); + } + %} %% +\#include\"spcommon\.h\"\/\/\-\-\-[^\n]* { + if(inclname) + fprintf(out, "#include\"%s\"", inclname); + else + fputs("#include\"spcommon.h\"", out); + } + + {LABEL}/{IDENTIFIER} { flag = 0; skip = 1; - fprintf(out, "%s (BEGINNING OF CODE)\n", yytext); + // mfprint used in order to update 'line' automatically + mfprint("%s (BEGINNING OF CODE)\n", yytext); for(i = 0; yytext[i] == ' ' || yytext[i] == '\t'; i++); cc = yytext[i]; - yytext[i] = 0; // get indentation string - stmp = va_arg(param, char*); // get string to insert + yytext[i] = 0; // get indentation string in yytext + bl = va_arg(param, cblock); // get string to insert + stmp = bl.text; if(stmp) { - for(j = 0; stmp[j]; j++) { - fwrite(stmp+j, sizeof(stmp[j]), 1, out); - if(stmp[j] == '\r' || stmp[j] == '\n') - fprintf(out, "%s", yytext); + if(bl.file) { + mfprint("#line %d \"%s\"\n", bl.line, bl.file); + for(j = 0; stmp[j]; j++) { + fwrite(stmp+j, sizeof(stmp[j]), 1, out); + if(stmp[j] == '\r' || stmp[j] == '\n') { + fprintf(out, "%s", yytext); // print indentation + line += (stmp[j] == '\n'); + } + } + mfprint("\n#line %d \"%s\"\n", line+2, fileName); } + else { // look for LINEDIR requests + for(j = 0, k = 0; stmp[j]; j++, k++) { + if(stmp[j] == lntxt[k]) + continue; + if(!lntxt[k]) { // a LINEDIR request was found + mfprint("\n#line %d \"%s\"\n",line+2, fileName); + k = -1; + continue; + } + for(j = j - k; k >= 0; k--, j++) + fwrite(stmp+j, sizeof(*stmp), 1, out); + j--; + if(stmp[j] == '\r' || stmp[j] == '\n') { + fprintf(out, "%s", yytext); // print indentation + line += (stmp[j] == '\n'); + } + } + } } yytext[i] = cc; // restore yytext - fprintf(out, "\n%s (END OF CODE)\n", yytext); + // mfprint used in order to update 'line' automatically + mfprint("\n%s (END OF CODE)\n", yytext); } {IDENTIFIER} { @@ -48,6 +100,7 @@ \n|\r { skip = 0; fprintf(out, "%s", yytext); + line += (yytext[0] == '\n'); } %% @@ -57,19 +110,38 @@ return 1; } -int FillTemplate(FILE* template, FILE* outp, ...) { +int FillTemplate(struct input template, FILE* outp, char* outpname, \ + char* incname, char* preamble, ...) { + static int fl = 0; - va_start(param, outp); + if(!template.file && !template.buf) + merror(0, "CODE GENERATION: Invalid template input"); + line = 1; + inclname = incname; + + va_start(param, preamble); + flag = 0; skip = 0; + fileName = outpname; - yyin = template; + lntxtlen = strlen(LINEDIR); + out = outp; - if(fl) - yyrestart(template); + if(template.file) { + yyin = template.file; + if(fl) + yyrestart(template.file); + } + else + yy_scan_string(template.buf); + + if(preamble) + mfprint(preamble); // this will also update 'line' + yylex(); va_end(param); Added: present_version/newcodegen/fl2str.lex =================================================================== --- present_version/newcodegen/fl2str.lex (rev 0) +++ present_version/newcodegen/fl2str.lex 2012-08-15 23:47:15 UTC (rev 265) @@ -0,0 +1,90 @@ + +%{ + +#include<stdio.h> + + static FILE *f; + +%} + +%% + +\\ fputs("\\\\", f); +\" fputs("\\\"", f); + +\r fputs("\\r", f); +\n fputs("\\n", f); +\t fputs("\\t", f); + +. fputc(yytext[0], f); + +%% + +int yywrap(void) { + return 1; + } + +int main(int na, char* argv[]) { + int i, j; + char flag, c; + + if(na <= 2) { + printf("\nThis program converts text files to strings that can be used within C programs"); + printf("\n\nUsage: %s output_file input_file [input_files]\n", argv[0]); + return 0; + } + + f = fopen(argv[1], "w"); + if(!f) { + printf("\nThe file %s cannot be written\n", argv[1]); + return 1; + } + + for(i = 2, flag = 0; i < na; i++) { + yyin = fopen(argv [i], "r"); + if(!yyin) { + flag = 1; + printf("\nThe file %s could not be opened\n", argv[i]); + } + else + fclose(yyin); + } + + if(flag) + return 1; + + // fprintf(f, "/* This is %s generated with the command line:\n %s %s", argv[1], argv[0], argv[1]); + //for(i = 2; i < na; i++) + // fprintf(f, " %s", argv[i]); + // fputs("\n*/\n\n", f); + + for(i = 2; i < na; i++) { + yyin = fopen(argv[i], "r"); + if(!yyin) { + printf("\nCould not reopen the file %s\n", argv[i]); + fclose(f); + return 1; + } + + fputs("\nchar ", f); + for(j = 0; argv[i][j]; j++) { + c = argv[i][j]; + if(c == '.') + fputc('_', f); + else + fputc(c, f); + } + fputs("[] = \"", f); + + if(i >= 3) + yyrestart(yyin); + yylex(); + fclose(yyin); + + fputs("\";\n", f); + } + + fclose(f); + return 0; +} + Modified: present_version/newcodegen/plantCompiler.c =================================================================== --- present_version/newcodegen/plantCompiler.c 2012-08-15 20:59:28 UTC (rev 264) +++ present_version/newcodegen/plantCompiler.c 2012-08-15 23:47:15 UTC (rev 265) @@ -2,9 +2,12 @@ plantCompiler.c -- Generates the c code for the plant PNs This is the 2010 version. The 2010 version was written by M. V. Iordache. Created: May 2010. -Last updated: June 2010. +Last updated: Nov 2011. ****************************************************************************/ +// TO DO: +// For each transition ti create "#define ti___data(x) {(x).t = ...;(x).l = ...; ...}" allowing to initialize ___TR[j] to the data of ti. This is for the select function + #include<stdio.h> #include<stdarg.h> #include<time.h> @@ -14,6 +17,8 @@ #define TEMPL "ProcessTemplate.c" +extern char ProcessTemplate_c[]; +extern char *inc_name; FILE* searchTemplate(char* s) { // In future versions this should do a search in some default paths. @@ -30,9 +35,9 @@ } -struct myinsert genDefineBlock(specs *sp, process* pr, TrData* TrInfo) { +struct myinsert genDefineBlock(specs *sp, process* pr, TrData* TrInfo, int* actlabels) { struct myinsert ins; - int i, j, k, ntr; + int i, j, k, ntr, t, no_place, out_place, label; pns *pn; ins = InitInsert(512); @@ -63,6 +68,9 @@ } ins = SInsert("};", ins); + if(pr->dfns) + ins = FSInsert(ins, "\n\n%s", pr->dfns); + if(pr->thread) { ins = FSInsert(ins, "\n\n\ void* ___start_%s(void* ___v) {\n\ @@ -81,6 +89,39 @@ //if(DBG3) // if yes, then generated executables should also be in debug mode // incl = SInsert("\n#define ___DEBUG\n", incl); + + // Determine whether it is useful to generate the TRdata array + // (This unlikely to be necessary apart from select functions.) + + i = pn->pnum; + if(pn) + if(pn->select) + for(i = 0; i < pn->pnum; i++) + if(pn->select[i].text != 0) + break; + // Select functions have been defined if i != pn->pnum + // Then write the TRdata array + if(i != pn->pnum) { + ins = SInsert("\nstatic const struct ___trans ___TRData[] = {", ins); + for(t = 0; t < pn->tnum; t++) { + out_place = -1; + no_place = 1; + for(j = 0; j < pn->pnum; j++) + if(GetMatrixEl(&(pn->in), j, t)) { // if arc from t to j + out_place = j; + no_place = 0; + break; + } + label = 0; + if(pn->t) + label = pn->t[t].l; + if(t) + ins = SInsert(", ", ins); + ins = FSInsert(ins,"{%d, %d, %d, %d, %d}", no_place, out_place, label, actlabels[t], t); + } + ins = SInsert("};\n", ins); + } + return ins; } @@ -100,7 +141,13 @@ for(i = 0; i < pn->pnum; i++) { ins = FSInsert(ins, "\ncase %d:\n", i); if(pn->segment) - ins = SInsert(pn->segment[i], ins); + if(pn->segment[i].text) { + if(pr->file) + ins = FSInsert(ins,"#line %d \"%s\"\n", pn->segment[i].line, pr->file); + ins = SInsert(pn->segment[i].text, ins); + if(pr->file) + ins = SInsert(LINEDIR, ins); + } // Inserting/creating select functions // The output of the select function is the ___TR list. @@ -113,9 +160,14 @@ // The code will not progress until a transition is enabled fl = 0; if(pn->select) - fl = (pn->select[i] != 0); - if(fl) // if select function already provided - ins = FSInsert(ins, "\n___i = %s;", pn->select[i]); + fl = (pn->select[i].text != 0); + if(fl) { // if select function already provided + if(pr->file) + ins = FSInsert(ins,"\n#line %d \"%s\"", pn->select[i].line, pr->file); + ins = FSInsert(ins, "\n___i = %s;", pn->select[i].text); + if(pr->file) + ins = SInsert(LINEDIR, ins); + } else { // write the operations involved in selecting the next transition for(t = 0; t < pn->tnum; t++) { if(GetMatrixEl(&(pn->out), i, t)) { // if there is an arc (p,t) @@ -123,7 +175,7 @@ if(pn->arc_list) { for(arcp = pn->arc_list[t]; arcp; arcp = arcp->next) if(arcp->in_place == i) { - if(arcp->condition) + if(arcp->condition.text) flag = 1; break; } @@ -140,7 +192,11 @@ if(pn->t) label = pn->t[t].l; if(flag) { // if the transition is conditionally enabled - ins = FSInsert(ins, "\nif(%s)", arcp->condition); + if(pr->file) + ins = FSInsert(ins,"\n#line %d \"%s\"", arcp->condition.line, pr->file); + ins = FSInsert(ins, "\nif(%s)", arcp->condition.text); + if(pr->file) + ins = SInsert(LINEDIR, ins); ins = FSInsert(ins, "\n___i = ___AddToTR(___TR, ___i, %d, %d, %d, %d, %d);",\ no_place, out_place, label, t, actlabels[t]); } @@ -180,11 +236,19 @@ int i, j; char *fileName, *tmp; - FILE* plantFile, *f; + FILE* plantFile; time_t currentTime; - struct myinsert incl, mblock; + struct myinsert incl, mblock, pre; + cblock bl1, bl2; + struct input in; - f = searchTemplate(TEMPL); + if(sp->templ) { + in.file = searchTemplate(TEMPL); in.buf = 0; + rewind(in.file); + } + else { + in.file = 0; in.buf = ProcessTemplate_c; + } for(i = 0; i < nbrElements; i++) { fileName = GetFileName(procArray[i]->name, "c"); @@ -196,35 +260,42 @@ // Write header of file + pre = InitInsert(128); time(¤tTime); - fprintf(plantFile,"\ + + pre = FSInsert(pre, "\ // This is %s generated from template %s.\n\ // %s\n\n", fileName, TEMPL, asctime(localtime(¤tTime))); - if(procArray[i]->thread) fprintf(plantFile,"\n#define ___THREAD\n"); - else fprintf(plantFile,"\n#define ___PROCESS\n")... [truncated message content] |
From: <mio...@us...> - 2012-08-15 20:59:35
|
Revision: 264 http://pntool.svn.sourceforge.net/pntool/?rev=264&view=rev Author: miordache Date: 2012-08-15 20:59:28 +0000 (Wed, 15 Aug 2012) Log Message: ----------- update of old_versions folder Modified Paths: -------------- present_version/README.txt Added Paths: ----------- old_versions/version_1/ old_versions/version_1/LICENSE/ old_versions/version_1/Makefile old_versions/version_1/Makefile-cygwin.mak old_versions/version_1/Makefile-linux.mak old_versions/version_1/README.txt old_versions/version_1/doc/ old_versions/version_1/examples/ old_versions/version_1/newcodegen/ old_versions/version_1/parser/ old_versions/version_1/pnheaders/ old_versions/version_1/spnbox/ Copied: old_versions/version_1/Makefile (from rev 263, present_version/Makefile) =================================================================== --- old_versions/version_1/Makefile (rev 0) +++ old_versions/version_1/Makefile 2012-08-15 20:59:28 UTC (rev 264) @@ -0,0 +1,33 @@ +# This is the make file of the entire program. + + +COMPILER=gcc -g +LDFLAGS=-lm -ldl + +PNHEADERS=pnheaders +SPNBOX=spnbox +CODEGEN=newcodegen +CODEGENOBJS = $(CODEGEN) +TRANSLATOR=parser + +ct: objectfiles main_function2.o + $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ + main_function2.o $(SPNBOX)/*.a $(TRANSLATOR)/*.o $(LDFLAGS) + +objectfiles: + cd $(PNHEADERS); make + cd $(CODEGEN); make -f Makefile-linux.mak static + cd $(SPNBOX); make + cd $(TRANSLATOR); make + +main_function2.o: $(PNHEADERS)/main_function2.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function2.c -Ispnbox -I$(CODEGEN) -I$(PNHEADERS) + +clean: + rm -f main_function2.o + rm -f ct + cd $(PNHEADERS); make clean + cd $(CODEGEN); make -f Makefile-linux.mak clean + cd $(TRANSLATOR); make clean + cd $(SPNBOX); make clean + Copied: old_versions/version_1/Makefile-cygwin.mak (from rev 263, present_version/Makefile-cygwin.mak) =================================================================== --- old_versions/version_1/Makefile-cygwin.mak (rev 0) +++ old_versions/version_1/Makefile-cygwin.mak 2012-08-15 20:59:28 UTC (rev 264) @@ -0,0 +1,33 @@ +# This is the make file of the entire program. + + +COMPILER=gcc -g +LDFLAGS=-lm -ldl + +PNHEADERS=pnheaders +SPNBOX=spnbox +CODEGEN=newcodegen +CODEGENOBJS = $(CODEGEN) +TRANSLATOR=parser + +ct: objectfiles main_function2.o + $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ + main_function2.o $(SPNBOX)/*.a $(TRANSLATOR)/*.o $(LDFLAGS) + +objectfiles: + cd $(PNHEADERS); make + cd $(CODEGEN); make -f Makefile-cygwin.mak static + cd $(SPNBOX); make + cd $(TRANSLATOR); make + +main_function2.o: $(PNHEADERS)/main_function2.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function2.c -Ispnbox -I$(CODEGEN) -I$(PNHEADERS) + +clean: + rm -f main_function2.o + rm -f ct + cd $(PNHEADERS); make clean + cd $(CODEGEN); make -f Makefile-cygwin.mak clean + cd $(TRANSLATOR); make clean + cd $(SPNBOX); make clean + Copied: old_versions/version_1/Makefile-linux.mak (from rev 263, present_version/Makefile-linux.mak) =================================================================== --- old_versions/version_1/Makefile-linux.mak (rev 0) +++ old_versions/version_1/Makefile-linux.mak 2012-08-15 20:59:28 UTC (rev 264) @@ -0,0 +1,33 @@ +# This is the make file of the entire program. + + +COMPILER=gcc -g +LDFLAGS=-lm -ldl + +PNHEADERS=pnheaders +SPNBOX=spnbox +CODEGEN=newcodegen +CODEGENOBJS = $(CODEGEN) +TRANSLATOR=parser + +ct: objectfiles main_function2.o + $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ + main_function2.o $(SPNBOX)/*.a $(TRANSLATOR)/*.o $(LDFLAGS) + +objectfiles: + cd $(PNHEADERS); make + cd $(CODEGEN); make -f Makefile-linux.mak static + cd $(SPNBOX); make + cd $(TRANSLATOR); make + +main_function2.o: $(PNHEADERS)/main_function2.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function2.c -Ispnbox -I$(CODEGEN) -I$(PNHEADERS) + +clean: + rm -f main_function2.o + rm -f ct + cd $(PNHEADERS); make clean + cd $(CODEGEN); make -f Makefile-linux.mak clean + cd $(TRANSLATOR); make clean + cd $(SPNBOX); make clean + Copied: old_versions/version_1/README.txt (from rev 263, present_version/README.txt) =================================================================== --- old_versions/version_1/README.txt (rev 0) +++ old_versions/version_1/README.txt 2012-08-15 20:59:28 UTC (rev 264) @@ -0,0 +1,17 @@ +To build the software, copy first the directory third-party from the directory +of the current version to this directory. + +Use the command "make" to build the program. + + +After building the software you may use it as follows: + +1) Write the specification file. + +2) Copy ProcessTemplate.c, SupervisorTemplate.c, and spcommon.h from newcodegen to the working directory. These are skeleton files for the concurrency code. + +3) Run the concurrency software. This will build the source code files specified in the specification file. + +4) Build your application with the generated makefile. + + Modified: present_version/README.txt =================================================================== --- present_version/README.txt 2011-09-05 12:28:05 UTC (rev 263) +++ present_version/README.txt 2012-08-15 20:59:28 UTC (rev 264) @@ -8,4 +8,3 @@ 4) Build your application with the generated makefile. - This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-09-05 12:28:11
|
Revision: 263 http://pntool.svn.sourceforge.net/pntool/?rev=263&view=rev Author: miordache Date: 2011-09-05 12:28:05 +0000 (Mon, 05 Sep 2011) Log Message: ----------- Modified Paths: -------------- old_versions/2011/pnheaders/pns.c present_version/pnheaders/pns.c Modified: old_versions/2011/pnheaders/pns.c =================================================================== --- old_versions/2011/pnheaders/pns.c 2011-08-27 01:53:21 UTC (rev 262) +++ old_versions/2011/pnheaders/pns.c 2011-09-05 12:28:05 UTC (rev 263) @@ -1662,9 +1662,6 @@ int i, a, n; char zL, zC; - if(n <= 0) - return 1; - zL = !L || !m; zC = !C || !v; @@ -1679,6 +1676,9 @@ else n = NumberOfRows(*C); + if(n <= 0) + return 1; + for(i = 0; i < n; i++) { a = 0; if(!zL) Modified: present_version/pnheaders/pns.c =================================================================== --- present_version/pnheaders/pns.c 2011-08-27 01:53:21 UTC (rev 262) +++ present_version/pnheaders/pns.c 2011-09-05 12:28:05 UTC (rev 263) @@ -1662,9 +1662,6 @@ int i, a, n; char zL, zC; - if(n <= 0) - return 1; - zL = !L || !m; zC = !C || !v; @@ -1679,6 +1676,9 @@ else n = NumberOfRows(*C); + if(n <= 0) + return 1; + for(i = 0; i < n; i++) { a = 0; if(!zL) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-08-27 01:53:27
|
Revision: 262 http://pntool.svn.sourceforge.net/pntool/?rev=262&view=rev Author: miordache Date: 2011-08-27 01:53:21 +0000 (Sat, 27 Aug 2011) Log Message: ----------- Modified Paths: -------------- old_versions/2011/newcodegen/plantCompiler.c old_versions/2011/newcodegen/spcommon.h present_version/newcodegen/plantCompiler.c present_version/newcodegen/spcommon.h present_version/pnheaders/main_function2.c Modified: old_versions/2011/newcodegen/plantCompiler.c =================================================================== --- old_versions/2011/newcodegen/plantCompiler.c 2011-08-04 23:18:35 UTC (rev 261) +++ old_versions/2011/newcodegen/plantCompiler.c 2011-08-27 01:53:21 UTC (rev 262) @@ -24,8 +24,7 @@ f = fopen(s, "r"); if(!f) - merror(0,"CODEGEN: Unable to find template file %s in current directory",\ - s); + merror(0,"Unable to find the template file %s in the current directory. Copy spcommon.h and the template files from newcodegen/ to the working directory.", s); return f; } Modified: old_versions/2011/newcodegen/spcommon.h =================================================================== --- old_versions/2011/newcodegen/spcommon.h 2011-08-04 23:18:35 UTC (rev 261) +++ old_versions/2011/newcodegen/spcommon.h 2011-08-27 01:53:21 UTC (rev 262) @@ -80,6 +80,33 @@ } +int ___send_msg(const void* ___pdata, int ___n, int pwrite, \ + void (*dbgfn) (char* ___str, ...)); + +int ___get_msg(int ___read_end, void *p___ms, int ___n,\ + void (*dbgfn) (char* ___str, ...)); + +inline void ___send_exit_notification(struct ___thread_data* ___pthr); + +int RequestToFire(int ___n, struct ___trans* ___TRV, \ + struct ___thread_data *___pthr, \ + void (*dbgfn) (char* ___str, ...)); + +void AnnounceFiring(int ___tr, struct ___trans* ___TRV, \ + struct ___thread_data *___pthr); + +int ___NextState(struct ___trans* ___TRV, const char* ___TRVinfo, \ + int ___cplace, int ___n, int* p___finish, struct \ + ___thread_data *___pthr, void (*dbgfn) (char* ___str, ...)); + +void ___TRShuffle(struct ___trans* ___TRV, int ___n); + +inline int ___AddToTR(struct ___trans* ___TRV, int ___i, char ___flag, int ___p, \ + int ___l, int ___t, int ___a); + + + + #ifndef ___THREAD //thread code must not repeat definitions of supervisor code void ___debugInfoSub(int ___type, int ___id, char* ___vname, char* ___str, va_list ___param) { @@ -202,6 +229,11 @@ } +#ifdef ___SUPERVISOR +static pthread_mutex_t ___mtx = PTHREAD_MUTEX_INITIALIZER; +#endif + + int RequestToFire(int ___n, struct ___trans* ___TRV, \ struct ___thread_data *___pthr, \ void (*dbgfn) (char* ___str, ...)) { @@ -217,7 +249,21 @@ static int ___req_id = 0; struct ___msg ___ms; +#ifdef ___SUPERVISOR + pthread_mutex_lock(&___mtx); // one thread at a time may change ___req_id + // The lock: a temorary solution. It would be better to assigne a ___req_id + // to each thread and avoid in this way the mutex. There is no need to have + // a unique ___req_id for all threads. +#endif + ___req_id++; + if(!___req_id) + ___req_id = 1; + +#ifdef ___SUPERVISOR + pthread_mutex_unlock(&___mtx); +#endif + ___ms.type = ___FIRING_REQUEST; ___ms.id = ___pthr->id; ___ms.req_id = ___req_id; Modified: present_version/newcodegen/plantCompiler.c =================================================================== --- present_version/newcodegen/plantCompiler.c 2011-08-04 23:18:35 UTC (rev 261) +++ present_version/newcodegen/plantCompiler.c 2011-08-27 01:53:21 UTC (rev 262) @@ -24,8 +24,7 @@ f = fopen(s, "r"); if(!f) - merror(0,"CODEGEN: Unable to find template file %s in current directory",\ - s); + merror(0,"Unable to find the template file %s in the current directory. Copy spcommon.h and the template files from newcodegen/ to the working directory.", s); return f; } Modified: present_version/newcodegen/spcommon.h =================================================================== --- present_version/newcodegen/spcommon.h 2011-08-04 23:18:35 UTC (rev 261) +++ present_version/newcodegen/spcommon.h 2011-08-27 01:53:21 UTC (rev 262) @@ -80,6 +80,33 @@ } +int ___send_msg(const void* ___pdata, int ___n, int pwrite, \ + void (*dbgfn) (char* ___str, ...)); + +int ___get_msg(int ___read_end, void *p___ms, int ___n,\ + void (*dbgfn) (char* ___str, ...)); + +inline void ___send_exit_notification(struct ___thread_data* ___pthr); + +int RequestToFire(int ___n, struct ___trans* ___TRV, \ + struct ___thread_data *___pthr, \ + void (*dbgfn) (char* ___str, ...)); + +void AnnounceFiring(int ___tr, struct ___trans* ___TRV, \ + struct ___thread_data *___pthr); + +int ___NextState(struct ___trans* ___TRV, const char* ___TRVinfo, \ + int ___cplace, int ___n, int* p___finish, struct \ + ___thread_data *___pthr, void (*dbgfn) (char* ___str, ...)); + +void ___TRShuffle(struct ___trans* ___TRV, int ___n); + +inline int ___AddToTR(struct ___trans* ___TRV, int ___i, char ___flag, int ___p, \ + int ___l, int ___t, int ___a); + + + + #ifndef ___THREAD //thread code must not repeat definitions of supervisor code void ___debugInfoSub(int ___type, int ___id, char* ___vname, char* ___str, va_list ___param) { @@ -202,6 +229,11 @@ } +#ifdef ___SUPERVISOR +static pthread_mutex_t ___mtx = PTHREAD_MUTEX_INITIALIZER; +#endif + + int RequestToFire(int ___n, struct ___trans* ___TRV, \ struct ___thread_data *___pthr, \ void (*dbgfn) (char* ___str, ...)) { @@ -217,7 +249,21 @@ static int ___req_id = 0; struct ___msg ___ms; +#ifdef ___SUPERVISOR + pthread_mutex_lock(&___mtx); // one thread at a time may change ___req_id + // The lock: a temorary solution. It would be better to assigne a ___req_id + // to each thread and avoid in this way the mutex. There is no need to have + // a unique ___req_id for all threads. +#endif + ___req_id++; + if(!___req_id) + ___req_id = 1; + +#ifdef ___SUPERVISOR + pthread_mutex_unlock(&___mtx); +#endif + ___ms.type = ___FIRING_REQUEST; ___ms.id = ___pthr->id; ___ms.req_id = ___req_id; Modified: present_version/pnheaders/main_function2.c =================================================================== --- present_version/pnheaders/main_function2.c 2011-08-04 23:18:35 UTC (rev 261) +++ present_version/pnheaders/main_function2.c 2011-08-27 01:53:21 UTC (rev 262) @@ -172,7 +172,7 @@ TrData** TInf; // These are flags - unsigned char no_main = 0, signals = 0, sleep = 1, single_ch = 0; + unsigned char no_main = 0, signals = 0, sleep = 0, single_ch = 0; char help[] = "\ The program generates concurrency control code based on a specification file.\ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-08-04 23:18:42
|
Revision: 261 http://pntool.svn.sourceforge.net/pntool/?rev=261&view=rev Author: miordache Date: 2011-08-04 23:18:35 +0000 (Thu, 04 Aug 2011) Log Message: ----------- Modified Paths: -------------- old_versions/2011/spnbox/spnbox.h present_version/spnbox/spnbox.h Removed Paths: ------------- present_version/pnheaders/main_function.c Modified: old_versions/2011/spnbox/spnbox.h =================================================================== --- old_versions/2011/spnbox/spnbox.h 2011-07-28 21:14:17 UTC (rev 260) +++ old_versions/2011/spnbox/spnbox.h 2011-08-04 23:18:35 UTC (rev 261) @@ -1,14 +1,23 @@ #ifndef SPNBOX_H #define SPNBOX_H +// Written by Steven Camp in 2009. + +/* 2011 Change: The following change was made in order to ensure UpdateDPData + of dp.c is portable (to avoid "segmentation faults" on certain systems) + "__attribute__ ((packed))" was inserted in the fields of the data structures + used by UpdateDPData. Note that UpdateDPData assumes that the bytes of one + field precede immediately the bytes of the next field. The change ensures + that this assumption is correct. M.V. Iordache, August 2011. */ + #include <stdarg.h> #include "../pnheaders/matrix.h" -#include "../../../present_version/third-party/lp_solve_5.5/lpkit.h" +#include "../third-party/lp_solve_5.5/lpkit.h" #include "../pnheaders/pns.h" typedef struct supervis_r { /* result of supervis */ - matrix Dfm; //The supervised net output matrix - matrix Dfp; //The supervised net input matrix + matrix Dfm __attribute__ ((packed)); //The supervised net output matrix + matrix Dfp __attribute__ ((packed)); //The supervised net input matrix } supervis_r; typedef struct ipslv_r { @@ -51,24 +60,24 @@ typedef struct msplit_r { /*Final Petri net*/ - matrix Df; - matrix Dfm; - matrix Dfp; + matrix Df __attribute__ ((packed)); + matrix Dfm __attribute__ ((packed)); + matrix Dfp __attribute__ ((packed)); /*The transformation matrix for finding the dependent marking from the independent marking*/ - matrix Mf; + matrix Mf __attribute__ ((packed)); /*Initial and universal marking constraints*/ - matrix L0f; - matrix Lf; + matrix L0f __attribute__ ((packed)); + matrix Lf __attribute__ ((packed)); /*The modified list of independent places and the count.*/ - int* iplf; - int ipCountf; + int* iplf __attribute__ ((packed)); + int ipCountf __attribute__ ((packed)); /*The lists of transitions that cannot be made live if a specified transition is dead, indexed by the specified transition. The number of lists is the number of transitions*/ - int **TDf; + int **TDf __attribute__ ((packed)); /*This gives the number of elements in each list above*/ - int* TDfCount; + int* TDfCount __attribute__ ((packed)); } msplit_r; typedef struct nltrans_r @@ -80,42 +89,42 @@ typedef struct pn2acpn_r { //The final Petri net matrices - matrix Df; - matrix Dmf; - matrix Dpf; + matrix Df __attribute__ ((packed)); + matrix Dmf __attribute__ ((packed)); + matrix Dpf __attribute__ ((packed)); //Modified constraint matrices - matrix MXF; - matrix L0F; - matrix LF; + matrix MXF __attribute__ ((packed)); + matrix L0F __attribute__ ((packed)); + matrix LF __attribute__ ((packed)); //The new independent place list, given as a pointer to an array of integers - int *iplf; + int *iplf __attribute__ ((packed)); //The number of independent places (length of the iplf array) - int iplfCount; + int iplfCount __attribute__ ((packed)); } pn2acpn_r; typedef struct pn2eacpn_r { //New Petri net matrices - matrix Df; - matrix Dmf; - matrix Dpf; + matrix Df __attribute__ ((packed)); + matrix Dmf __attribute__ ((packed)); + matrix Dpf __attribute__ ((packed)); //New constraint matrices - matrix MXF; - matrix L0F; - matrix LF; + matrix MXF __attribute__ ((packed)); + matrix L0F __attribute__ ((packed)); + matrix LF __attribute__ ((packed)); //New independent place list, given as a pointer to an array of integers. - int *iplf; + int *iplf __attribute__ ((packed)); //Length of the independent place list. - int iplfCount; + int iplfCount __attribute__ ((packed)); /*New list of transitions that are unraisable when a given transition is dead. This is a pointer to an array of integer arrays. There is an element for each transition. Each array lists the transitions that cannot be raised if the transition that array corresponds to is dead.*/ - int **TD; + int **TD __attribute__ ((packed)); /*The number of elements in each of the arrays in the TD array of arrays. This is a pointer to an array of integers, one for each transition, that lists the number of elements in the corresponding array in TD.*/ - int *TDCount; + int *TDCount __attribute__ ((packed)); } pn2eacpn_r; typedef struct chkcons_r @@ -144,20 +153,20 @@ { /*The input and output matrices of the active subnet, given as a copy of the original subnet with dead transitions and/or places overwritten with zeroes.*/ - matrix Dma; - matrix Dpa; + matrix Dma __attribute__ ((packed)); + matrix Dpa __attribute__ ((packed)); /*The input and output matrices of the active subnet, given as those rows from Dma and Dpa that were not overwritten with zeroes.*/ - matrix Dmra; - matrix Dpra; + matrix Dmra __attribute__ ((packed)); + matrix Dpra __attribute__ ((packed)); /*The list of active transitions. This is a pointer to an array of integers, each one of which is the index of a transition that made it into the active subnet.*/ - int* TA; + int* TA __attribute__ ((packed)); /*The number of active transitions, i.e. length of the TA list.*/ - int TACount; + int TACount __attribute__ ((packed)); /*This flag will be meaninful only if a uniqueness check was done. See actn.*/ - int unique; + int unique __attribute__ ((packed)); } actn_r; /*The type of data returned by actn and tactn are identical. Create a tactn_r @@ -179,18 +188,18 @@ those that were added by the asiph procedure. Given as a matrix with a row for each place and a column for each siphon. An element will be nonzero if the corresponding place is a part of the corresponding siphon.*/ - matrix MS; + matrix MS __attribute__ ((packed)); /*The list of active siphons added by the asiph procedure. Same format as MS.*/ - matrix NMS; + matrix NMS __attribute__ ((packed)); } asiph_r; typedef struct admcon_r { /*A flag vector and its length.*/ - int *l; - int lCount; + int *l __attribute__ ((packed)); + int lCount __attribute__ ((packed)); /*A flag. If set, we found an admissible constraint.*/ - int how; + int how __attribute__ ((packed)); } admcon_r; typedef struct dp_r @@ -477,6 +486,13 @@ Written by Feng Zhu, fz...@nd... Converted to C by Po Wu, pw...@nd... */ + +int satisfied_expr(expression2 *expr); +/* Returns 1 if the expression is satisfied at the initial marking. Otherwise, + it returns 0. Written by Po Wu. Placed in tree2spec.c. The test file is + test-lintree.c. */ + + linenf_r linenf(matrix* Dm, matrix* Dp, matrix* L, int* b, int* m0, matrix* F, matrix* C, int TucCount, int* Tuc, int TuoCount, int* Tuo); /* LINENF - Linear Inequality Enforcement This function creates the supervisor enforcing Deleted: present_version/pnheaders/main_function.c =================================================================== --- present_version/pnheaders/main_function.c 2011-07-28 21:14:17 UTC (rev 260) +++ present_version/pnheaders/main_function.c 2011-08-04 23:18:35 UTC (rev 261) @@ -1,567 +0,0 @@ -#include "pns.h" -#include "spnbox.h" -#include "codegen.h" -#include"insert.h" - -int verb; - -int inline is_verbose() { return verb; } - - - - -void br_filter(char *p) { // removes beginning and end braces - int n; - if(!p) - return; - n = strlen(p); - if(!n) - return; - n--; - if(p[0] == '{' && p[n] == '}') { - p[0] = ' '; - p[n] = ' '; - } -} - - -int is_empty(char *p) { // returns 1 if p has only space and tab characters - int i; - if(!p) return 1; - for(i = 0; p[i]; i++) - if(p[i] != ' ' && p[i] != '\t') - break; - return ! p[i]; -} - -int th_filter(char** ap, char* pattern) { // remove pattern from strings - char* p = *ap, *p2 = 0; - int i, n; - if(!p || !pattern) return 0; - n = strlen(pattern); - for(i = 0; p[i]; i++) { - if(p[i] == ' ' || p[i] == '\t') - continue; - if(!strncmp(p+i, pattern, n)) { - if(!is_empty(p+i+n)) // else p2 remains equal to zero - asprintf(&p2, "%s", p+i+n); - free(*ap); - *ap = p2; - return 1; - } - break; - } - return 0; -} - - -void main_filter(char **inc, char **newinc, char **main, char *pattern) { - // Copy/append to newinc everything in *inc up to 'pattern'. - // Copy/append to *main everything in *inc following 'pattern'. - // If newinc is zero, keep in inc everything up to 'pattern'. - // If newinc is nonzero, dealloc *inc and set it to zero. - - int i, n; - char *p, *p2; - - if(!inc) return; - p = *inc; - if(!p || !pattern) return; - n = strlen(pattern); - for(i = 0; p[i]; i++) { - if(p[i] == ' ' || p[i] == '\t') - continue; - if(!strncmp(p+i, pattern, n)) // then 'pattern' has been found - break; - } - - if(main && p[i]) { // p[i] is nonzero if 'pattern' was found - if(*main) { // append to text in *main - asprintf(&p2, "%s\n\n%s", *main, p+i+n); - free(*main); - *main = p2; - } - else // write text to *main - asprintf(main, "%s", p+i+n); - } - - p[i] = 0; // keep in inc everything up to 'pattern' - if(newinc) { - if(!*newinc) - *newinc = *inc; - else { // append to text in newinc - asprintf(&p2, "%s\n\n%s", *newinc, *inc); - free(*newinc); - *newinc = p2; - free(*inc); - } - *inc = 0; - } -} - - -void sp_filter(specs *sp) { - // Removes beginning and end braces. Processes embedded instructions. - // Sets default values for fields not processed by the translator. - int i, j; - pns *pn; - arcs *pa; - if(!sp) - return; - if(!sp->process_array) - return; - - // Default values - - sp->main = 0; - sp->include = 0; - - for(i = 0; i < sp->process_num; i++) { - if(!sp->process_array[i]) - continue; - - sp->process_array[i]->main = 0; // not processed by the translator - - br_filter(sp->process_array[i]->build); - br_filter(sp->process_array[i]->include); - - // Is this a thread? - sp->process_array[i]->thread = th_filter(&(sp->process_array[i]->build),\ - "<thread>"); - // Is this a supervisor component? - sp->process_array[i]->supervisor=th_filter(&(sp->process_array[i]->build),\ - "<supervisor>"); - // Process the <main> instructions if any - if(sp->process_array[i]->supervisor) - main_filter(&(sp->process_array[i]->include), &(sp->include), \ - &(sp->main), "<main>"); - else - main_filter(&(sp->process_array[i]->include), 0, \ - &(sp->process_array[i]->main), "<main>"); - pn = sp->process_array[i]->pn; - if(pn) { - if(pn->segment) - for(j = 0; j < pn->pnum; j++) - br_filter(pn->segment[j]); - if(pn->select) - for(j = 0; j < pn->pnum; j++) - br_filter(pn->select[j]); - if(pn->arc_list) - for(j = 0; j < pn->tnum; j++) - for(pa = pn->arc_list[j]; pa; pa = pa->next) - br_filter(pa->condition); - } - } -} - - -int main(int na, char* argv[]) { - - int i, j, l1, l2, UCcnt, UOcnt, LVcnt, *Tuc, *Tuo, *Tlive, *UClst, *UOlst, *LVlst; - int labelcount = 0, finish = 0, plcnum, spcnum; - char* input, *build; - FILE* f; - specs *sp; - syncc *snc; - pns pn, pn1, *apnsv; - process **plant_array, **spv_array; - matrix L, C, H; - int *B; - struct myinsert ins; - linenf_r lin_res, lin_res2; - dp_p LVparams; - dp_r LVresult; - struct synclist *syncl, *syncl2; - struct sync_element *syn_el, *syn_el2; - struct label_lst* lls; - TrData** TInf; - - // These are flags - unsigned char no_main = 0, signals = 0, sleep = 1, single_ch = 0; - -char help[] = "\ -The program generates concurrency control code based on a specification file.\ -\n\ -\nUsage: ct [options] [specification file] [-b list]\ -\n\ -\n'list' stands for a list of files and compiler options that should be\ -\ncopied to the command line used to build the executable file.\ -\n\ -\nOptions:\ -\n -d<number> Comment on execution progress. More information displayed for\ -\n higher values of <number>, where <number> = 1 ... 20.\ -\n -m Do not generate a main function.\ -\n -s<number> Depending on the value of <number> the supervisor can be built\ -\n as follows:\ -\n 0: The supervisor waits actively for events. \ -\n 1: The supervisor is built as in option 0 except it enters a \ -\n sleep state (for a finite amount of time) when no events\ -\n are detected. \ -\n 2: The supervisor blocks when no events occur. This option is \ -\n best when the number of concurrent processes or threads is \ -\n small. The supervisor has the least computational overhead \ -\n under this option. \ -\n\ -\nExamples: ct manf.sp\ -\n ct -d3 input.sp\n"; - -// About single channe (option 2) all plant components write to the same pipe. -// Use this option if it is unlikely that the pipe would keep getting full -// (i.e. if there are not many processes). Otherwise, fairness depends on -// whether the OS is fair in deciding which requests to serve when the pipe -// keeps getting full and there are competing requests to write to the pipe. - - - // 1. INITIALIZATION - - ins = InitInsert(512); // used to store command line parameters - verb = 0; - input = 0; - - if(na <= 1) { - puts(help); - finish = 1; - } - - for(i = 1; i < na && !finish; i++) { - if(!strcmp(argv[i], "--help")) { - finish = 1; - puts(help); - break; - } - if(argv[i][0] == '-') { - switch(argv[i][1]) { - case 'd': verb = atoi(argv[i]+2); - break; - case 'm': no_main = 1; - break; - case 's': j = atoi(argv[i]+2); - switch(j) { - case 0: sleep = 0; break; - case 1: sleep = 1; break; - case 2: single_ch = 1; break; - case 3: signals = 1; break; - default: fprintf(stderr,"Unexpected parameter %s.\n", argv[i]); - } - break; - case 'b': if(argv[i][2]) - ins = FSInsert(ins, " %s", argv[i]+2); - for(i = i + 1; i < na; i++) - ins = FSInsert(ins, " %s", argv[i]); - break; - default: fprintf(stderr, "Unknown option %s.\n", argv[i]); - } - } - else { - if(input) - fprintf(stderr, "Unexpected parameter %s.\n", argv[i]); - else - input = argv[i]; - } - } - - if(!input) { - fprintf(stderr, "No input file specified."); - finish = 1; - } - else { - f = fopen(input,"r"); - if(!f) { - fprintf(stderr, "The file %s cannot be opened.\n", input); - finish = 1; - } - else { - if(verb && !finish) - fprintf(stderr, "Using the input file %s ...\n", input); - fclose(f); - } - } - - build = GetInsertBuf(&ins); - - if(finish) { // Terminate if errors were encountered - if(build) free(build); - return 0; - } - - // 2. TRANSLATE SPECIFICATION - - sp = ScanInput(input); - - // 2.1. Check translator result - - if(!sp) - return 1; - - if(sp->process_num <= 0) { - fprintf(stderr, "No processes defined! Nothing to do.\n"); - dealloc_specs(sp); - if(build) free(build); - return 0; - } - - // Set settings not detected by translator - - sp->signals = signals; - sp->sleep = sleep; - sp->singlechannel = single_ch; - sp->nomain = no_main; - - sp_filter(sp); // detect settings and remove extra braces - - if(is_verbose() >= 3) { // For debugging - for(i = 0; i < sp->process_num; i++) { - printf("\n\n======================================================"); - if(sp->process_array[i]->supervisor) - printf("\nSUPERVISOR COMPONENT: "); - else if(sp->process_array[i]->thread) - printf("\nTHREAD NAME: "); - else - printf("\nPROCESS NAME: "); - printf("%s (%s)\n", sp->process_array[i]->instance, sp->process_array[i]->name); - displaypn(*(sp->process_array[i]->pn), stdout); - } - } - - for(i = 0; i < sp->process_num; i++) - if(!sp->process_array[i]->supervisor) - break; - - if(i >= sp->process_num) { - fprintf(stderr, "No plant components defined! Nothing to do.\n"); - dealloc_specs(sp); - if(build) free(build); - return 0; - } - - - // 2.2 Label the PNs - - for(i = 0; i < sp->process_num; i++) - updatepn(sp->process_array[i]->pn, "freelabel", &labelcount); - - // 2.2.1 Deal with synchronization constraints - - for(i = 1; i; ) /* i = 0 indicates when loop may end */ - for(i = 0, snc = sp->synclist; snc; snc = snc->next) { - l1 = snc->pn1->t[snc->t1].l; l2 = snc->pn2->t[snc->t2].l; - if(l1 != l2) { - i = 1; - j = (l1 > l2)?l1:l2; - snc->pn1->t[snc->t1].l = j; snc->pn2->t[snc->t2].l = j; - } - } - - // 2.3 Obtain SC specification. Currently: - // extract the L, C, H, and b matrices (more complex specs to be done later) - // the function calculates also the composed PN - - extractLHCB(sp, &pn, &L, &H, &C, &B); - - if(is_verbose() >= 3) { // For debugging - printf("\n\n======================================================"); - printf("\nCONSTRAINTS:\n"); - printLHCB(&pn, &L, &H, &C, B, -1, stdout); - } - - // 3. SUPERVISORY CONTROL - - // 3.1 Enforce SC specs (linear constraints supported currently) - - Tuc = tcalloc(pn.tnum, sizeof(*Tuc)); - Tuo = tcalloc(pn.tnum, sizeof(*Tuo)); - Tlive = tcalloc(pn.tnum, sizeof(*Tlive)); - if(pn.t) - for(i = 0; i < pn.tnum; i++) { - Tuc[i] = pn.t[i].uncontrollable; - Tuo[i] = pn.t[i].unobservable; - Tlive[i] = pn.t[i].live; - } - - UCcnt = findIndices(Tuc, pn.tnum, sizeof(*Tuc), &UClst); - UOcnt = findIndices(Tuo, pn.tnum, sizeof(*Tuo), &UOlst); - LVcnt = findIndices(Tlive, pn.tnum, sizeof(*Tlive), &LVlst); - - lin_res = linenf(&pn.out, &pn.in, &L, B, pn.marking, &H, &C, \ - UCcnt, UClst, UOcnt, UOlst); - - if(is_verbose() >= 3) { // For debugging - printf("\n\n======================================================"); - printf("\nADMISSIBLE CONSTRAINTS (H entries omitted): \n"); - printLHCB(&pn, &lin_res.Lf, 0, &lin_res.Cf, lin_res.bf, -1, stdout); - } - - // Check whether SC was successful - - if(strcmp(lin_res.how, "OK")) - merror(0, "MAIN FUNCTION: SC has failed. Relax the specification\n\ - such as by reducing the number of uncontrollable and unobservable transitions"); - - // 3.2. Enforce liveness - - // - Liveness enforcement is applied to the closed-loop - // - Check whether the initial marking satisfies the constraints. - // - The result of liveness enforcement is enforced on the closed-loop - // with linenf and no uncontro. and unobs. transitions, since the result - // is guaranteed to be admissible. - // - The supervisor is extracted from the closed-loop reported by linenf via - // getSupervisor - - // For future work: - // - calculate initial marking constraints: check marking constraints satisfied by initial marking of plant. - // - check if responsiveness is guaranteed. - // - To help convergence, invariants from previous constraints should be - // communicated by means of the L, B parameters of the function dp. - - - if(LVcnt) { // If T-liveness enforcement has been requested - if(is_verbose() >= 3) { // For debugging - printf("\n\n======================================================"); - printf("\n\nLiveness enforcement has been requested. This may take a while ...\n"); - } - // Initialize parameters - memset(&LVparams, 0, sizeof(LVparams)); - LVparams.Dm = lin_res.Dfm; LVparams.Dp = lin_res.Dfp; - LVparams.Tuc = UClst; LVparams.TucCount = UCcnt; - LVparams.Tuo = UOlst; LVparams.TuoCount = UOcnt; - LVparams.IncludeT = LVlst; LVparams.IncludeCount = LVcnt; - LVparams.option = 12 + (is_verbose() >= 4); - - LVresult = dp(&LVparams); // apply the T-liveness enforcement procedure - if(strcmp(LVresult.how, "OK")) - merror(0, "MAIN FUNCTION: Liveness enforcement has failed. Relax the specification\nsuch as by reducing the number of uncontrollable and unobservable transitions.\nSee also the log file of the liveness enforcement algorithm."); - - // Verify L*m0 >= B - if(!TestLCB(&LVresult.Lf, lin_res.ms0, 0,0, GREATER_OR_EQUAL, LVresult.Bf)) - merror(0, "MAIN FUNCTION: Liveness enforcement has failed due to insufficient initial \nmarking (the initial marking does not satisfy the L*m >= B constraints). \nRelax the specification such as by increasing the initial marking and \nreducing the number of uncontrollable and unobservable transitions. See also \nthe log file of the liveness enforcement algorithm."); - - // Verify L0*m0 >= b0 - if(!TestLCB(&LVresult.L0f, lin_res.ms0,0,0,GREATER_OR_EQUAL, LVresult.B0f)) - merror(0, "MAIN FUNCTION: Liveness enforcement has failed due to insufficient initial \nmarking (the initial marking does not satisfy the L0*m >= B0 constraints). \nRelax the specification such as by increasing the initial marking and \nreducing the number of uncontrollable and unobservable transitions. See also \nthe log file of the liveness enforcement algorithm."); - - // Convert L*m >= B to L*m <= B (the input expected by linenf) - InvertSignOfMatrix(&LVresult.Lf); // L = -L - InvertSignOfVector(LVresult.Bf, NumberOfRows(LVresult.Lf)); // B = -B - - lin_res2 = linenf(&lin_res.Dfm, &lin_res.Dfp, &LVresult.Lf, LVresult.Bf,\ - lin_res.ms0, 0, 0, 0, 0, 0, 0); - // no uncontr. and unobs. transitions have to be passed to linenf - // since constraints are admissible - - DeallocateDp(&LVresult); DeallocateLinenf(&lin_res); - - lin_res = lin_res2; - } - - free(Tuc); free(Tuo); free(Tlive); free(UClst); free(UOlst); free(LVlst); - - // 3.3 Extract supervisor as a pn - - apnsv = getSupervisor(&pn, &lin_res.Dfm, &lin_res.Dfp, lin_res.ms0); - - if(is_verbose() >= 3) { // For debugging - printf("\n\n======================================================"); - printf("\nCOMPOSED PLANT PN PLUS PREDEFINED SUPERVISOR COMPONENTS\n"); - displaypn(pn, stdout); - printf("\n\n======================================================"); - if(apnsv) { - printf("\nSC GENERATED SUPERVISOR\n"); - displaypn(*apnsv, stdout); - } - else - printf("\nNO SC GENERATED SUPERVISOR\n"); - } - deallocpn(&pn); - - - // 4. GENERATE CODE - - // 4.1 Separate supervisor components from plant components - - spv_array = tcalloc(sp->process_num, sizeof(*spv_array)); - plant_array = tcalloc(sp->process_num, sizeof(*plant_array)); - for(i = 0, plcnum = 0, spcnum = 0; i < sp->process_num; i++) { - if(sp->process_array[i]->supervisor) { - spv_array[spcnum] = sp->process_array[i]; - spcnum++; - } - else { - plant_array[plcnum] = sp->process_array[i]; - plcnum++; - } - } - - // 4.2 Compose supervisor components with SC generated supervisor. - - pn = pn_composition(spv_array, spcnum); - pn1 = composepn(apnsv, &pn); - if(apnsv) - free(apnsv); - deallocpn(&pn); // free intermediary result - apnsv = &pn1; - - if(is_verbose() >= 3 && spcnum) { - // If spcnum != 0, then SC supervisor and final supervisor are different. - printf("\n\n======================================================"); - if(apnsv) { - printf("\nFINAL SUPERVISOR\n"); - displaypn(*apnsv, stdout); - } - } - - // 4.3 Obtain a synclist structure with the sync data for plant processes - - /* May be deleted after testing the change - lls = get_label_list(sp->process_array, sp->process_num); - syncl = get_synclist(lls, sp->process_array); - TInf = get_TrData(apnsv, sp->process_array, sp->process_num, lls); - */ - - lls = get_label_list(plant_array, plcnum); - syncl = get_synclist(lls, plant_array); - TInf = get_TrData(apnsv, plant_array, plcnum, lls); - - // Call the code generation function - - /*CodeGenerator(apnsv, sp->name, sp->process_array, sp->process_num, \ - syncl, TInf, build); - */ - sp->sbuildparam = build; - CodeGenerator(apnsv, sp, plant_array, plcnum, syncl, TInf); - - - // 5. TERMINATE - - if(apnsv) { - deallocpn(apnsv); - //free(apnsv); - } - free(plant_array); - free(spv_array); - dealloc_specs(sp); - free_label_list(lls); - free_synclist(syncl); - free_TrData(TInf, plcnum); - - return 0; -} - - - -/* Future improvements for deadlock prevention. - - Currently deadlock prevention does not account for determinism. Thus, - some potential deadlocks may remain undetected. - - The following function could be defined in the future to help the deadlock - prevention procedure converge. Additionally, a function for initial - markings could be developed. - -matrix getLB(matrix Lf, matrix Cf, int *Bf, int** B) { - // Outputs a matrix L such that L*m <= B contains the rows of - // Lf*m + Cf*v <= Bf on which Cf is zero. B is also allocated and - // initialized. - -} - -*/ Modified: present_version/spnbox/spnbox.h =================================================================== --- present_version/spnbox/spnbox.h 2011-07-28 21:14:17 UTC (rev 260) +++ present_version/spnbox/spnbox.h 2011-08-04 23:18:35 UTC (rev 261) @@ -1,14 +1,23 @@ #ifndef SPNBOX_H #define SPNBOX_H +// Written by Steven Camp in 2009. + +/* 2011 Change: The following change was made in order to ensure UpdateDPData + of dp.c is portable (to avoid "segmentation faults" on certain systems) + "__attribute__ ((packed))" was inserted in the fields of the data structures + used by UpdateDPData. Note that UpdateDPData assumes that the bytes of one + field precede immediately the bytes of the next field. The change ensures + that this assumption is correct. M.V. Iordache, August 2011. */ + #include <stdarg.h> #include "../pnheaders/matrix.h" #include "../third-party/lp_solve_5.5/lpkit.h" #include "../pnheaders/pns.h" typedef struct supervis_r { /* result of supervis */ - matrix Dfm; //The supervised net output matrix - matrix Dfp; //The supervised net input matrix + matrix Dfm __attribute__ ((packed)); //The supervised net output matrix + matrix Dfp __attribute__ ((packed)); //The supervised net input matrix } supervis_r; typedef struct ipslv_r { @@ -51,24 +60,24 @@ typedef struct msplit_r { /*Final Petri net*/ - matrix Df; - matrix Dfm; - matrix Dfp; + matrix Df __attribute__ ((packed)); + matrix Dfm __attribute__ ((packed)); + matrix Dfp __attribute__ ((packed)); /*The transformation matrix for finding the dependent marking from the independent marking*/ - matrix Mf; + matrix Mf __attribute__ ((packed)); /*Initial and universal marking constraints*/ - matrix L0f; - matrix Lf; + matrix L0f __attribute__ ((packed)); + matrix Lf __attribute__ ((packed)); /*The modified list of independent places and the count.*/ - int* iplf; - int ipCountf; + int* iplf __attribute__ ((packed)); + int ipCountf __attribute__ ((packed)); /*The lists of transitions that cannot be made live if a specified transition is dead, indexed by the specified transition. The number of lists is the number of transitions*/ - int **TDf; + int **TDf __attribute__ ((packed)); /*This gives the number of elements in each list above*/ - int* TDfCount; + int* TDfCount __attribute__ ((packed)); } msplit_r; typedef struct nltrans_r @@ -80,42 +89,42 @@ typedef struct pn2acpn_r { //The final Petri net matrices - matrix Df; - matrix Dmf; - matrix Dpf; + matrix Df __attribute__ ((packed)); + matrix Dmf __attribute__ ((packed)); + matrix Dpf __attribute__ ((packed)); //Modified constraint matrices - matrix MXF; - matrix L0F; - matrix LF; + matrix MXF __attribute__ ((packed)); + matrix L0F __attribute__ ((packed)); + matrix LF __attribute__ ((packed)); //The new independent place list, given as a pointer to an array of integers - int *iplf; + int *iplf __attribute__ ((packed)); //The number of independent places (length of the iplf array) - int iplfCount; + int iplfCount __attribute__ ((packed)); } pn2acpn_r; typedef struct pn2eacpn_r { //New Petri net matrices - matrix Df; - matrix Dmf; - matrix Dpf; + matrix Df __attribute__ ((packed)); + matrix Dmf __attribute__ ((packed)); + matrix Dpf __attribute__ ((packed)); //New constraint matrices - matrix MXF; - matrix L0F; - matrix LF; + matrix MXF __attribute__ ((packed)); + matrix L0F __attribute__ ((packed)); + matrix LF __attribute__ ((packed)); //New independent place list, given as a pointer to an array of integers. - int *iplf; + int *iplf __attribute__ ((packed)); //Length of the independent place list. - int iplfCount; + int iplfCount __attribute__ ((packed)); /*New list of transitions that are unraisable when a given transition is dead. This is a pointer to an array of integer arrays. There is an element for each transition. Each array lists the transitions that cannot be raised if the transition that array corresponds to is dead.*/ - int **TD; + int **TD __attribute__ ((packed)); /*The number of elements in each of the arrays in the TD array of arrays. This is a pointer to an array of integers, one for each transition, that lists the number of elements in the corresponding array in TD.*/ - int *TDCount; + int *TDCount __attribute__ ((packed)); } pn2eacpn_r; typedef struct chkcons_r @@ -144,20 +153,20 @@ { /*The input and output matrices of the active subnet, given as a copy of the original subnet with dead transitions and/or places overwritten with zeroes.*/ - matrix Dma; - matrix Dpa; + matrix Dma __attribute__ ((packed)); + matrix Dpa __attribute__ ((packed)); /*The input and output matrices of the active subnet, given as those rows from Dma and Dpa that were not overwritten with zeroes.*/ - matrix Dmra; - matrix Dpra; + matrix Dmra __attribute__ ((packed)); + matrix Dpra __attribute__ ((packed)); /*The list of active transitions. This is a pointer to an array of integers, each one of which is the index of a transition that made it into the active subnet.*/ - int* TA; + int* TA __attribute__ ((packed)); /*The number of active transitions, i.e. length of the TA list.*/ - int TACount; + int TACount __attribute__ ((packed)); /*This flag will be meaninful only if a uniqueness check was done. See actn.*/ - int unique; + int unique __attribute__ ((packed)); } actn_r; /*The type of data returned by actn and tactn are identical. Create a tactn_r @@ -179,18 +188,18 @@ those that were added by the asiph procedure. Given as a matrix with a row for each place and a column for each siphon. An element will be nonzero if the corresponding place is a part of the corresponding siphon.*/ - matrix MS; + matrix MS __attribute__ ((packed)); /*The list of active siphons added by the asiph procedure. Same format as MS.*/ - matrix NMS; + matrix NMS __attribute__ ((packed)); } asiph_r; typedef struct admcon_r { /*A flag vector and its length.*/ - int *l; - int lCount; + int *l __attribute__ ((packed)); + int lCount __attribute__ ((packed)); /*A flag. If set, we found an admissible constraint.*/ - int how; + int how __attribute__ ((packed)); } admcon_r; typedef struct dp_r This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-28 21:14:27
|
Revision: 260 http://pntool.svn.sourceforge.net/pntool/?rev=260&view=rev Author: miordache Date: 2011-07-28 21:14:17 +0000 (Thu, 28 Jul 2011) Log Message: ----------- Modified Paths: -------------- old_versions/2011/translator/pnscript.g old_versions/2011/translator/pnscriptParser.c old_versions/2011/translator/pnscriptParser.h present_version/pnheaders/pns.h present_version/spnbox/spnbox.h present_version/spnbox/tests/test-lintree.c present_version/spnbox/tree2spec.c Modified: old_versions/2011/translator/pnscript.g =================================================================== --- old_versions/2011/translator/pnscript.g 2011-07-28 19:40:14 UTC (rev 259) +++ old_versions/2011/translator/pnscript.g 2011-07-28 21:14:17 UTC (rev 260) @@ -1,648 +1,655 @@ -//This pass lexes and parses the grammer into an AST for future passes -//I try to do all the error checking here, as early as possible. -//The ASSOC_ARRAY pointers 'processes' and 'threads' are defined here for debugging -// and passed on to pngenerator.g later so it does not have to rebuild these data -// structures - -grammar pnscript; -options { - language=C; - output=AST; -} - -tokens { - HEADER; - TO; - FROM; - GROUP; - PLACE; - SUB; -} - -@header { - #include <stdbool.h> - #include <string.h> - #include "pns.h" - #include "datastructures.h" - - #define GET_TOKEN(list, num) (pANTLR3_COMMON_TOKEN) list->get(list, num) - //retrieves the text of the numth token in the list - #define GET_TEXT(list, num) (char*) (GET_TOKEN(list, num))->getText((GET_TOKEN(list, num)))->chars - #define WARN_AT(token) showContext(ctx, token) - #define FAIL_AT(token) fprintf(stderr, "Parser Failed: "); showContext(ctx, token); exitAtEnd = true; - - //don't ask... I have no idea, but you get bus errors otherwise - //there's got to be a bug in the hash table backing this list. - #define kNAME 0 - #define kPROC 1 - #define kPLACES 2 - #define kTRANS 3 -} - -@members { - static void showContext(ppnscriptParser ctx, pANTLR3_COMMON_TOKEN tok); - static void addPlace(ASSOC_ARRAY* placeList, void* place); - static void addTrans(ASSOC_ARRAY* transList, void* trans); - static void free_proc_list(void** list); - static void** copy_list(void** list); - - //see kDEFINES above - ASSOC_ARRAY* processes; - //see kDEFINES above - ASSOC_ARRAY* threads; - pANTLR3_COMMON_TOKEN_STREAM tStream; - exitAtEnd = false; - - static void showContext(ppnscriptParser ctx, pANTLR3_COMMON_TOKEN tok) { - int i; - pANTLR3_LIST list; - list = (pANTLR3_LIST) tStream->getTokenRange(tStream, tok->getTokenIndex(tok)-3, tok->getTokenIndex(tok)+4); - - fprintf(stderr, "Line \%i, character \%i, somewhere around\n", tok->getLine(tok), tok->getCharPositionInLine(tok)); - for(i = 0; i < list->size(list); i++) { - fprintf(stderr, "\%s", GET_TEXT(list, i)); - } - fprintf(stderr, "\n"); - } - - static void addPlace(ASSOC_ARRAY* placeList, void* place) { - int* i; - i = tmalloc(sizeof(int)); - *i = placeList->size(placeList); - //these values (yes, values) are going to be copied into the specs structure - placeList->add(placeList, (char*) place, i, ANTLR3_FUNC_PTR(free)); - } - - static void addTrans(ASSOC_ARRAY* transList, void* trans) { - int* i; - i = tmalloc(sizeof(int)); - *i = transList->size(transList); - //these values (yes, values) are going to be copied into the specs structure - transList->add(transList, (char*) trans, i, ANTLR3_FUNC_PTR(free)); - } - - static void free_proc_list(void** list) { - //the name is freed by the parser - dealloc_process((process*)list[kPROC]); - ((ASSOC_ARRAY*)list[kPLACES])->free((ASSOC_ARRAY*)list[kPLACES]); - ((ASSOC_ARRAY*)list[kTRANS])->free((ASSOC_ARRAY*)list[kTRANS]); - } - - static void** copy_list(void** list) { - void** ret; - ret = tcalloc(4, sizeof(void*)); - ret[kNAME] = list[kNAME]; - ret[kPROC] = list[kPROC]; - ret[kPLACES] = list[kPLACES]; - ret[kTRANS] = list[kTRANS]; - return ret; - } -} - -//this encompasses the grammer and serves as our entry point -pn[pANTLR3_COMMON_TOKEN_STREAM tokenStream, ASSOC_ARRAY* procData, ASSOC_ARRAY* threadData] -@init { - processes = procData; - threads = threadData; - tStream = tokenStream; -} - : proc_declarations!+ proc_definitions+ { - //make sure every process was defined - int i; - void** list; - process* proc; - for(i = 0; i < processes->size(processes); i++) { - list = (void**) processes->iter(processes, i); - proc = (process*) list[kPROC]; - if(proc->start) { - proc->start = false; - } else { - fprintf(stderr, "ERROR: Process \%s declared but not defined...?\n", (char*) list[kNAME]); - exit(1); - } - } - } proc_instantiations+ constraints* other_commands* { - if(exitAtEnd) { - exit(1); - } - }; -//------------------- -proc_declarations -scope { - process* procObj; -} -@init { - $proc_declarations::procObj = tmalloc(sizeof(process)); - $proc_declarations::procObj->instance = NULL; - $proc_declarations::procObj->build = NULL; - $proc_declarations::procObj->include = NULL; -} - : proc_dec^ proc_build? proc_include?; -proc_dec -@init { - //set up the symbol table - void** proc = tcalloc(4, sizeof(void*)); - ASSOC_ARRAY* places; - ASSOC_ARRAY* trans; - - //do you want to enter in (much less keep track of) more place names? - places = newAssocArray(32); - trans = newAssocArray(32); - //this process has not been defined yet, only declared - $proc_declarations::procObj->type = false; - - proc[kNAME] = NULL; - //processes will be freed by the specs structure - proc[kPROC] = $proc_declarations::procObj; - proc[kPLACES] = places; - proc[kTRANS] = trans; -} - : (EXTERN { - $proc_declarations::procObj->type = true; - })? PROCESS ID { - char* name; - name = (char*) $ID.text->chars; - proc[kNAME] = name; - $proc_declarations::procObj->name = tcalloc(strlen(name)+1, sizeof(char)); - strcpy($proc_declarations::procObj->name, name); - //the threads will free these lists - processes->add(processes, (char*) name, proc, ANTLR3_FUNC_PTR(free_proc_list)); - } SEMICOLON -> ^(ID EXTERN?); -proc_build - : BUILD CODE_BLOCK { - char* tmp; - tmp = (char*) $CODE_BLOCK.text->chars; - $proc_declarations::procObj->build = tcalloc(strlen(tmp)+1, sizeof(char)); - strcpy($proc_declarations::procObj->build, tmp); - } SEMICOLON -> ^(BUILD CODE_BLOCK); -proc_include - : INCLUDE CODE_BLOCK { - char* tmp; - tmp = (char*) $CODE_BLOCK.text->chars; - $proc_declarations::procObj->include = tcalloc(strlen(tmp)+1, sizeof(char)); - strcpy($proc_declarations::procObj->include, tmp); - } SEMICOLON -> ^(INCLUDE CODE_BLOCK); -//------------------- -proc_definitions -scope { - char* name; - bool external; - ASSOC_ARRAY* places; - ASSOC_ARRAY* trans; -} - : def_start^ places! trans! trans_defs* select_functions* nondeterm?; -def_start -@init { - void** list; -} - : ID { - process* proc; - $proc_definitions::name = (char*) $ID.text->chars; - list = (void**) processes->get(processes, $proc_definitions::name); - if(list == NULL) { - fprintf(stderr, "ERROR: You didn't declare a process type \%s...?\n", (char*) $ID.text->chars); - FAIL_AT($ID); - } - proc = (process*) list[kPROC]; - //used to signal that the process has been defined - proc->start = true; - $proc_definitions::external = (bool) proc->type; - $proc_definitions::places = (ASSOC_ARRAY*) list[kPLACES]; - $proc_definitions::trans = (ASSOC_ARRAY*) list[kTRANS]; - } PNDEF SEMICOLON? -> ID; -places - : PLACES (ID { - addPlace($proc_definitions::places, (char*)$ID.text->chars); - })+ SEMICOLON -> ^(PLACES ID+); -trans - : TRANS (ID { - if(NULL != $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { - fprintf(stderr, "ERROR: The place and transition \%s have the same name in process \%s\n", $ID.text->chars, $proc_definitions::name); - FAIL_AT($ID); - } - addTrans($proc_definitions::trans, (char*)$ID.text->chars); - })+ SEMICOLON -> ^(TRANS ID+); -trans_defs - : ( extern_trans_def { - //this could be a gated semantic predicate, but my error handling is more helpful - if(!$proc_definitions::external) { - fprintf(stderr, "ERROR: Process \%s looks like an extern process, but you didn't declare it that way...?\n", $proc_definitions::name); - FAIL_AT($extern_trans_def.start); - } - } - | trans_def { - if($proc_definitions::external) { - fprintf(stderr, "ERROR: Process \%s is extern, but you're declaring everything here...?\n", $proc_definitions::name); - FAIL_AT($trans_def.start); - } - }) SEMICOLON!; -extern_trans_def - : (MULT p=ID { - if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $p.text->chars)) { - fprintf(stderr, "WARNING: You didn't declare a place \%s in process \%s...\n", $p.text->chars, $proc_definitions::name); - WARN_AT($p); - addPlace($proc_definitions::places, $p.text->chars); - } - } ':' (t+=ID { - if(NULL == $proc_definitions::trans->get($proc_definitions::trans, (char*) t->getText(t)->chars)) { - fprintf(stderr, "WARNING: You didn't declare a transition \%s in process \%s...\n", t->getText(t)->chars, $proc_definitions::name); - WARN_AT(t); - addTrans($proc_definitions::trans, t->getText(t)->chars); - } - })+) -> ^(FROM[$p, $p.text->chars] $t+) - | (p=ID { - if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $p.text->chars)) { - fprintf(stderr, "WARNING: You didn't declare a place \%s in process \%s...\n", $p.text->chars, $proc_definitions::name); - WARN_AT($p); - addPlace($proc_definitions::places, $p.text->chars); - } - } '*:' (t+=ID { - if(NULL == $proc_definitions::trans->get($proc_definitions::trans, (char*) t->getText(t)->chars)) { - fprintf(stderr, "WARNING: You didn't declare a transition \%s in process \%s...\n", t->getText(t)->chars, $proc_definitions::name); - WARN_AT(t); - addTrans($proc_definitions::trans, t->getText(t)->chars); - } - })+) -> ^(TO[$p, $p.text->chars] $t+); -trans_def -@init { - pANTLR3_COMMON_TOKEN tran = NULL; - pANTLR3_COMMON_TOKEN place = NULL; -} - : (ID { - if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { - fprintf(stderr, "WARNING: You didn't declare a place \%s in process \%s...\n", $ID.text->chars, $proc_definitions::name); - WARN_AT($ID); - //silly user! We'll try to help them out here... - addPlace($proc_definitions::places, $ID.text->chars); - } - } CODE CODE_BLOCK -> ^(ID CODE_BLOCK)) - | (start='(' items+=ID (',' items+=ID)+ ')' { - //one of the first two of these ID's needs to be a transition - char* text; - int i; - if($proc_definitions::places->get($proc_definitions::places, GET_TEXT($items, 0)) != NULL) { - //this is the start place, we'll deal with it later - place = GET_TOKEN($items, 0); - $items->remove($items, 0); - } - pANTLR3_COMMON_TOKEN tmp; - for(i = 0; i < $items->size($items); i++) { - tmp = GET_TOKEN($items, i); - text = (char*) tmp->getText(tmp)->chars; - if(NULL != $proc_definitions::trans->get($proc_definitions::trans, text)) { - $items->remove($items, i); - tran = tmp; - } else if(NULL == $proc_definitions::places->get($proc_definitions::places, text)) { - fprintf(stderr, "WARNING: Attempted to reference \%s in process \%s. Assuming it's a place...\n", text, $proc_definitions::name); - WARN_AT(tmp); - addPlace($proc_definitions::places, text); - } - } - if(tran == NULL) { - fprintf(stderr, "ERROR: You declared a transition arc without a transition...?\n"); - FAIL_AT(GET_TOKEN($items, 0)); - //we need this transition to create the AST tokens. - if(place != NULL) { - tran = place; - } else { - tran = GET_TOKEN($items, 0); //we're guaranteed at least one... - } - } - } (DOT CODE_BLOCK)? -> {place != NULL}? ^(ID[tran, tran->getText(tran)->chars] PLACE[place, place->getText(place)->chars] $items* CODE_BLOCK?) - -> ^(ID[tran, tran->getText(tran)->chars] $items+ CODE_BLOCK?)); -select_functions - : SELECT_DEF ID { - if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { - fprintf(stderr, "ERROR: You tried to add a select function to a place \%s that is not declared in process \%s.", $ID.text->chars, $proc_definitions::name); - fprintf(stderr, " I have no idea what you are trying to do here...?\n"); - FAIL_AT($ID); - } - } DOT CODE_BLOCK SEMICOLON -> ^(SELECT_DEF ID CODE_BLOCK); -nondeterm - : text='nondeterministic places: ' (ID { - if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { - fprintf(stderr, "WARNING: You declared the place \%s as nondeterministic, but this place has never been mentioned before in the", $ID.text->chars); - fprintf(stderr, " process \%s. I don't think you meant to do this, but I'll humor you...\n", $proc_definitions::name); - WARN_AT($ID); - addPlace($proc_definitions::places, $ID.text->chars); - } - })+ SEMICOLON -> ^($text ID+); -//------------------- -//We don't accept new places or transitions after this point. From now on, those are errors. -//------------------- -proc_instantiations - : (proc_init | sync_def | proc_start) SEMICOLON!; -proc_init - : ID! proc_init_helper[(char*) $ID.text->chars]+; - -proc_init_helper[char* proc] -@init { - void** list; - ASSOC_ARRAY* places; -} - : ID { - if(0 == strcasecmp((char*) $ID.text->chars, (char*) "global")) { - fprintf(stderr, "ERROR: Sorry, you cannot name a thread \"\%s\".\n", $ID.text->chars); - FAIL_AT($ID); - } - list = copy_list((void**) processes->get(processes, $proc)); - if(list == NULL) { - fprintf(stderr, "ERROR: You didn't declare a process type \%s...?\n", $proc); - FAIL_AT($proc); - } - places = (ASSOC_ARRAY*) list[kPLACES]; - //when processes gets cleaned up by the ANTLR libraries, this list pointer will get - //deallocated. Really, it will. Don't try to free it here, because you can't free memory twice - threads->add(threads, (char*) $ID.text->chars, list, NULL); - } ('(' ids+=numbered_ID[places, $ID.text] (',' ids+=numbered_ID[places, $ID.text])* ')')? -> ^(ID $ids*); - -sync_def - : SYNC_TOK (group_elements { - int size; - char* text1; - char* text2; - void** list; - ASSOC_ARRAY* trans; - - size = $group_elements.ret->size($group_elements.ret); - text1 = GET_TEXT($group_elements.ret, 0); - if(size == 1) { - fprintf(stderr, "ERROR: You tried to sync \%s, but that is not a fully qualified transition name...?\n", text1); - FAIL_AT($SYNC_TOK); - } - - list = (void**) threads->get(threads, text1); - if(list == NULL) { - fprintf(stderr, "ERROR: You did not declare a thread named \%s...?\n", text1); - FAIL_AT($SYNC_TOK); - } - text2 = GET_TEXT($group_elements.ret, 1); - trans = (ASSOC_ARRAY*) list[kTRANS]; - if(NULL == trans->get(trans, text2)) { - fprintf(stderr, "ERROR: You did not declare a transition \%s in process \%s\n", text2, (char*) list[kNAME]); - FAIL_AT($SYNC_TOK); - } - })+ -> ^(SYNC_TOK group_elements+); -proc_start - : START^ (ID { - if(NULL == threads->get(threads, (char*) $ID.text->chars)) { - fprintf(stderr, "ERROR: You are attempting to start an undeclared thread \%s...?\n", $ID.text->chars); - FAIL_AT($ID); - } - })+; -numbered_ID[ASSOC_ARRAY* places, pANTLR3_STRING name] - : ID { - if(NULL == places->get(places, (char*) $ID.text->chars)) { - fprintf(stderr, "ERROR: You tried to start the thread \%s at an undefined place \%s...?\n", name->chars, $ID.text->chars); - FAIL_AT($ID); - } - } (':'INT)? -> ^(ID INT?); -//------------------- -constraints -scope { - char* procName; - char* name; - ASSOC_ARRAY* places; - ASSOC_ARRAY* trans; -} -@init { - $constraints::procName = NULL; - $constraints::name = NULL; - $constraints::places = NULL; - $constraints::trans = NULL; -} - : constraint_block^ ((eq SEMICOLON!)|live_def|uncontrol|unobserve)*; -constraint_block - : ID { - $constraints::name = (char*) $ID.text->chars; - void** thread = (void**) threads->get(threads, $constraints::name); - bool tmp = 0 != strcasecmp($constraints::name, (char*) "global"); - if(NULL == thread && tmp) { - fprintf(stderr, "ERROR: You did not declare a thread named \%s...?\n", $constraints::name); - FAIL_AT($ID); - } - if(tmp) { - $constraints::procName = (char*) thread[kNAME]; - $constraints::places = (ASSOC_ARRAY*) thread[kPLACES]; - $constraints::trans = (ASSOC_ARRAY*) thread[kTRANS]; - } - } CONSTRAINTS SEMICOLON? -> ^(ID); -eq - : relationalExpression ((AND_OP|OR_OP)^ relationalExpression)?; -relationalExpression - : additiveExpression (EQ_OP^ additiveExpression)*; -additiveExpression - : primary ((PLUS|MINUS)^ primary)*; -primary - : '('! eq ')'! - | MINUS '(' additiveExpression ')' -> ^(SUB[$MINUS, "-"] additiveExpression) - | group_elements { - if($constraints::places != NULL) { - //I'm assuming that threads can't reference one another for internal constraints - if($group_elements.ret->size($group_elements.ret) == 1) { //simple reference - if(NULL == $constraints::places->get($constraints::places, GET_TEXT($group_elements.ret, 0))) { - if(NULL == $constraints::trans->get($constraints::trans, GET_TEXT($group_elements.ret, 0))) { - fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 0), $constraints::procName); - FAIL_AT(GET_TOKEN($group_elements.ret, 0)); - } - } - } else { //special type of transition check - if(strcasecmp(GET_TEXT($group_elements.ret, 0), "q") != 0) { - fprintf(stderr, "ERROR: You specified an invalid transition subtype \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 0), $constraints::procName); - FAIL_AT(GET_TOKEN($group_elements.ret, 0)); - } - //if it's special, it must be a transition - if(NULL == $constraints::trans->get($constraints::trans, GET_TEXT($group_elements.ret, 1))) { - fprintf(stderr, "ERROR: You did not declare a transition \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 1), $constraints::procName); - FAIL_AT(GET_TOKEN($group_elements.ret, 1)); - } - } - } else { //global - void** list; - char* name; - ASSOC_ARRAY* places; - ASSOC_ARRAY* trans; - if($group_elements.ret->size($group_elements.ret) == 1) { - fprintf(stderr, "ERROR: Attempting to use an unqualified reference to \%s in global constraints...?\n", GET_TEXT($group_elements.ret, 0)); - FAIL_AT(GET_TOKEN($group_elements.ret, 0)); - } - - if($group_elements.ret->size($group_elements.ret) == 2) { - list = (void**) threads->get(threads, GET_TEXT($group_elements.ret, 0)); - if(list == NULL) { - fprintf(stderr, "ERROR: You did not define a thread \%s...?\n", GET_TEXT($group_elements.ret, 0)); - FAIL_AT(GET_TOKEN($group_elements.ret, 0)); - } - name = (char*) list[kNAME]; - places = (ASSOC_ARRAY*) list[kPLACES]; - trans = (ASSOC_ARRAY*) list[kTRANS]; - if(NULL == places->get(places, GET_TEXT($group_elements.ret, 1))) { - if(NULL == trans->get(trans, GET_TEXT($group_elements.ret, 1))) { - fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 1), name); - FAIL_AT(GET_TOKEN($group_elements.ret, 0)); - } - } - } else { //special transition check - list = (void**) threads->get(threads, GET_TEXT($group_elements.ret, 1)); - if(list == NULL) { - fprintf(stderr, "ERROR: You did not define a thread \%s...?\n", GET_TEXT($group_elements.ret, 1)); - FAIL_AT(GET_TOKEN($group_elements.ret, 1)); - } - name = (char*) list[kNAME]; - trans = (ASSOC_ARRAY*) list[kTRANS]; - if(NULL == trans->get(trans, GET_TEXT($group_elements.ret, 2))) { - fprintf(stderr, "ERROR: You did not declare a transition \%s in thread \%s...?\n", GET_TEXT($group_elements.ret, 2), name); - FAIL_AT(GET_TOKEN($group_elements.ret, 0)); - } - } - } - } - | number (MULT^ primary)?; -live_def - : LIVE { - if($constraints::procName == NULL) { - fprintf(stderr, "ERROR: The \"live\" keyword is not valid in a global context.\n"); - FAIL_AT($LIVE); - } - } ( - ALL (MINUS id1=ID { - if(NULL == $constraints::places->get($constraints::places, (char*) $id1.text->chars)) { - if(NULL == $constraints::trans->get($constraints::trans, (char*) $id1.text->chars)) { - fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $id1.text->chars, $constraints::procName); - FAIL_AT($id1); - } - } - })* -> ^(LIVE ALL ID*) - | (id2=ID { - if(NULL == $constraints::places->get($constraints::places, (char*) $id2.text->chars)) { - if(NULL == $constraints::trans->get($constraints::trans, (char*) $id2.text->chars)) { - fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $id2.text->chars, $constraints::procName); - FAIL_AT($id2); - } - } - })+ -> ^(LIVE ID+) - ) SEMICOLON; -uncontrol - : UNCONTROL { - if($constraints::procName == NULL) { - fprintf(stderr, "ERROR: The \"uncontrollable\" keyword is not valid in a global context.\n"); - FAIL_AT($UNCONTROL); - } - } (ID { - if(NULL == $constraints::places->get($constraints::places, (char*) $ID.text->chars)) { - if(NULL == $constraints::trans->get($constraints::trans, (char*) $ID.text->chars)) { - fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $ID.text->chars, $constraints::procName); - FAIL_AT($ID); - } - } - })+ SEMICOLON -> ^(UNCONTROL ID+); -unobserve - : UNOBSERVE { - if($constraints::procName == NULL) { - fprintf(stderr, "ERROR: The \"unobservable\" keyword is not valid in a global context.\n"); - FAIL_AT($UNOBSERVE); - } - } (ID { - if(NULL == $constraints::places->get($constraints::places, (char*) $ID.text->chars)) { - if(NULL == $constraints::trans->get($constraints::trans, (char*) $ID.text->chars)) { - fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $ID.text->chars, $constraints::procName); - FAIL_AT($ID); - } - } - })+ SEMICOLON -> ^(UNOBSERVE ID+); -//------------------- -other_commands - : print; -print - : PRINT ID 'to' group_elements -> ^(PRINT ID group_elements); - -number - : MINUS^? INT; -group_elements returns [pANTLR3_VECTOR ret] - : idList+=ID (DOT idList+=ID)* {$ret = $idList;} -> ^(GROUP ID+); - -//------------------------------------------------------- - -EXTERN - : 'extern'; -PROCESS - : 'process' 'type'?; -BUILD - : 'build' ':'; -INCLUDE - : 'include' ':'; - -PNDEF - : '.PN:'; -PLACES - : 'places' ':'; -TRANS - : 'trans' 'itions'? ':'; -CODE - : '.code:'; -SELECT_DEF - : 'select function'; - -SYNC_TOK - : 'sync'; -START - : 'start'; - -CONSTRAINTS - : '.constraints:'; -AND_OP - : '&&'|'and'|'AND'; -OR_OP - : '||'|'or'|'OR'; -EQ_OP - : '<'|'<='|'>='|'>';//'='|'!='| -MULT - : '*'; -LIVE - : 'live:'; -ALL : 'all'|'All'|'ALL'; -UNCONTROL - : 'uncontrollable: '; -UNOBSERVE - : 'unobservable: '; - -PRINT - : 'print'; - -//inspiration was drawn from ANTLR's implementation of code blocks, and the functionality should be -//equivalent. However, ANTLR's native implementation utterly failed to work. This works. -CODE_BLOCK //This takes care of nested blocks and close '}' in strings. Comments are NOT handled. - : '{' ( CODE_BLOCK | STRING | ~('{'|'}'|'\"'|'\'') )* '}'; -STRING -options { greedy=false; } - : '\'' (CHAR_ESC|~('\\'|'\''))* '\'' - | '\"' (CHAR_ESC|~('\\'|'\"'))* '\"'; -CHAR_ESC - : '\\\'' - | '\\\"' - | '\\' ~('\''|'\"'); - -DOT - : '.'; -PLUS - : '+'; -MINUS - : '-'; -INT - : '0'..'9'+ ; -ID - : ('A'..'Z'|'a'..'z') ('A'..'Z'|'a'..'z'|'0'..'9'|'_')*; -//newline endings are complicated. See Python example code. I'll get them right eventually, -//but it's just not worth it right now. I'm using ';' endings for development. -SEMICOLON - : ';'+; //('\r'?'\n')+; - -//we don't care about white space -WS //see comment on END - : (' '|'\t'|'\r'|'\n')+ {$channel=HIDDEN;}; -//define c-style comments -COMMENT //see comment on END - : '//' .* '\n' {$channel=HIDDEN;}; -BLOCK_COMMENT -options { greedy=false; } - : '/*' .* '*/' {$channel=HIDDEN;}; +//This pass lexes and parses the grammer into an AST for future passes +//I try to do all the error checking here, as early as possible. +//The ASSOC_ARRAY pointers 'processes' and 'threads' are defined here for debugging +// and passed on to pngenerator.g later so it does not have to rebuild these data +// structures + +grammar pnscript; +options { + language=C; + output=AST; +} + +tokens { + HEADER; + TO; + FROM; + GROUP; + PLACE; + SUB; +} + +@header { + #include <stdbool.h> + #include <string.h> + #include "pns.h" + + /* + Bug Fix: Basil Hall, 7/25/2011 + Was producing ("datastructures.h" no such file or directory) error. + Fix: Cygwin is not case sensitive in a Windows filesystem. Unix/Linux filesystems are always case sensitive. + #include "datastructures.h" + */ + #include "dataStructures.h" + + #define GET_TOKEN(list, num) (pANTLR3_COMMON_TOKEN) list->get(list, num) + //retrieves the text of the numth token in the list + #define GET_TEXT(list, num) (char*) (GET_TOKEN(list, num))->getText((GET_TOKEN(list, num)))->chars + #define WARN_AT(token) showContext(ctx, token) + #define FAIL_AT(token) fprintf(stderr, "Parser Failed: "); showContext(ctx, token); exitAtEnd = true; + + //don't ask... I have no idea, but you get bus errors otherwise + //there's got to be a bug in the hash table backing this list. + #define kNAME 0 + #define kPROC 1 + #define kPLACES 2 + #define kTRANS 3 +} + +@members { + static void showContext(ppnscriptParser ctx, pANTLR3_COMMON_TOKEN tok); + static void addPlace(ASSOC_ARRAY* placeList, void* place); + static void addTrans(ASSOC_ARRAY* transList, void* trans); + static void free_proc_list(void** list); + static void** copy_list(void** list); + + //see kDEFINES above + ASSOC_ARRAY* processes; + //see kDEFINES above + ASSOC_ARRAY* threads; + pANTLR3_COMMON_TOKEN_STREAM tStream; + exitAtEnd = false; + + static void showContext(ppnscriptParser ctx, pANTLR3_COMMON_TOKEN tok) { + int i; + pANTLR3_LIST list; + list = (pANTLR3_LIST) tStream->getTokenRange(tStream, tok->getTokenIndex(tok)-3, tok->getTokenIndex(tok)+4); + + fprintf(stderr, "Line \%i, character \%i, somewhere around\n", tok->getLine(tok), tok->getCharPositionInLine(tok)); + for(i = 0; i < list->size(list); i++) { + fprintf(stderr, "\%s", GET_TEXT(list, i)); + } + fprintf(stderr, "\n"); + } + + static void addPlace(ASSOC_ARRAY* placeList, void* place) { + int* i; + i = tmalloc(sizeof(int)); + *i = placeList->size(placeList); + //these values (yes, values) are going to be copied into the specs structure + placeList->add(placeList, (char*) place, i, ANTLR3_FUNC_PTR(free)); + } + + static void addTrans(ASSOC_ARRAY* transList, void* trans) { + int* i; + i = tmalloc(sizeof(int)); + *i = transList->size(transList); + //these values (yes, values) are going to be copied into the specs structure + transList->add(transList, (char*) trans, i, ANTLR3_FUNC_PTR(free)); + } + + static void free_proc_list(void** list) { + //the name is freed by the parser + dealloc_process((process*)list[kPROC]); + ((ASSOC_ARRAY*)list[kPLACES])->free((ASSOC_ARRAY*)list[kPLACES]); + ((ASSOC_ARRAY*)list[kTRANS])->free((ASSOC_ARRAY*)list[kTRANS]); + } + + static void** copy_list(void** list) { + void** ret; + ret = tcalloc(4, sizeof(void*)); + ret[kNAME] = list[kNAME]; + ret[kPROC] = list[kPROC]; + ret[kPLACES] = list[kPLACES]; + ret[kTRANS] = list[kTRANS]; + return ret; + } +} + +//this encompasses the grammer and serves as our entry point +pn[pANTLR3_COMMON_TOKEN_STREAM tokenStream, ASSOC_ARRAY* procData, ASSOC_ARRAY* threadData] +@init { + processes = procData; + threads = threadData; + tStream = tokenStream; +} + : proc_declarations!+ proc_definitions+ { + //make sure every process was defined + int i; + void** list; + process* proc; + for(i = 0; i < processes->size(processes); i++) { + list = (void**) processes->iter(processes, i); + proc = (process*) list[kPROC]; + if(proc->start) { + proc->start = false; + } else { + fprintf(stderr, "ERROR: Process \%s declared but not defined...?\n", (char*) list[kNAME]); + exit(1); + } + } + } proc_instantiations+ constraints* other_commands* { + if(exitAtEnd) { + exit(1); + } + }; +//------------------- +proc_declarations +scope { + process* procObj; +} +@init { + $proc_declarations::procObj = tmalloc(sizeof(process)); + $proc_declarations::procObj->instance = NULL; + $proc_declarations::procObj->build = NULL; + $proc_declarations::procObj->include = NULL; +} + : proc_dec^ proc_build? proc_include?; +proc_dec +@init { + //set up the symbol table + void** proc = tcalloc(4, sizeof(void*)); + ASSOC_ARRAY* places; + ASSOC_ARRAY* trans; + + //do you want to enter in (much less keep track of) more place names? + places = newAssocArray(32); + trans = newAssocArray(32); + //this process has not been defined yet, only declared + $proc_declarations::procObj->type = false; + + proc[kNAME] = NULL; + //processes will be freed by the specs structure + proc[kPROC] = $proc_declarations::procObj; + proc[kPLACES] = places; + proc[kTRANS] = trans; +} + : (EXTERN { + $proc_declarations::procObj->type = true; + })? PROCESS ID { + char* name; + name = (char*) $ID.text->chars; + proc[kNAME] = name; + $proc_declarations::procObj->name = tcalloc(strlen(name)+1, sizeof(char)); + strcpy($proc_declarations::procObj->name, name); + //the threads will free these lists + processes->add(processes, (char*) name, proc, ANTLR3_FUNC_PTR(free_proc_list)); + } SEMICOLON -> ^(ID EXTERN?); +proc_build + : BUILD CODE_BLOCK { + char* tmp; + tmp = (char*) $CODE_BLOCK.text->chars; + $proc_declarations::procObj->build = tcalloc(strlen(tmp)+1, sizeof(char)); + strcpy($proc_declarations::procObj->build, tmp); + } SEMICOLON -> ^(BUILD CODE_BLOCK); +proc_include + : INCLUDE CODE_BLOCK { + char* tmp; + tmp = (char*) $CODE_BLOCK.text->chars; + $proc_declarations::procObj->include = tcalloc(strlen(tmp)+1, sizeof(char)); + strcpy($proc_declarations::procObj->include, tmp); + } SEMICOLON -> ^(INCLUDE CODE_BLOCK); +//------------------- +proc_definitions +scope { + char* name; + bool external; + ASSOC_ARRAY* places; + ASSOC_ARRAY* trans; +} + : def_start^ places! trans! trans_defs* select_functions* nondeterm?; +def_start +@init { + void** list; +} + : ID { + process* proc; + $proc_definitions::name = (char*) $ID.text->chars; + list = (void**) processes->get(processes, $proc_definitions::name); + if(list == NULL) { + fprintf(stderr, "ERROR: You didn't declare a process type \%s...?\n", (char*) $ID.text->chars); + FAIL_AT($ID); + } + proc = (process*) list[kPROC]; + //used to signal that the process has been defined + proc->start = true; + $proc_definitions::external = (bool) proc->type; + $proc_definitions::places = (ASSOC_ARRAY*) list[kPLACES]; + $proc_definitions::trans = (ASSOC_ARRAY*) list[kTRANS]; + } PNDEF SEMICOLON? -> ID; +places + : PLACES (ID { + addPlace($proc_definitions::places, (char*)$ID.text->chars); + })+ SEMICOLON -> ^(PLACES ID+); +trans + : TRANS (ID { + if(NULL != $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { + fprintf(stderr, "ERROR: The place and transition \%s have the same name in process \%s\n", $ID.text->chars, $proc_definitions::name); + FAIL_AT($ID); + } + addTrans($proc_definitions::trans, (char*)$ID.text->chars); + })+ SEMICOLON -> ^(TRANS ID+); +trans_defs + : ( extern_trans_def { + //this could be a gated semantic predicate, but my error handling is more helpful + if(!$proc_definitions::external) { + fprintf(stderr, "ERROR: Process \%s looks like an extern process, but you didn't declare it that way...?\n", $proc_definitions::name); + FAIL_AT($extern_trans_def.start); + } + } + | trans_def { + if($proc_definitions::external) { + fprintf(stderr, "ERROR: Process \%s is extern, but you're declaring everything here...?\n", $proc_definitions::name); + FAIL_AT($trans_def.start); + } + }) SEMICOLON!; +extern_trans_def + : (MULT p=ID { + if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $p.text->chars)) { + fprintf(stderr, "WARNING: You didn't declare a place \%s in process \%s...\n", $p.text->chars, $proc_definitions::name); + WARN_AT($p); + addPlace($proc_definitions::places, $p.text->chars); + } + } ':' (t+=ID { + if(NULL == $proc_definitions::trans->get($proc_definitions::trans, (char*) t->getText(t)->chars)) { + fprintf(stderr, "WARNING: You didn't declare a transition \%s in process \%s...\n", t->getText(t)->chars, $proc_definitions::name); + WARN_AT(t); + addTrans($proc_definitions::trans, t->getText(t)->chars); + } + })+) -> ^(FROM[$p, $p.text->chars] $t+) + | (p=ID { + if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $p.text->chars)) { + fprintf(stderr, "WARNING: You didn't declare a place \%s in process \%s...\n", $p.text->chars, $proc_definitions::name); + WARN_AT($p); + addPlace($proc_definitions::places, $p.text->chars); + } + } '*:' (t+=ID { + if(NULL == $proc_definitions::trans->get($proc_definitions::trans, (char*) t->getText(t)->chars)) { + fprintf(stderr, "WARNING: You didn't declare a transition \%s in process \%s...\n", t->getText(t)->chars, $proc_definitions::name); + WARN_AT(t); + addTrans($proc_definitions::trans, t->getText(t)->chars); + } + })+) -> ^(TO[$p, $p.text->chars] $t+); +trans_def +@init { + pANTLR3_COMMON_TOKEN tran = NULL; + pANTLR3_COMMON_TOKEN place = NULL; +} + : (ID { + if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { + fprintf(stderr, "WARNING: You didn't declare a place \%s in process \%s...\n", $ID.text->chars, $proc_definitions::name); + WARN_AT($ID); + //silly user! We'll try to help them out here... + addPlace($proc_definitions::places, $ID.text->chars); + } + } CODE CODE_BLOCK -> ^(ID CODE_BLOCK)) + | (start='(' items+=ID (',' items+=ID)+ ')' { + //one of the first two of these ID's needs to be a transition + char* text; + int i; + if($proc_definitions::places->get($proc_definitions::places, GET_TEXT($items, 0)) != NULL) { + //this is the start place, we'll deal with it later + place = GET_TOKEN($items, 0); + $items->remove($items, 0); + } + pANTLR3_COMMON_TOKEN tmp; + for(i = 0; i < $items->size($items); i++) { + tmp = GET_TOKEN($items, i); + text = (char*) tmp->getText(tmp)->chars; + if(NULL != $proc_definitions::trans->get($proc_definitions::trans, text)) { + $items->remove($items, i); + tran = tmp; + } else if(NULL == $proc_definitions::places->get($proc_definitions::places, text)) { + fprintf(stderr, "WARNING: Attempted to reference \%s in process \%s. Assuming it's a place...\n", text, $proc_definitions::name); + WARN_AT(tmp); + addPlace($proc_definitions::places, text); + } + } + if(tran == NULL) { + fprintf(stderr, "ERROR: You declared a transition arc without a transition...?\n"); + FAIL_AT(GET_TOKEN($items, 0)); + //we need this transition to create the AST tokens. + if(place != NULL) { + tran = place; + } else { + tran = GET_TOKEN($items, 0); //we're guaranteed at least one... + } + } + } (DOT CODE_BLOCK)? -> {place != NULL}? ^(ID[tran, tran->getText(tran)->chars] PLACE[place, place->getText(place)->chars] $items* CODE_BLOCK?) + -> ^(ID[tran, tran->getText(tran)->chars] $items+ CODE_BLOCK?)); +select_functions + : SELECT_DEF ID { + if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { + fprintf(stderr, "ERROR: You tried to add a select function to a place \%s that is not declared in process \%s.", $ID.text->chars, $proc_definitions::name); + fprintf(stderr, " I have no idea what you are trying to do here...?\n"); + FAIL_AT($ID); + } + } DOT CODE_BLOCK SEMICOLON -> ^(SELECT_DEF ID CODE_BLOCK); +nondeterm + : text='nondeterministic places: ' (ID { + if(NULL == $proc_definitions::places->get($proc_definitions::places, (char*) $ID.text->chars)) { + fprintf(stderr, "WARNING: You declared the place \%s as nondeterministic, but this place has never been mentioned before in the", $ID.text->chars); + fprintf(stderr, " process \%s. I don't think you meant to do this, but I'll humor you...\n", $proc_definitions::name); + WARN_AT($ID); + addPlace($proc_definitions::places, $ID.text->chars); + } + })+ SEMICOLON -> ^($text ID+); +//------------------- +//We don't accept new places or transitions after this point. From now on, those are errors. +//------------------- +proc_instantiations + : (proc_init | sync_def | proc_start) SEMICOLON!; +proc_init + : ID! proc_init_helper[(char*) $ID.text->chars]+; + +proc_init_helper[char* proc] +@init { + void** list; + ASSOC_ARRAY* places; +} + : ID { + if(0 == strcasecmp((char*) $ID.text->chars, (char*) "global")) { + fprintf(stderr, "ERROR: Sorry, you cannot name a thread \"\%s\".\n", $ID.text->chars); + FAIL_AT($ID); + } + list = copy_list((void**) processes->get(processes, $proc)); + if(list == NULL) { + fprintf(stderr, "ERROR: You didn't declare a process type \%s...?\n", $proc); + FAIL_AT($proc); + } + places = (ASSOC_ARRAY*) list[kPLACES]; + //when processes gets cleaned up by the ANTLR libraries, this list pointer will get + //deallocated. Really, it will. Don't try to free it here, because you can't free memory twice + threads->add(threads, (char*) $ID.text->chars, list, NULL); + } ('(' ids+=numbered_ID[places, $ID.text] (',' ids+=numbered_ID[places, $ID.text])* ')')? -> ^(ID $ids*); + +sync_def + : SYNC_TOK (group_elements { + int size; + char* text1; + char* text2; + void** list; + ASSOC_ARRAY* trans; + + size = $group_elements.ret->size($group_elements.ret); + text1 = GET_TEXT($group_elements.ret, 0); + if(size == 1) { + fprintf(stderr, "ERROR: You tried to sync \%s, but that is not a fully qualified transition name...?\n", text1); + FAIL_AT($SYNC_TOK); + } + + list = (void**) threads->get(threads, text1); + if(list == NULL) { + fprintf(stderr, "ERROR: You did not declare a thread named \%s...?\n", text1); + FAIL_AT($SYNC_TOK); + } + text2 = GET_TEXT($group_elements.ret, 1); + trans = (ASSOC_ARRAY*) list[kTRANS]; + if(NULL == trans->get(trans, text2)) { + fprintf(stderr, "ERROR: You did not declare a transition \%s in process \%s\n", text2, (char*) list[kNAME]); + FAIL_AT($SYNC_TOK); + } + })+ -> ^(SYNC_TOK group_elements+); +proc_start + : START^ (ID { + if(NULL == threads->get(threads, (char*) $ID.text->chars)) { + fprintf(stderr, "ERROR: You are attempting to start an undeclared thread \%s...?\n", $ID.text->chars); + FAIL_AT($ID); + } + })+; +numbered_ID[ASSOC_ARRAY* places, pANTLR3_STRING name] + : ID { + if(NULL == places->get(places, (char*) $ID.text->chars)) { + fprintf(stderr, "ERROR: You tried to start the thread \%s at an undefined place \%s...?\n", name->chars, $ID.text->chars); + FAIL_AT($ID); + } + } (':'INT)? -> ^(ID INT?); +//------------------- +constraints +scope { + char* procName; + char* name; + ASSOC_ARRAY* places; + ASSOC_ARRAY* trans; +} +@init { + $constraints::procName = NULL; + $constraints::name = NULL; + $constraints::places = NULL; + $constraints::trans = NULL; +} + : constraint_block^ ((eq SEMICOLON!)|live_def|uncontrol|unobserve)*; +constraint_block + : ID { + $constraints::name = (char*) $ID.text->chars; + void** thread = (void**) threads->get(threads, $constraints::name); + bool tmp = 0 != strcasecmp($constraints::name, (char*) "global"); + if(NULL == thread && tmp) { + fprintf(stderr, "ERROR: You did not declare a thread named \%s...?\n", $constraints::name); + FAIL_AT($ID); + } + if(tmp) { + $constraints::procName = (char*) thread[kNAME]; + $constraints::places = (ASSOC_ARRAY*) thread[kPLACES]; + $constraints::trans = (ASSOC_ARRAY*) thread[kTRANS]; + } + } CONSTRAINTS SEMICOLON? -> ^(ID); +eq + : relationalExpression ((AND_OP|OR_OP)^ relationalExpression)?; +relationalExpression + : additiveExpression (EQ_OP^ additiveExpression)*; +additiveExpression + : primary ((PLUS|MINUS)^ primary)*; +primary + : '('! eq ')'! + | MINUS '(' additiveExpression ')' -> ^(SUB[$MINUS, "-"] additiveExpression) + | group_elements { + if($constraints::places != NULL) { + //I'm assuming that threads can't reference one another for internal constraints + if($group_elements.ret->size($group_elements.ret) == 1) { //simple reference + if(NULL == $constraints::places->get($constraints::places, GET_TEXT($group_elements.ret, 0))) { + if(NULL == $constraints::trans->get($constraints::trans, GET_TEXT($group_elements.ret, 0))) { + fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 0), $constraints::procName); + FAIL_AT(GET_TOKEN($group_elements.ret, 0)); + } + } + } else { //special type of transition check + if(strcasecmp(GET_TEXT($group_elements.ret, 0), "q") != 0) { + fprintf(stderr, "ERROR: You specified an invalid transition subtype \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 0), $constraints::procName); + FAIL_AT(GET_TOKEN($group_elements.ret, 0)); + } + //if it's special, it must be a transition + if(NULL == $constraints::trans->get($constraints::trans, GET_TEXT($group_elements.ret, 1))) { + fprintf(stderr, "ERROR: You did not declare a transition \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 1), $constraints::procName); + FAIL_AT(GET_TOKEN($group_elements.ret, 1)); + } + } + } else { //global + void** list; + char* name; + ASSOC_ARRAY* places; + ASSOC_ARRAY* trans; + if($group_elements.ret->size($group_elements.ret) == 1) { + fprintf(stderr, "ERROR: Attempting to use an unqualified reference to \%s in global constraints...?\n", GET_TEXT($group_elements.ret, 0)); + FAIL_AT(GET_TOKEN($group_elements.ret, 0)); + } + + if($group_elements.ret->size($group_elements.ret) == 2) { + list = (void**) threads->get(threads, GET_TEXT($group_elements.ret, 0)); + if(list == NULL) { + fprintf(stderr, "ERROR: You did not define a thread \%s...?\n", GET_TEXT($group_elements.ret, 0)); + FAIL_AT(GET_TOKEN($group_elements.ret, 0)); + } + name = (char*) list[kNAME]; + places = (ASSOC_ARRAY*) list[kPLACES]; + trans = (ASSOC_ARRAY*) list[kTRANS]; + if(NULL == places->get(places, GET_TEXT($group_elements.ret, 1))) { + if(NULL == trans->get(trans, GET_TEXT($group_elements.ret, 1))) { + fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s...?\n", GET_TEXT($group_elements.ret, 1), name); + FAIL_AT(GET_TOKEN($group_elements.ret, 0)); + } + } + } else { //special transition check + list = (void**) threads->get(threads, GET_TEXT($group_elements.ret, 1)); + if(list == NULL) { + fprintf(stderr, "ERROR: You did not define a thread \%s...?\n", GET_TEXT($group_elements.ret, 1)); + FAIL_AT(GET_TOKEN($group_elements.ret, 1)); + } + name = (char*) list[kNAME]; + trans = (ASSOC_ARRAY*) list[kTRANS]; + if(NULL == trans->get(trans, GET_TEXT($group_elements.ret, 2))) { + fprintf(stderr, "ERROR: You did not declare a transition \%s in thread \%s...?\n", GET_TEXT($group_elements.ret, 2), name); + FAIL_AT(GET_TOKEN($group_elements.ret, 0)); + } + } + } + } + | number (MULT^ primary)?; +live_def + : LIVE { + if($constraints::procName == NULL) { + fprintf(stderr, "ERROR: The \"live\" keyword is not valid in a global context.\n"); + FAIL_AT($LIVE); + } + } ( + ALL (MINUS id1=ID { + if(NULL == $constraints::places->get($constraints::places, (char*) $id1.text->chars)) { + if(NULL == $constraints::trans->get($constraints::trans, (char*) $id1.text->chars)) { + fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $id1.text->chars, $constraints::procName); + FAIL_AT($id1); + } + } + })* -> ^(LIVE ALL ID*) + | (id2=ID { + if(NULL == $constraints::places->get($constraints::places, (char*) $id2.text->chars)) { + if(NULL == $constraints::trans->get($constraints::trans, (char*) $id2.text->chars)) { + fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $id2.text->chars, $constraints::procName); + FAIL_AT($id2); + } + } + })+ -> ^(LIVE ID+) + ) SEMICOLON; +uncontrol + : UNCONTROL { + if($constraints::procName == NULL) { + fprintf(stderr, "ERROR: The \"uncontrollable\" keyword is not valid in a global context.\n"); + FAIL_AT($UNCONTROL); + } + } (ID { + if(NULL == $constraints::places->get($constraints::places, (char*) $ID.text->chars)) { + if(NULL == $constraints::trans->get($constraints::trans, (char*) $ID.text->chars)) { + fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $ID.text->chars, $constraints::procName); + FAIL_AT($ID); + } + } + })+ SEMICOLON -> ^(UNCONTROL ID+); +unobserve + : UNOBSERVE { + if($constraints::procName == NULL) { + fprintf(stderr, "ERROR: The \"unobservable\" keyword is not valid in a global context.\n"); + FAIL_AT($UNOBSERVE); + } + } (ID { + if(NULL == $constraints::places->get($constraints::places, (char*) $ID.text->chars)) { + if(NULL == $constraints::trans->get($constraints::trans, (char*) $ID.text->chars)) { + fprintf(stderr, "ERROR: You did not declare a place or transition \%s in process \%s\n", $ID.text->chars, $constraints::procName); + FAIL_AT($ID); + } + } + })+ SEMICOLON -> ^(UNOBSERVE ID+); +//------------------- +other_commands + : print; +print + : PRINT ID 'to' group_elements -> ^(PRINT ID group_elements); + +number + : MINUS^? INT; +group_elements returns [pANTLR3_VECTOR ret] + : idList+=ID (DOT idList+=ID)* {$ret = $idList;} -> ^(GROUP ID+); + +//------------------------------------------------------- + +EXTERN + : 'extern'; +PROCESS + : 'process' 'type'?; +BUILD + : 'build' ':'; +INCLUDE + : 'include' ':'; + +PNDEF + : '.PN:'; +PLACES + : 'places' ':'; +TRANS + : 'trans' 'itions'? ':'; +CODE + : '.code:'; +SELECT_DEF + : 'select function'; + +SYNC_TOK + : 'sync'; +START + : 'start'; + +CONSTRAINTS + : '.constraints:'; +AND_OP + : '&&'|'and'|'AND'; +OR_OP + : '||'|'or'|'OR'; +EQ_OP + : '<'|'<='|'>='|'>';//'='|'!='| +MULT + : '*'; +LIVE + : 'live:'; +ALL : 'all'|'All'|'ALL'; +UNCONTROL + : 'uncontrollable: '; +UNOBSERVE + : 'unobservable: '; + +PRINT + : 'print'; + +//inspiration was drawn from ANTLR's implementation of code blocks, and the functionality should be +//equivalent. However, ANTLR's native implementation utterly failed to work. This works. +CODE_BLOCK //This takes care of nested blocks and close '}' in strings. Comments are NOT handled. + : '{' ( CODE_BLOCK | STRING | ~('{'|'}'|'\"'|'\'') )* '}'; +STRING +options { greedy=false; } + : '\'' (CHAR_ESC|~('\\'|'\''))* '\'' + | '\"' (CHAR_ESC|~('\\'|'\"'))* '\"'; +CHAR_ESC + : '\\\'' + | '\\\"' + | '\\' ~('\''|'\"'); + +DOT + : '.'; +PLUS + : '+'; +MINUS + : '-'; +INT + : '0'..'9'+ ; +ID + : ('A'..'Z'|'a'..'z') ('A'..'Z'|'a'..'z'|'0'..'9'|'_')*; +//newline endings are complicated. See Python example code. I'll get them right eventually, +//but it's just not worth it right now. I'm using ';' endings for development. +SEMICOLON + : ';'+; //('\r'?'\n')+; + +//we don't care about white space +WS //see comment on END + : (' '|'\t'|'\r'|'\n')+ {$channel=HIDDEN;}; +//define c-style comments +COMMENT //see comment on END + : '//' .* '\n' {$channel=HIDDEN;}; +BLOCK_COMMENT +options { greedy=false; } + : '/*' .* '*/' {$channel=HIDDEN;}; Modified: old_versions/2011/translator/pnscriptParser.c =================================================================== --- old_versions/2011/translator/pnscriptParser.c 2011-07-28 19:40:14 UTC (rev 259) +++ old_versions/2011/translator/pnscriptParser.c 2011-07-28 21:14:17 UTC (rev 260) @@ -1,8413 +1,8420 @@ -/** \file - * This C source file was generated by $ANTLR version 3.1.2 - * - * - From the grammar source file : /Users/bion/projects/iordache/translator/pnscript.g - * - On : 2009-07-08 15:14:42 - * - for the parser : pnscriptParserParser * - * Editing it, at least manually, is not wise. - * - * C language generator and runtime by Jim Idle, jimi|hereisanat|idle|dotgoeshere|ws. - * - * -*/ -// [The "BSD licence"] -// Copyright (c) 2005-2009 Jim Idle, Temporal Wave LLC -// http://www.temporal-wave.com -// http://www.linkedin.com/in/jimidle -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions -// are met: -// 1. Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright -// notice, this list of conditions and the following disclaimer in the -// documentation and/or other materials provided with the distribution. -// 3. The name of the author may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -/* ============================================================================= - * This is what the grammar programmer asked us to put at the top of every file. - */ - - #include <stdbool.h> - #include <string.h> - #include "pns.h" - #include "datastructures.h" - - #define GET_TOKEN(list, num) (pANTLR3_COMMON_TOKEN) list->get(list, num) - //retrieves the text of the numth token in the list - #define GET_TEXT(list, num) (char*) (GET_TOKEN(list, num))->getText((GET_TOKEN(list, num)))->chars - #define WARN_AT(token) showContext(ctx, token) - #define FAIL_AT(token) fprintf(stderr, "Parser Failed: "); showContext(ctx, token); exitAtEnd = true; - - //don't ask... I have no idea, but you get bus errors otherwise - //there's got to be a bug in the hash table backing this list. - #define kNAME 0 - #define kPROC 1 - #define kPLACES 2 - #define kTRANS 3 - -/* End of Header action. - * ============================================================================= - */ -/* ----------------------------------------- - * Include the ANTLR3 generated header file. - */ -#include "pnscriptParser.h" -/* ----------------------------------------- */ - - - - - -/* MACROS that hide the C interface implementations from the - * generated code, which makes it a little more understandable to the human eye. - * I am very much against using C pre-processor macros for function calls and bits - * of code as you cannot see what is happening when single stepping in debuggers - * and so on. The exception (in my book at least) is for generated code, where you are - * not maintaining it, but may wish to read and understand it. If you single step it, you know that input() - * hides some indirect calls, but is always referring to the input stream. This is - * probably more readable than ctx->input->istream->input(snarfle0->blarg) and allows me to rejig - * the runtime interfaces without changing the generated code too often, without - * confusing the reader of the generated output, who may not wish to know the gory - * details of the interface inheritance. - */ - -#define CTX ctx - -/* Aids in accessing scopes for grammar programmers - */ -#undef SCOPE_TYPE -#undef SCOPE_STACK -#undef SCOPE_TOP -#define SCOPE_TYPE(scope) ppnscriptParser_##scope##_SCOPE -#define SCOPE_STACK(scope) ppnscriptParser_##scope##Stack -#define SCOPE_TOP(scope) ctx->ppnscriptParser_##scope##Top -#define SCOPE_SIZE(scope) (ctx->SCOPE_STACK(scope)->size(ctx->SCOPE_STACK(scope))) -#define SCOPE_INSTANCE(scope, i) (ctx->SCOPE_STACK(scope)->get(ctx->SCOPE_STACK(scope),i)) - -/* Macros for accessing things in the parser - */ - -#undef PARSER -#undef RECOGNIZER -#undef HAVEPARSEDRULE -#undef MEMOIZE -#undef INPUT -#undef STRSTREAM -#undef HASEXCEPTION -#undef EXCEPTION -#undef MATCHT -#undef MATCHANYT -#undef FOLLOWSTACK -#undef FOLLOWPUSH -#undef FOLLOWPOP -#undef PRECOVER -#undef PREPORTERROR -#undef LA -#undef LT -#undef CONSTRUCTEX -#undef CONSUME -#undef MARK -#undef REWIND -#undef REWINDLAST -#undef PERRORRECOVERY -#undef HASFAILED -#undef FAILEDFLAG -#undef RECOVERFROMMISMATCHEDSET -#undef RECOVERFROMMISMATCHEDELEMENT -#undef INDEX -#undef ADAPTOR -#undef SEEK -#undef RULEMEMO -#undef DBG - -#define PARSER ctx->pParser -#define RECOGNIZER PARSER->rec -#define PSRSTATE RECOGNIZER->state -#define HAVEPARSEDRULE(r) RECOGNIZER->alreadyParsedRule(RECOGNIZER, r) -#define MEMOIZE(ri,si) RECOGNIZER->memoize(RECOGNIZER, ri, si) -#define INPUT PARSER->tstream -#define STRSTREAM INPUT -#define ISTREAM INPUT->istream -#define INDEX() ISTREAM->index(INPUT->istream) -#define HASEXCEPTION() (PSRSTATE->error == ANTLR3_TRUE) -#define EXCEPTION PSRSTATE->exception -#define MATCHT(t, fs) RECOGNIZER->match(RECOGNIZER, t, fs) -#define MATCHANYT() RECOGNIZER->matchAny(RECOGNIZER) -#define FOLLOWSTACK PSRSTATE->following -#define FOLLOWPUSH(x) FOLLOWSTACK->push(FOLLOWSTACK, ((void *)(&(x))), NULL) -#define FOLLOWPOP() FOLLOWSTACK->pop(FOLLOWSTACK) -#define PRECOVER() RECOGNIZER->recover(RECOGNIZER) -#define PREPORTERROR() RECOGNIZER->reportError(RECOGNIZER) -#define LA(n) INPUT->istream->_LA(ISTREAM, n) -#define LT(n) INPUT->_LT(INPUT, n) -#define CONSTRUCTEX() RECOGNIZER->exConstruct(RECOGNIZER) -#define CONSUME() ISTREAM->consume(ISTREAM) -#define MARK() ISTREAM->mark(ISTREAM) -#define REWIND(m) ISTREAM->rewind(ISTREAM, m) -#define REWINDLAST() ISTREAM->rewindLast(ISTREAM) -#define SEEK(n) ISTREAM->seek(ISTREAM, n) -#define PERRORRECOVERY PSRSTATE->errorRecovery -#define FAILEDFLAG PSRSTATE->failed -#define HASFAILED() (FAILEDFLAG == ANTLR3_TRUE) -#define BACKTRACKING PSRSTATE->backtracking -#define RECOVERFROMMISMATCHEDSET(s) RECOGNIZER->recoverFromMismatchedSet(RECOGNIZER, s) -#define RECOVERFROMMISMATCHEDELEMENT(e) RECOGNIZER->recoverFromMismatchedElement(RECOGNIZER, s) -#define ADAPTOR ctx->adaptor -#define RULEMEMO PSRSTATE->ruleMemo -#define DBG RECOGNIZER->debugger - -#define TOKTEXT(tok, txt) tok, (pANTLR3_UINT8)txt - -/* The 4 tokens defined below may well clash with your own #defines or token types. If so - * then for the present you must use different names for your defines as these are hard coded - * in the code generator. It would be better not to use such names internally, and maybe - * we can change this in a forthcoming release. I deliberately do not #undef these - * here as this will at least give you a redefined error somewhere if they clash. - */ -#define UP ANTLR3_TOKEN_UP -#define DOWN ANTLR3_TOKEN_DOWN -#define EOR ANTLR3_TOKEN_EOR -#define INVALID ANTLR3_TOKEN_INVALID - - -/* ============================================================================= - * Functions to create and destroy scopes. First come the rule scopes, followed - * by the global declared scopes. - */ - -/* ruleAttributeScopeFuncDecl(scope) - */ -/* ----------------------------------------------------------------------------- - * Function declarations for creating a pnscriptParser_proc_declarations scope set - */ -static ppnscriptParser_proc_declarations_SCOPE ppnscriptParser_proc_declarationsPush(ppnscriptParser ctx); -static void ANTLR3_CDECL proc_declarationsFree(ppnscriptParser_proc_declarations_SCOPE scope); -/* ----------------------------------------------------------------------------- */ - -/* ruleAttributeScopeFuncs(scope) - */ -/* attributeFuncs(scope) - */ - -static void ANTLR3_CDECL proc_declarationsFree(ppnscriptParser_proc_declarations_SCOPE scope) -{ - ANTLR3_FREE(scope); -} - -/** \brief Allocate initial memory for a pnscriptParser proc_declarations scope variable stack entry and - * add it to the top of the stack. - * - * \remark - * By default the structure is freed with ANTLR_FREE(), but you can use the - * the \@init action to install a pointer to a custom free() routine by - * adding the code: - * \code - * ctx->ppnscriptParser_proc_declarationsTop->free = myroutine; - * \endcode - * - * With lots of comments of course! The routine should be declared in - * \@members { } as: - * \code - * void ANTLR3_CDECL myfunc( ppnscriptParser_proc_declarations_SCOPE ptr). - * \endcode - * - * It should perform any custom freeing stuff that you need (call ANTLR_FREE3, not free() - * NB: It should not free the pointer it is given, which is the scope stack entry itself - * and will be freed by the function that calls your custom free routine. - * - */ -static ppnscriptParser_proc_declarations_SCOPE -ppnscriptParser_proc_declarationsPush(ppnscriptParser ctx) -{ - /* Pointer used to create a new set of attributes - */ - ppnscriptParser_proc_declarations_SCOPE newAttributes; - - /* Allocate the memory for a new structure if we need one. - */ - if (ctx->ppnscriptParser_proc_declarationsStack->size(ctx->ppnscriptParser_proc_declarationsStack) > ctx->ppnscriptParser_proc_declarationsStack_limit) - { - // The current limit value was less than the number of scopes available on the stack so - // we can just reuse one. Our limit tracks the stack count, so the index of the entry we want - // is one less than that, or conveniently, the current value of limit. - // - newAttributes = ctx->ppnscriptParser_proc_declarationsStack->get(ctx->ppnscriptParser_proc_declarationsStack, ctx->ppnscriptParser_proc_declarationsStack_limit); - } - else - { - // Need a new allocation - // - newAttributes = (ppnscriptParser_proc_declarations_SCOPE) ANTLR3_MALLOC(sizeof(pnscriptParser_proc_declarations_SCOPE)); - if (newAttributes != NULL) - { - /* Standard ANTLR3 library implementation - */ - ctx->ppnscriptParser_proc_declarationsStack->push(ctx->ppnscriptParser_proc_declarationsStack, newAttributes, (void (*)(void *))proc_declarationsFree); - } - } - - // Blank out any previous free pointer, the user might or might install a new one. - // - newAttributes->free = NULL; - - // Indicate the posi... [truncated message content] |
From: <mio...@us...> - 2011-07-28 19:40:20
|
Revision: 259 http://pntool.svn.sourceforge.net/pntool/?rev=259&view=rev Author: miordache Date: 2011-07-28 19:40:14 +0000 (Thu, 28 Jul 2011) Log Message: ----------- Modified Paths: -------------- old_versions/2011/newcodegen/SupervisorTemplate.c old_versions/2011/newcodegen/supervisorCompiler.c present_version/newcodegen/SupervisorTemplate.c present_version/newcodegen/supervisorCompiler.c Modified: old_versions/2011/newcodegen/SupervisorTemplate.c =================================================================== --- old_versions/2011/newcodegen/SupervisorTemplate.c 2011-07-28 16:39:24 UTC (rev 258) +++ old_versions/2011/newcodegen/SupervisorTemplate.c 2011-07-28 19:40:14 UTC (rev 259) @@ -786,8 +786,8 @@ } if( ! ___cpid) { // code execuded by child process ___upd_comm_param(0, ___pr, ___where); - execlp(___pname[___type], ___pname[___type], ___com, 0); - debugInfo("exclp was unable to start \"%s %s\"", ___pname[___type], ___com); + execl(___pname[___type], ___pname[___type], ___com, (char*)0); + debugInfo("excl was unable to start \"%s %s\"", ___pname[___type], ___com); ___ms.type = ___EXIT_NOTIFICATION; ___ms.id = ___pr; ___send_to_supervisor(&___ms, sizeof(___ms), ___pr); Modified: old_versions/2011/newcodegen/supervisorCompiler.c =================================================================== --- old_versions/2011/newcodegen/supervisorCompiler.c 2011-07-28 16:39:24 UTC (rev 258) +++ old_versions/2011/newcodegen/supervisorCompiler.c 2011-07-28 19:40:14 UTC (rev 259) @@ -840,7 +840,7 @@ if(prs[i]->name) if(strlen(prs[i]->name)) { if( ! prs[i]->thread ) - ins = FSInsert(ins, " \"%s.exe\"", prs[i]->name); + ins = FSInsert(ins, " \"./%s.exe\"", prs[i]->name); else ins = SInsert(" 0", ins); if(i == nprs - 1) @@ -949,7 +949,7 @@ #ifndef ___USE_PTHREAD_LIB fprintf(f, "\n\t$(COMPILER) -o %s.exe %s.c", sn, sn); #else - fprintf(f, "\n\t$(COMPILER) -lpthreads -o %s.exe %s.c", sn, sn); + fprintf(f, "\n\t$(COMPILER) -lpthread -o %s.exe %s.c", sn, sn); #endif for(i = 0; i < n; i++) if(thr[i]) @@ -985,7 +985,7 @@ #ifndef ___USE_PTHREAD_LIB fprintf(f, "\n\t$(COMPILER) -o %s.exe %s.c", prs[i]->name, prs[i]->name); #else - fprintf(f, "\n\t$(COMPILER) -lpthreads -o %s.exe %s.c", prs[i]->name, prs[i]->name); + fprintf(f, "\n\t$(COMPILER) -lpthread -o %s.exe %s.c", prs[i]->name, prs[i]->name); #endif } } Modified: present_version/newcodegen/SupervisorTemplate.c =================================================================== --- present_version/newcodegen/SupervisorTemplate.c 2011-07-28 16:39:24 UTC (rev 258) +++ present_version/newcodegen/SupervisorTemplate.c 2011-07-28 19:40:14 UTC (rev 259) @@ -786,8 +786,8 @@ } if( ! ___cpid) { // code execuded by child process ___upd_comm_param(0, ___pr, ___where); - execlp(___pname[___type], ___pname[___type], ___com, 0); - debugInfo("exclp was unable to start \"%s %s\"", ___pname[___type], ___com); + execl(___pname[___type], ___pname[___type], ___com, (char*)0); + debugInfo("excl was unable to start \"%s %s\"", ___pname[___type], ___com); ___ms.type = ___EXIT_NOTIFICATION; ___ms.id = ___pr; ___send_to_supervisor(&___ms, sizeof(___ms), ___pr); Modified: present_version/newcodegen/supervisorCompiler.c =================================================================== --- present_version/newcodegen/supervisorCompiler.c 2011-07-28 16:39:24 UTC (rev 258) +++ present_version/newcodegen/supervisorCompiler.c 2011-07-28 19:40:14 UTC (rev 259) @@ -840,7 +840,7 @@ if(prs[i]->name) if(strlen(prs[i]->name)) { if( ! prs[i]->thread ) - ins = FSInsert(ins, " \"%s.exe\"", prs[i]->name); + ins = FSInsert(ins, " \"./%s.exe\"", prs[i]->name); else ins = SInsert(" 0", ins); if(i == nprs - 1) This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-28 16:39:31
|
Revision: 258 http://pntool.svn.sourceforge.net/pntool/?rev=258&view=rev Author: miordache Date: 2011-07-28 16:39:24 +0000 (Thu, 28 Jul 2011) Log Message: ----------- more examples Modified Paths: -------------- present_version/examples/README Added Paths: ----------- present_version/examples/test2.sp present_version/examples/test3a.sp present_version/examples/test3c.sp present_version/examples/test3d.sp Modified: present_version/examples/README =================================================================== --- present_version/examples/README 2011-07-28 15:06:37 UTC (rev 257) +++ present_version/examples/README 2011-07-28 16:39:24 UTC (rev 258) @@ -2,3 +2,17 @@ inteq.sp: a simple example illustrating how to write concurrent program specifications. It specifies a concurrent program for finding integer solutions to the equation w^2 = x^2 + y^2 + z^2. + +The following files were converted to the present specification format by Micah Martin and Basil Hall. + +test2.sp: This is a test file intended to check the code generation module. It generates a process that can creates periodically a thread until it terminates. There are synchronizations between the process and the threads it generates. + + + +test3: A dining philosopher example. + +test3a.sp: Tests that the deadlock prevention function works fine when no deadlock is possible. Only one philosopher with two resources. + +test3c.sp: A test involving 5 philosophers. + +test3d.sp: A test involving 5 philosophers. Here, the resources (chopsticks) are defined as supervisor components, not as threads. Added: present_version/examples/test2.sp =================================================================== --- present_version/examples/test2.sp (rev 0) +++ present_version/examples/test2.sp 2011-07-28 16:39:24 UTC (rev 258) @@ -0,0 +1,114 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1 { + + places: p0 p1 p2 + transitions: t0 t1 t2 t3 t4 + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + + (p0, t4, p2) + (p1, t3) + (p2, t2, p0) + (p1, t1, p2) + (p0, t0, p1) +} + +thread PN3 { + + places: p0 p1 + transitions: t0 t1 t2 + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + + (t2, p0) + (p0, t0, p1) + (p1, t1) +} + +initialize: TYPE1(p0:1) +initialize: PN3(p0:0) + +TYPE1.p0 { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +} + +TYPE1.p1 { + fprintf(stderr, "\nPN: State 1"); + delay(1); +} + +TYPE1.p2 { + fprintf(stderr, "\nPN: State 2"); + delay(1); +} + +PN3.p0 { + u++; + printf("\nPN3: State 0 u = %d", u); + delay(2); +} + +PN3.p1 { + printf("\nPN3: State 1"); + delay(2); +} + +TYPE1.include { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +} + +PN3.include { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +} + +TYPE1.build {gcc -g -o $$$.exe $$$.c } + Added: present_version/examples/test3a.sp =================================================================== --- present_version/examples/test3a.sp (rev 0) +++ present_version/examples/test3a.sp 2011-07-28 16:39:24 UTC (rev 258) @@ -0,0 +1,91 @@ +// This is a test file intended to check the code generation module + +thread ph1 { + + places: p0 p1 p2 p3 + transitions: t0 t1 t2 t3 t4 + + // t3 + // ------------|<--------------- + // | | + // ->O-->|-->O-->|-->O-->|-->O-- + // p0 t0 p1 t1 p2 t2 p3 + + (p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0) +} + +thread left { + + places: p + transitions: t0 t2 + + // --->| t2 + // p | + // t0 |--->O + // + + (p, t2); (t0, p) +} + +initialize: left(p:1) ph1(p0:1) + +live: ph1.t1 + +ph1.p0 { + u++; + fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); + fflush(0); + delay(1); +} + +ph1.p1 { + fprintf(stderr, "\nPN: State 1 (requesting right fork)"); + fflush(0); + delay(1); +} + +ph1.p2 { + fprintf(stderr, "\nPN: State 2 (requesting left fork)"); + fflush(0); + delay(1); +} + +ph1.p3 { + fprintf(stderr, "\nPN: State 3 (eat)"); + fflush(0); + delay(1); +} + +left.p { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +} + +ph1.include { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +} + +left.include { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +} + +right = left // right is a copy of the thread left + +initialize: right(p:1) //the assignment above does not copy the initial marking + +sync ph1.t1 left.t2 +sync ph1.t2 right.t2 +sync ph1.t3 left.t0 +sync ph1.t3 right.t0 Added: present_version/examples/test3c.sp =================================================================== --- present_version/examples/test3c.sp (rev 0) +++ present_version/examples/test3c.sp 2011-07-28 16:39:24 UTC (rev 258) @@ -0,0 +1,107 @@ +// This is a test file intended to check the code generation module + +thread ph1 { + + places: p0 p1 p2 p3 + transitions: t0 t1 t2 t3 t4 + + // t3 + // ------------|<--------------- + // | | + // ->O-->|-->O-->|-->O-->|-->O-- + // p0 t0 p1 t1 p2 t2 p3 + + (p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0) +} + +thread r1 { + + places: p + transitions: t0 t1 t2 t3 + + // --->| t2 + // p | + // t0 |--->O<---| t1 + // | + // --->| t3 + + (p, t2); (p, t3); (t0, p); (t1, p) +} + +initialize: r1(p:1) ph1(p0:1) + +ph1.p0 { + u++; + fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); + fflush(0); + delay(1); +} + +ph1.p1 { + fprintf(stderr, "\nPN: State 1 (requesting right fork)"); + fflush(0); + delay(1); +} + +ph1.p2 { + fprintf(stderr, "\nPN: State 2 (requesting left fork)"); + fflush(0); + delay(1); +} + +ph1.p3 { + fprintf(stderr, "\nPN: State 3 (eat)"); + fflush(0); + delay(1); +} + +r1.p { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +} + +ph1.include { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +} + +r1.include { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +} + +r2 = r1 +r3 = r1 +r4 = r1 +r5 = r1 + +ph2 = ph1 +ph3 = ph1 +ph4 = ph1 +ph5 = ph1 + + +initialize: r2(p:1) ph2(p0:1) r3(p:1) ph3(p0:1) r4(p:1) ph4(p0:1) r5(p:1) ph5(p0:1) + + +sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2 + +sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3 + +sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1 + +live: ph1.t1 +live: ph2.t1 +live: ph3.t1 +live: ph4.t1 +live: ph5.t1 Added: present_version/examples/test3d.sp =================================================================== --- present_version/examples/test3d.sp (rev 0) +++ present_version/examples/test3d.sp 2011-07-28 16:39:24 UTC (rev 258) @@ -0,0 +1,91 @@ +// This is a test file intended to check the code generation module + +thread ph1 { + + places: p0 p1 p2 p3 + transitions: t0 t1 t2 t3 t4 + + // t3 + // ------------|<--------------- + // | | + // ->O-->|-->O-->|-->O-->|-->O-- + // p0 t0 p1 t1 p2 t2 p3 + + (p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0) +} + +supervisor r1 { + + places: p + transitions: t0 t1 t2 t3 + + // --->| t2 + // p | + // t0 |--->O<---| t1 + // | + // --->| t3 + + (p, t2); (p, t3); (t0, p); (t1, p) +} + +initialize: r1(p:1) ph1(p0:1) + +ph1.p0 { + u++; + fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); + fflush(0); + delay(1); +} + +ph1.p1 { + fprintf(stderr, "\nPN: State 1 (requesting right fork)"); + fflush(0); + delay(1); +} + +ph1.p2 { + fprintf(stderr, "\nPN: State 2 (requesting left fork)"); + fflush(0); + delay(1); +} + +ph1.p3 { + fprintf(stderr, "\nPN: State 3 (eat)"); + fflush(0); + delay(1); +} + +ph1.include { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +} + + +r2 = r1 +r3 = r1 +r4 = r1 +r5 = r1 + +ph2 = ph1 +ph3 = ph1 +ph4 = ph1 +ph5 = ph1 + +initialize: r2(p:1) ph2(p0:1) r3(p:1) ph3(p0:1) r4(p:1) ph4(p0:1) r5(p:1) ph5(p0:1) + +sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2 + +sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3 + +sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1 + +live: ph1.t1 +live: ph2.t1 +live: ph3.t1 +live: ph4.t1 +live: ph5.t1 This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-28 15:06:44
|
Revision: 257 http://pntool.svn.sourceforge.net/pntool/?rev=257&view=rev Author: miordache Date: 2011-07-28 15:06:37 +0000 (Thu, 28 Jul 2011) Log Message: ----------- Modified Paths: -------------- present_version/newcodegen/supervisorCompiler.c Added Paths: ----------- present_version/Makefile Copied: present_version/Makefile (from rev 256, present_version/Makefile-linux.mak) =================================================================== --- present_version/Makefile (rev 0) +++ present_version/Makefile 2011-07-28 15:06:37 UTC (rev 257) @@ -0,0 +1,33 @@ +# This is the make file of the entire program. + + +COMPILER=gcc -g +LDFLAGS=-lm -ldl + +PNHEADERS=pnheaders +SPNBOX=spnbox +CODEGEN=newcodegen +CODEGENOBJS = $(CODEGEN) +TRANSLATOR=parser + +ct: objectfiles main_function2.o + $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ + main_function2.o $(SPNBOX)/*.a $(TRANSLATOR)/*.o $(LDFLAGS) + +objectfiles: + cd $(PNHEADERS); make + cd $(CODEGEN); make -f Makefile-linux.mak static + cd $(SPNBOX); make + cd $(TRANSLATOR); make + +main_function2.o: $(PNHEADERS)/main_function2.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function2.c -Ispnbox -I$(CODEGEN) -I$(PNHEADERS) + +clean: + rm -f main_function2.o + rm -f ct + cd $(PNHEADERS); make clean + cd $(CODEGEN); make -f Makefile-linux.mak clean + cd $(TRANSLATOR); make clean + cd $(SPNBOX); make clean + Modified: present_version/newcodegen/supervisorCompiler.c =================================================================== --- present_version/newcodegen/supervisorCompiler.c 2011-07-28 13:54:36 UTC (rev 256) +++ present_version/newcodegen/supervisorCompiler.c 2011-07-28 15:06:37 UTC (rev 257) @@ -949,7 +949,7 @@ #ifndef ___USE_PTHREAD_LIB fprintf(f, "\n\t$(COMPILER) -o %s.exe %s.c", sn, sn); #else - fprintf(f, "\n\t$(COMPILER) -lpthreads -o %s.exe %s.c", sn, sn); + fprintf(f, "\n\t$(COMPILER) -lpthread -o %s.exe %s.c", sn, sn); #endif for(i = 0; i < n; i++) if(thr[i]) @@ -985,7 +985,7 @@ #ifndef ___USE_PTHREAD_LIB fprintf(f, "\n\t$(COMPILER) -o %s.exe %s.c", prs[i]->name, prs[i]->name); #else - fprintf(f, "\n\t$(COMPILER) -lpthreads -o %s.exe %s.c", prs[i]->name, prs[i]->name); + fprintf(f, "\n\t$(COMPILER) -lpthread -o %s.exe %s.c", prs[i]->name, prs[i]->name); #endif } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-28 13:54:55
|
Revision: 256 http://pntool.svn.sourceforge.net/pntool/?rev=256&view=rev Author: miordache Date: 2011-07-28 13:54:36 +0000 (Thu, 28 Jul 2011) Log Message: ----------- reorganizing folders Added Paths: ----------- old_versions/ old_versions/2009/ old_versions/2009/LICENSE/ old_versions/2009/LICENSE/ANTLR3_LICENSE.txt old_versions/2009/LICENSE/LICENSE.txt old_versions/2009/LICENSE/README.txt old_versions/2009/Makefile09 old_versions/2009/codegen/ old_versions/2009/codegen/.gitignore old_versions/2009/codegen/Makefile old_versions/2009/codegen/README.txt old_versions/2009/codegen/build/ old_versions/2009/codegen/codegen.xcodeproj/ old_versions/2009/codegen/demo.sh old_versions/2009/codegen/deploy.sh old_versions/2009/codegen/die.sh old_versions/2009/codegen/includes.txt old_versions/2009/codegen/ptrtest.c old_versions/2009/codegen/src/ old_versions/2009/codegen/src/MakeGen.c old_versions/2009/codegen/src/MakeGen.h old_versions/2009/codegen/src/codegen.1 old_versions/2009/codegen/src/codegen.c old_versions/2009/codegen/src/codegen.h old_versions/2009/codegen/src/codegen.xcodeproj/ old_versions/2009/codegen/src/codegen.xcodeproj/drew.mode1v3 old_versions/2009/codegen/src/codegen.xcodeproj/drew.pbxuser old_versions/2009/codegen/src/codegen.xcodeproj/project.pbxproj old_versions/2009/codegen/src/main.c old_versions/2009/codegen/src/petriNetSerializer.c old_versions/2009/codegen/src/petriNetSerializer.h old_versions/2009/codegen/src/plantCompiler.c old_versions/2009/codegen/src/plantCompiler.h old_versions/2009/codegen/src/plantVariableList.txt old_versions/2009/codegen/src/supervisorCompiler.c old_versions/2009/codegen/src/supervisorCompiler.h old_versions/2009/codegen/src/supervisor_static_include.h old_versions/2009/codegen/src/text.c old_versions/2009/codegen/src/text.h old_versions/2009/codegen/supervisor_algorithm.txt old_versions/2009/codegen/test_ptrtest.txt old_versions/2009/codegen/test_supervisor.sh old_versions/2009/pnheaders/ old_versions/2009/pnheaders/Makefile old_versions/2009/pnheaders/README.txt old_versions/2009/pnheaders/general.c old_versions/2009/pnheaders/general.h old_versions/2009/pnheaders/main_function.c old_versions/2009/pnheaders/matrix.c old_versions/2009/pnheaders/matrix.h old_versions/2009/pnheaders/pnexample.c old_versions/2009/pnheaders/pns.c old_versions/2009/pnheaders/pns.h old_versions/2009/spnbox09/ old_versions/2009/spnbox09/Makefile old_versions/2009/spnbox09/MemoryManager.c old_versions/2009/spnbox09/MemoryManager.h old_versions/2009/spnbox09/actn.c old_versions/2009/spnbox09/admcon.c old_versions/2009/spnbox09/asiph.c old_versions/2009/spnbox09/avpr.c old_versions/2009/spnbox09/chkcons.c old_versions/2009/spnbox09/deallocation.c old_versions/2009/spnbox09/dp.c old_versions/2009/spnbox09/dp4.c old_versions/2009/spnbox09/extendedmatrix.c old_versions/2009/spnbox09/extendedmatrix.h old_versions/2009/spnbox09/fvpr.c old_versions/2009/spnbox09/gcdv.c old_versions/2009/spnbox09/ilpadm.c old_versions/2009/spnbox09/invar.c old_versions/2009/spnbox09/ipslv.c old_versions/2009/spnbox09/ipsolve.c old_versions/2009/spnbox09/isadm.c old_versions/2009/spnbox09/issiph.c old_versions/2009/spnbox09/linenf.c old_versions/2009/spnbox09/matrixmath.c old_versions/2009/spnbox09/matrixmath.h old_versions/2009/spnbox09/mroadm.c old_versions/2009/spnbox09/msplit.c old_versions/2009/spnbox09/nltrans.c old_versions/2009/spnbox09/pn2acpn.c old_versions/2009/spnbox09/pn2eacpn.c old_versions/2009/spnbox09/reduce.c old_versions/2009/spnbox09/spnbox.h old_versions/2009/spnbox09/supervis.c old_versions/2009/spnbox09/tactn.c old_versions/2009/spnbox09/tests/ old_versions/2009/spnbox09/tests/Makefile old_versions/2009/spnbox09/tests/StructuredIO.c old_versions/2009/spnbox09/tests/StructuredIO.h old_versions/2009/spnbox09/tests/pnexample.c old_versions/2009/spnbox09/tests/test-actn.c old_versions/2009/spnbox09/tests/test-actn.txt old_versions/2009/spnbox09/tests/test-admcon.c old_versions/2009/spnbox09/tests/test-asiph.c old_versions/2009/spnbox09/tests/test-asiph.txt old_versions/2009/spnbox09/tests/test-avpr.c old_versions/2009/spnbox09/tests/test-avpr.txt old_versions/2009/spnbox09/tests/test-dp.c old_versions/2009/spnbox09/tests/test-dp.txt old_versions/2009/spnbox09/tests/test-extendedmatrix.c old_versions/2009/spnbox09/tests/test-extendedmatrix.txt old_versions/2009/spnbox09/tests/test-fvpr.c old_versions/2009/spnbox09/tests/test-fvpr.txt old_versions/2009/spnbox09/tests/test-gcdv.c old_versions/2009/spnbox09/tests/test-gcdv.txt old_versions/2009/spnbox09/tests/test-ilpadm.c old_versions/2009/spnbox09/tests/test-ilpadm.txt old_versions/2009/spnbox09/tests/test-invar.c old_versions/2009/spnbox09/tests/test-invar.txt old_versions/2009/spnbox09/tests/test-ipslv.c old_versions/2009/spnbox09/tests/test-ipsolve.c old_versions/2009/spnbox09/tests/test-ipsolve.txt old_versions/2009/spnbox09/tests/test-isadm.c old_versions/2009/spnbox09/tests/test-isadm.txt old_versions/2009/spnbox09/tests/test-issiph.c old_versions/2009/spnbox09/tests/test-issiph.txt old_versions/2009/spnbox09/tests/test-linenf.c old_versions/2009/spnbox09/tests/test-linenf.txt old_versions/2009/spnbox09/tests/test-matrixmath.c old_versions/2009/spnbox09/tests/test-matrixmath.txt old_versions/2009/spnbox09/tests/test-mroadm.c old_versions/2009/spnbox09/tests/test-mroadm.txt old_versions/2009/spnbox09/tests/test-msplit.c old_versions/2009/spnbox09/tests/test-msplit.txt old_versions/2009/spnbox09/tests/test-nltrans.c old_versions/2009/spnbox09/tests/test-nltrans.txt old_versions/2009/spnbox09/tests/test-pn2acpn.c old_versions/2009/spnbox09/tests/test-pn2acpn.txt old_versions/2009/spnbox09/tests/test-pn2eacpn.c old_versions/2009/spnbox09/tests/test-pn2eacpn.txt old_versions/2009/spnbox09/tests/test-reduce.c old_versions/2009/spnbox09/tests/test-reduce.txt old_versions/2009/spnbox09/tests/test-supervis.c old_versions/2009/spnbox09/tests/test-supervis.txt old_versions/2009/spnbox09/tests/test-tactn.c old_versions/2009/spnbox09/tests/test-tactn.txt old_versions/2009/spnbox09/tests/test.c old_versions/2009/spnbox09/tests/test.h old_versions/2011/ old_versions/2011/LICENSE/ old_versions/2011/LICENSE/ANTLR3_LICENSE.txt old_versions/2011/LICENSE/LICENSE.txt old_versions/2011/LICENSE/README.txt old_versions/2011/Makefile old_versions/2011/doc/ old_versions/2011/doc/GettingStarted.htm old_versions/2011/doc/input2.sp old_versions/2011/examples/ old_versions/2011/examples/+README+ old_versions/2011/examples/catandmouse.sp old_versions/2011/examples/loop.sp old_versions/2011/examples/loop3.sp old_versions/2011/examples/reader.sp old_versions/2011/examples/test.sp old_versions/2011/examples/test2.sp old_versions/2011/examples/test2a.sp old_versions/2011/examples/test2b.sp old_versions/2011/examples/test2c.sp old_versions/2011/examples/test2d.sp old_versions/2011/examples/test2e.sp old_versions/2011/examples/test2f.sp old_versions/2011/examples/test2g.sp old_versions/2011/examples/test3a.sp old_versions/2011/examples/test3b.sp old_versions/2011/examples/test3c.sp old_versions/2011/examples/test3d.sp old_versions/2011/newcodegen/ old_versions/2011/newcodegen/Makefile old_versions/2011/newcodegen/Makefile-linux.mak old_versions/2011/newcodegen/ProcessTemplate.c old_versions/2011/newcodegen/SupervisorTemplate.c old_versions/2011/newcodegen/codegen.h old_versions/2011/newcodegen/compexample.c old_versions/2011/newcodegen/filltmpl.lex old_versions/2011/newcodegen/plantCompiler.c old_versions/2011/newcodegen/plantCompiler.h old_versions/2011/newcodegen/spcommon.h old_versions/2011/newcodegen/supervisorCompiler.c old_versions/2011/pnheaders/ old_versions/2011/pnheaders/Makefile old_versions/2011/pnheaders/general.c old_versions/2011/pnheaders/general.h old_versions/2011/pnheaders/insert.c old_versions/2011/pnheaders/insert.h old_versions/2011/pnheaders/main_function.c old_versions/2011/pnheaders/matrix.c old_versions/2011/pnheaders/matrix.h old_versions/2011/pnheaders/pnexample.c old_versions/2011/pnheaders/pns.c old_versions/2011/pnheaders/pns.h old_versions/2011/spnbox/ old_versions/2011/spnbox/Makefile old_versions/2011/spnbox/MemoryManager.c old_versions/2011/spnbox/MemoryManager.h old_versions/2011/spnbox/actn.c old_versions/2011/spnbox/admcon.c old_versions/2011/spnbox/asiph.c old_versions/2011/spnbox/avpr.c old_versions/2011/spnbox/chkcons.c old_versions/2011/spnbox/deallocation.c old_versions/2011/spnbox/disj2normal.c old_versions/2011/spnbox/disj2pn.c old_versions/2011/spnbox/disq2disj.c old_versions/2011/spnbox/doc/ old_versions/2011/spnbox/doc/README.txt old_versions/2011/spnbox/doc/functions.html old_versions/2011/spnbox/doc/index.html old_versions/2011/spnbox/doc/isis-2002-003.pdf old_versions/2011/spnbox/doc/support.html old_versions/2011/spnbox/doc/test.html old_versions/2011/spnbox/dp.c old_versions/2011/spnbox/dp4.c old_versions/2011/spnbox/extendedmatrix.c old_versions/2011/spnbox/extendedmatrix.h old_versions/2011/spnbox/fvpr.c old_versions/2011/spnbox/gcdv.c old_versions/2011/spnbox/ilpadm.c old_versions/2011/spnbox/invar.c old_versions/2011/spnbox/ipslv.c old_versions/2011/spnbox/ipsolve.c old_versions/2011/spnbox/isadm.c old_versions/2011/spnbox/issiph.c old_versions/2011/spnbox/linenf.c old_versions/2011/spnbox/matrixmath.c old_versions/2011/spnbox/matrixmath.h old_versions/2011/spnbox/mroadm.c old_versions/2011/spnbox/msplit.c old_versions/2011/spnbox/nltrans.c old_versions/2011/spnbox/pn2acpn.c old_versions/2011/spnbox/pn2eacpn.c old_versions/2011/spnbox/reduce.c old_versions/2011/spnbox/spnbox.h old_versions/2011/spnbox/supervis.c old_versions/2011/spnbox/tactn.c old_versions/2011/spnbox/tests/ old_versions/2011/spnbox/tests/Makefile old_versions/2011/spnbox/tests/StructuredIO.c old_versions/2011/spnbox/tests/StructuredIO.h old_versions/2011/spnbox/tests/pnexample.c old_versions/2011/spnbox/tests/test-actn.c old_versions/2011/spnbox/tests/test-actn.txt old_versions/2011/spnbox/tests/test-admcon.c old_versions/2011/spnbox/tests/test-asiph.c old_versions/2011/spnbox/tests/test-asiph.txt old_versions/2011/spnbox/tests/test-avpr.c old_versions/2011/spnbox/tests/test-avpr.txt old_versions/2011/spnbox/tests/test-dp.c old_versions/2011/spnbox/tests/test-dp.txt old_versions/2011/spnbox/tests/test-extendedmatrix.c old_versions/2011/spnbox/tests/test-extendedmatrix.txt old_versions/2011/spnbox/tests/test-fvpr.c old_versions/2011/spnbox/tests/test-fvpr.txt old_versions/2011/spnbox/tests/test-gcdv.c old_versions/2011/spnbox/tests/test-gcdv.txt old_versions/2011/spnbox/tests/test-ilpadm.c old_versions/2011/spnbox/tests/test-ilpadm.txt old_versions/2011/spnbox/tests/test-invar.c old_versions/2011/spnbox/tests/test-invar.txt old_versions/2011/spnbox/tests/test-ipslv.c old_versions/2011/spnbox/tests/test-ipsolve.c old_versions/2011/spnbox/tests/test-ipsolve.txt old_versions/2011/spnbox/tests/test-isadm.c old_versions/2011/spnbox/tests/test-isadm.txt old_versions/2011/spnbox/tests/test-issiph.c old_versions/2011/spnbox/tests/test-issiph.txt old_versions/2011/spnbox/tests/test-lindisj.c old_versions/2011/spnbox/tests/test-lindisj.txt old_versions/2011/spnbox/tests/test-lindisq.c old_versions/2011/spnbox/tests/test-lindisq.txt old_versions/2011/spnbox/tests/test-linenf.c old_versions/2011/spnbox/tests/test-linenf.txt old_versions/2011/spnbox/tests/test-lintree.c old_versions/2011/spnbox/tests/test-lintree.txt old_versions/2011/spnbox/tests/test-matrixmath.c old_versions/2011/spnbox/tests/test-matrixmath.txt old_versions/2011/spnbox/tests/test-mroadm.c old_versions/2011/spnbox/tests/test-mroadm.txt old_versions/2011/spnbox/tests/test-msplit.c old_versions/2011/spnbox/tests/test-msplit.txt old_versions/2011/spnbox/tests/test-nltrans.c old_versions/2011/spnbox/tests/test-nltrans.txt old_versions/2011/spnbox/tests/test-pn2acpn.c old_versions/2011/spnbox/tests/test-pn2acpn.txt old_versions/2011/spnbox/tests/test-pn2eacpn.c old_versions/2011/spnbox/tests/test-pn2eacpn.txt old_versions/2011/spnbox/tests/test-reduce.c old_versions/2011/spnbox/tests/test-reduce.txt old_versions/2011/spnbox/tests/test-superdis.c old_versions/2011/spnbox/tests/test-supervis.c old_versions/2011/spnbox/tests/test-supervis.txt old_versions/2011/spnbox/tests/test-tactn.c old_versions/2011/spnbox/tests/test-tactn.txt old_versions/2011/spnbox/tests/test.c old_versions/2011/spnbox/tests/test.h old_versions/2011/spnbox/tree2spec.c old_versions/2011/third-party/ old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/ old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/AUTHORS old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/C.sln old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/C.vcproj old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/C.vcproj.vspscc old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/C.vssscc old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/COPYING old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/ChangeLog old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/INSTALL old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/Makefile.am old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/Makefile.in old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/NEWS old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/README old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/aclocal.m4 old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/antlr3config.h.in old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/config.guess old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/config.sub old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/configure old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/configure.ac old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/depcomp old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/ old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3baserecognizer.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3basetree.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3basetreeadaptor.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3bitset.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3collections.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3commontoken.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3commontree.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3commontreeadaptor.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3commontreenodestream.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3convertutf.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3cyclicdfa.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3debugeventlistener.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3defs.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3encodings.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3errors.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3exception.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3filestream.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3input.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3interfaces.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3intstream.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3lexer.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3memory.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3parser.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3parsetree.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3recognizersharedstate.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3rewritestreams.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3string.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3stringstream.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3tokenstream.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/include/antlr3treeparser.h old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/install-sh old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/ltmain.sh old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/missing old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/ old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3baserecognizer.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3basetree.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3basetreeadaptor.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3bitset.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3collections.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3commontoken.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3commontree.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3commontreeadaptor.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3commontreenodestream.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3convertutf.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3cyclicdfa.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3debughandlers.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3encodings.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3exception.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3filestream.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3inputstream.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3intstream.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3lexer.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3parser.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3rewritestreams.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3string.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3stringstream.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3tokenstream.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3treeparser.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/src/antlr3ucs2inputstream.c old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/vsrulefiles/ old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/vsrulefiles/antlr3lexer.rules old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/vsrulefiles/antlr3lexerandparser.rules old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/vsrulefiles/antlr3parser.rules old_versions/2011/third-party/ANTLR3_ctarget_3_1_3/vsrulefiles/antlr3treeparser.rules old_versions/2011/translator/ old_versions/2011/translator/Makefile old_versions/2011/translator/README.txt old_versions/2011/translator/clibs.patch old_versions/2011/translator/compactor.patch old_versions/2011/translator/dataStructures.c old_versions/2011/translator/dataStructures.h old_versions/2011/translator/docs/ old_versions/2011/translator/docs/PNspec.pdf old_versions/2011/translator/docs/TODO.rtf old_versions/2011/translator/docs/distributive.jpg old_versions/2011/translator/docs/eqSample.bmp old_versions/2011/translator/docs/eqsimplification.eps old_versions/2011/translator/docs/eqsimplification.pdf old_versions/2011/translator/docs/eqsimplification.txt old_versions/2011/translator/docs/notes.txt old_versions/2011/translator/docs/output.eps old_versions/2011/translator/docs/output.pdf old_versions/2011/translator/docs/spec.txt old_versions/2011/translator/docs/spec2.txt old_versions/2011/translator/docs/test.txt old_versions/2011/translator/generator.patch old_versions/2011/translator/input/ old_versions/2011/translator/input/complete.txt old_versions/2011/translator/main.c old_versions/2011/translator/parser.patch old_versions/2011/translator/pncompactor.c old_versions/2011/translator/pncompactor.g old_versions/2011/translator/pncompactor.h old_versions/2011/translator/pncompactor.tokens old_versions/2011/translator/pngenerator.c old_versions/2011/translator/pngenerator.g old_versions/2011/translator/pngenerator.h old_versions/2011/translator/pngenerator.tokens old_versions/2011/translator/pnscript.g old_versions/2011/translator/pnscript.tokens old_versions/2011/translator/pnscriptLexer.c old_versions/2011/translator/pnscriptLexer.h old_versions/2011/translator/pnscriptParser.c old_versions/2011/translator/pnscriptParser.h old_versions/2011/translator/pnscript_java_compat.g old_versions/2011/translator/pnscript_java_compat.tokens old_versions/2011/translator/tree.php old_versions/2011/translator/treeparser.h present_version/ present_version/LICENSE/ present_version/LICENSE/LICENSE.txt present_version/LICENSE/README.txt present_version/Makefile-cygwin.mak present_version/Makefile-linux.mak present_version/README.txt present_version/doc/ present_version/doc/GettingStarted.htm present_version/doc/format2.hl present_version/doc/input2.sp present_version/examples/ present_version/examples/README present_version/examples/inteq.sp present_version/newcodegen/ present_version/newcodegen/Makefile-cygwin.mak present_version/newcodegen/Makefile-linux.mak present_version/newcodegen/ProcessTemplate.c present_version/newcodegen/SupervisorTemplate.c present_version/newcodegen/codegen.h present_version/newcodegen/compexample.c present_version/newcodegen/filltmpl.lex present_version/newcodegen/plantCompiler.c present_version/newcodegen/plantCompiler.h present_version/newcodegen/spcommon.h present_version/newcodegen/supervisorCompiler.c present_version/parser/ present_version/parser/Makefile present_version/parser/actions.c present_version/parser/dict.c present_version/parser/dict.h present_version/parser/read.h present_version/parser/read.lex present_version/parser/read.y present_version/pnheaders/ present_version/pnheaders/Makefile present_version/pnheaders/general.c present_version/pnheaders/general.h present_version/pnheaders/insert.c present_version/pnheaders/insert.h present_version/pnheaders/main_function.c present_version/pnheaders/main_function2.c present_version/pnheaders/matrix.c present_version/pnheaders/matrix.h present_version/pnheaders/pnexample.c present_version/pnheaders/pns.c present_version/pnheaders/pns.h present_version/spnbox/ present_version/spnbox/Makefile present_version/spnbox/MemoryManager.c present_version/spnbox/MemoryManager.h present_version/spnbox/actn.c present_version/spnbox/admcon.c present_version/spnbox/asiph.c present_version/spnbox/avpr.c present_version/spnbox/chkcons.c present_version/spnbox/deallocation.c present_version/spnbox/disj2normal.c present_version/spnbox/disj2pn.c present_version/spnbox/disq2disj.c present_version/spnbox/doc/ present_version/spnbox/doc/README.txt present_version/spnbox/doc/functions.html present_version/spnbox/doc/index.html present_version/spnbox/doc/isis-2002-003.pdf present_version/spnbox/doc/support.html present_version/spnbox/doc/test.html present_version/spnbox/dp.c present_version/spnbox/dp4.c present_version/spnbox/extendedmatrix.c present_version/spnbox/extendedmatrix.h present_version/spnbox/fvpr.c present_version/spnbox/gcdv.c present_version/spnbox/ilpadm.c present_version/spnbox/invar.c present_version/spnbox/ipslv.c present_version/spnbox/ipsolve.c present_version/spnbox/isadm.c present_version/spnbox/issiph.c present_version/spnbox/linenf.c present_version/spnbox/matrixmath.c present_version/spnbox/matrixmath.h present_version/spnbox/mroadm.c present_version/spnbox/msplit.c present_version/spnbox/nltrans.c present_version/spnbox/pn2acpn.c present_version/spnbox/pn2eacpn.c present_version/spnbox/reduce.c present_version/spnbox/spnbox.h present_version/spnbox/supervis.c present_version/spnbox/tactn.c present_version/spnbox/tests/ present_version/spnbox/tests/Makefile present_version/spnbox/tests/StructuredIO.c present_version/spnbox/tests/StructuredIO.h present_version/spnbox/tests/pnexample.c present_version/spnbox/tests/test-actn.c present_version/spnbox/tests/test-actn.txt present_version/spnbox/tests/test-admcon.c present_version/spnbox/tests/test-asiph.c present_version/spnbox/tests/test-asiph.txt present_version/spnbox/tests/test-avpr.c present_version/spnbox/tests/test-avpr.txt present_version/spnbox/tests/test-dp.c present_version/spnbox/tests/test-dp.txt present_version/spnbox/tests/test-extendedmatrix.c present_version/spnbox/tests/test-extendedmatrix.txt present_version/spnbox/tests/test-fvpr.c present_version/spnbox/tests/test-fvpr.txt present_version/spnbox/tests/test-gcdv.c present_version/spnbox/tests/test-gcdv.txt present_version/spnbox/tests/test-ilpadm.c present_version/spnbox/tests/test-ilpadm.txt present_version/spnbox/tests/test-invar.c present_version/spnbox/tests/test-invar.txt present_version/spnbox/tests/test-ipslv.c present_version/spnbox/tests/test-ipsolve.c present_version/spnbox/tests/test-ipsolve.txt present_version/spnbox/tests/test-isadm.c present_version/spnbox/tests/test-isadm.txt present_version/spnbox/tests/test-issiph.c present_version/spnbox/tests/test-issiph.txt present_version/spnbox/tests/test-lindisj.c present_version/spnbox/tests/test-lindisj.txt present_version/spnbox/tests/test-lindisq.c present_version/spnbox/tests/test-lindisq.txt present_version/spnbox/tests/test-linenf.c present_version/spnbox/tests/test-linenf.txt present_version/spnbox/tests/test-lintree.c present_version/spnbox/tests/test-lintree.txt present_version/spnbox/tests/test-matrixmath.c present_version/spnbox/tests/test-matrixmath.txt present_version/spnbox/tests/test-mroadm.c present_version/spnbox/tests/test-mroadm.txt present_version/spnbox/tests/test-msplit.c present_version/spnbox/tests/test-msplit.txt present_version/spnbox/tests/test-nltrans.c present_version/spnbox/tests/test-nltrans.txt present_version/spnbox/tests/test-pn2acpn.c present_version/spnbox/tests/test-pn2acpn.txt present_version/spnbox/tests/test-pn2eacpn.c present_version/spnbox/tests/test-pn2eacpn.txt present_version/spnbox/tests/test-reduce.c present_version/spnbox/tests/test-reduce.txt present_version/spnbox/tests/test-superdis.c present_version/spnbox/tests/test-supervis.c present_version/spnbox/tests/test-supervis.txt present_version/spnbox/tests/test-tactn.c present_version/spnbox/tests/test-tactn.txt present_version/spnbox/tests/test.c present_version/spnbox/tests/test.h present_version/spnbox/tree2spec.c present_version/third-party/ present_version/third-party/lp_solve_5.5/ present_version/third-party/lp_solve_5.5/Makefile present_version/third-party/lp_solve_5.5/Makefile.Linux present_version/third-party/lp_solve_5.5/Makefile.in present_version/third-party/lp_solve_5.5/Makefile.msc present_version/third-party/lp_solve_5.5/README.txt present_version/third-party/lp_solve_5.5/bfp/ present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/ present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/ present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/LUSOL-overview.txt present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/LUSOL_LGPL.txt present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/LUSOL_Overview.txt present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/LUSOL_README.txt present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/Row-based L0.txt present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/Victoria1850.RUA present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/bfile3.txt present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/hbio.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/hbio.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol1.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol2.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol6a.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol6l0.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol6u.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol7a.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusol8a.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusolio.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusolio.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusolmain.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/lusolmain.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/mmio.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/mmio.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/myblas.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/myblas.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/sherman5.mtx present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/sherman5_rhs1.mtx present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/sparselib.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/LUSOL/sparselib.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/bfp_LUSOL.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/bfp_LUSOL.h present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/lp_LUSOL.c present_version/third-party/lp_solve_5.5/bfp/bfp_LUSOL/lp_LUSOL.h present_version/third-party/lp_solve_5.5/bfp/lp_BFP.h present_version/third-party/lp_solve_5.5/bfp/lp_BFP1.c present_version/third-party/lp_solve_5.5/bfp/lp_BFP2.c present_version/third-party/lp_solve_5.5/colamd/ present_version/third-party/lp_solve_5.5/colamd/colamd.c present_version/third-party/lp_solve_5.5/colamd/colamd.h present_version/third-party/lp_solve_5.5/configure present_version/third-party/lp_solve_5.5/configure.ac present_version/third-party/lp_solve_5.5/declare.h present_version/third-party/lp_solve_5.5/demo/ present_version/third-party/lp_solve_5.5/demo/cbcc32.bat present_version/third-party/lp_solve_5.5/demo/ccc present_version/third-party/lp_solve_5.5/demo/ccc.osx present_version/third-party/lp_solve_5.5/demo/cgcc.bat present_version/third-party/lp_solve_5.5/demo/cvc6.bat present_version/third-party/lp_solve_5.5/demo/cvc8.bat present_version/third-party/lp_solve_5.5/demo/demo.c present_version/third-party/lp_solve_5.5/demo/demo.sln present_version/third-party/lp_solve_5.5/demo/demo.vcproj present_version/third-party/lp_solve_5.5/demo/demolib.sln present_version/third-party/lp_solve_5.5/demo/demolib.vcproj present_version/third-party/lp_solve_5.5/demo/readme.txt present_version/third-party/lp_solve_5.5/doc/ present_version/third-party/lp_solve_5.5/doc/AMPL.htm present_version/third-party/lp_solve_5.5/doc/BFP.htm present_version/third-party/lp_solve_5.5/doc/Build.htm present_version/third-party/lp_solve_5.5/doc/CPLEX-format.htm present_version/third-party/lp_solve_5.5/doc/DIMACS_asn.htm present_version/third-party/lp_solve_5.5/doc/DIMACS_maxf.htm present_version/third-party/lp_solve_5.5/doc/DIMACS_mcf.htm present_version/third-party/lp_solve_5.5/doc/FAQ.htm present_version/third-party/lp_solve_5.5/doc/IDE/ present_version/third-party/lp_solve_5.5/doc/IDE/IDE1.gif present_version/third-party/lp_solve_5.5/doc/IDE/IDE2.gif present_version/third-party/lp_solve_5.5/doc/IDE/IDE3.gif present_version/third-party/lp_solve_5.5/doc/IDE/IDE4.gif present_version/third-party/lp_solve_5.5/doc/IDE.htm present_version/third-party/lp_solve_5.5/doc/Infeasible.htm present_version/third-party/lp_solve_5.5/doc/Intro.htm present_version/third-party/lp_solve_5.5/doc/Java/ present_version/third-party/lp_solve_5.5/doc/Java/README.html present_version/third-party/lp_solve_5.5/doc/Java/docs/ present_version/third-party/lp_solve_5.5/doc/Java/docs/api/ present_version/third-party/lp_solve_5.5/doc/Java/docs/api/allclasses-frame.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/allclasses-noframe.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/constant-values.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/deprecated-list.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/help-doc.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/index-all.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/index.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/ present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/AbortListener.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/BbListener.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/LogListener.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/LpSolve.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/LpSolveException.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/MsgListener.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/VersionInfo.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/package-frame.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/package-summary.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/lpsolve/package-tree.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/overview-tree.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/package-list present_version/third-party/lp_solve_5.5/doc/Java/docs/api/packages.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/resources/ present_version/third-party/lp_solve_5.5/doc/Java/docs/api/resources/inherit.gif present_version/third-party/lp_solve_5.5/doc/Java/docs/api/serialized-form.html present_version/third-party/lp_solve_5.5/doc/Java/docs/api/stylesheet.css present_version/third-party/lp_solve_5.5/doc/Java/docs/reference.html present_version/third-party/lp_solve_5.5/doc/Java.htm present_version/third-party/lp_solve_5.5/doc/LGPL.htm present_version/third-party/lp_solve_5.5/doc/LINDO-format.htm present_version/third-party/lp_solve_5.5/doc/LPBasics.htm present_version/third-party/lp_solve_5.5/doc/MATLAB.htm present_version/third-party/lp_solve_5.5/doc/MATLAB1.jpg present_version/third-party/lp_solve_5.5/doc/MATLAB2.jpg present_version/third-party/lp_solve_5.5/doc/MATLAB3.jpg present_version/third-party/lp_solve_5.5/doc/MathProg.htm present_version/third-party/lp_solve_5.5/doc/O-Matrix.htm present_version/third-party/lp_solve_5.5/doc/O-Matrix1.jpg present_version/third-party/lp_solve_5.5/doc/O-Matrix2.jpg present_version/third-party/lp_solve_5.5/doc/O-Matrix3.jpg present_version/third-party/lp_solve_5.5/doc/Octave.htm present_version/third-party/lp_solve_5.5/doc/Octave1.jpg present_version/third-party/lp_solve_5.5/doc/Octave2.jpg present_version/third-party/lp_solve_5.5/doc/Octave3.jpg present_version/third-party/lp_solve_5.5/doc/PHP.htm present_version/third-party/lp_solve_5.5/doc/Presolve.htm present_version/third-party/lp_solve_5.5/doc/Python.htm present_version/third-party/lp_solve_5.5/doc/R.htm present_version/third-party/lp_solve_5.5/doc/SOS.htm present_version/third-party/lp_solve_5.5/doc/Scilab.htm present_version/third-party/lp_solve_5.5/doc/Scilab1.jpg present_version/third-party/lp_solve_5.5/doc/Scilab2.jpg present_version/third-party/lp_solve_5.5/doc/Scilab3.jpg present_version/third-party/lp_solve_5.5/doc/Semi-ContinuousVariables_files/ present_version/third-party/lp_solve_5.5/doc/Semi-ContinuousVariables_files/bsscdhtm.js present_version/third-party/lp_solve_5.5/doc/Semi-ContinuousVariables_files/img00340.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/ present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/bsscdhtm.js present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/img00341.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/img00342.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/img00343.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/img00344.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/img00345.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/img00346.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeOne_files/img00347.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/ present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/bsscdhtm.js present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00348.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00349.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00350.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00351.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00352.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00353.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00354.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00355.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00356.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00357.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00358.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00359.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00360.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00361.gif present_version/third-party/lp_solve_5.5/doc/SpecialOrderedSetsOfTypeTwo_files/img00362.gif present_version/third-party/lp_solve_5.5/doc/Win32/ present_version/third-party/lp_solve_5.5/doc/Win32/HTML Help/ present_version/third-party/lp_solve_5.5/doc/XLI.htm present_version/third-party/lp_solve_5.5/doc/Xpress-format.htm present_version/third-party/lp_solve_5.5/doc/Zimpl.htm present_version/third-party/lp_solve_5.5/doc/absolute.htm present_version/third-party/lp_solve_5.5/doc/add_SOS.htm present_version/third-party/lp_solve_5.5/doc/add_column.htm present_version/third-party/lp_solve_5.5/doc/add_constraint.htm present_version/third-party/lp_solve_5.5/doc/add_lag_con.htm present_version/third-party/lp_solve_5.5/doc/bas-format.htm present_version/third-party/lp_solve_5.5/doc/changes5.htm present_version/third-party/lp_solve_5.5/doc/changes55.htm present_version/third-party/lp_solve_5.5/doc/closed.gif present_version/third-party/lp_solve_5.5/doc/column_in_lp.htm present_version/third-party/lp_solve_5.5/doc/contents.htm present_version/third-party/lp_solve_5.5/doc/copy_lp.htm present_version/third-party/lp_solve_5.5/doc/default_basis.htm present_version/third-party/lp_solve_5.5/doc/del_column.htm present_version/third-party/lp_solve_5.5/doc/del_constraint.htm present_version/third-party/lp_solve_5.5/doc/delete_lp.htm present_version/third-party/lp_solve_5.5/doc/dimacs_asn.gif present_version/third-party/lp_solve_5.5/doc/dimacs_maxf.gif present_version/third-party/lp_solve_5.5/doc/dimacs_mcf.gif present_version/third-party/lp_solve_5.5/doc/distribution.htm present_version/third-party/lp_solve_5.5/doc/download.htm present_version/third-party/lp_solve_5.5/doc/dualize_lp.htm present_version/third-party/lp_solve_5.5/doc/fold.gif present_version/third-party/lp_solve_5.5/doc/formulate.htm present_version/third-party/lp_solve_5.5/doc/free.htm present_version/third-party/lp_solve_5.5/doc/free_lp.htm present_version/third-party/lp_solve_5.5/doc/get_Lrows.htm present_version/third-party/lp_solve_5.5/doc/get_Ncolumns.htm present_version/third-party/lp_solve_5.5/doc/get_Norig_columns.htm present_version/third-party/lp_solve_5.5/doc/get_Norig_rows.htm present_version/third-party/lp_solve_5.5/doc/get_Nrows.htm present_version/third-party/lp_solve_5.5/doc/get_anti_degen.htm present_version/third-party/lp_solve_5.5/doc/get_basis.htm present_version/third-party/lp_solve_5.5/doc/get_basiscrash.htm present_version/third-party/lp_solve_5.5/doc/get_bb_depthlimit.htm present_version/third-party/lp_solve_5.5/doc/get_bb_floorfirst.htm present_version/third-party/lp_solve_5.5/doc/get_bb_rule.htm present_version/third-party/lp_solve_5.5/doc/get_bounds_tighter.htm present_version/third-party/lp_solve_5.5/doc/get_break_at_value.htm present_version/third-party/lp_solve_5.5/doc/get_col_name.htm present_version/third-party/lp_solve_5.5/doc/get_column.htm present_version/third-party/lp_solve_5.5/doc/get_constr_type.htm present_version/third-party/lp_solve_5.5/doc/get_constr_value.htm present_version/third-party/lp_solve_5.5/doc/get_constraints.htm present_version/third-party/lp_solve_5.5/doc/get_epsb.htm present_version/third-party/lp_solve_5.5/doc/get_epsd.htm present_version/third-party/lp_solve_5.5/doc/get_epsel.htm present_version/third-party/lp_solve_5.5/doc/get_epsint.htm present_version/third-party/lp_solve_5.5/doc/get_epsperturb.htm present_version/third-party/lp_solve_5.5/doc/get_epspivot.htm present_version/third-party/lp_solve_5.5/doc/get_improve.htm present_version/third-party/lp_solve_5.5/doc/get_infinite.htm present_version/third-party/lp_solve_5.5/doc/get_lambda.htm present_version/third-party/lp_solve_5.5/doc/get_lowbo.htm present_version/third-party/lp_solve_5.5/doc/get_lp_index.htm present_version/third-party/lp_solve_5.5/doc/get_lp_name.htm present_version/third-party/lp_solve_5.5/doc/get_mat.htm present_version/third-party/lp_solve_5.5/doc/get_max_level.htm present_version/third-party/lp_solve_5.5/doc/get_maxpivot.htm present_version/third-party/lp_solve_5.5/doc/get_mip_gap.htm present_version/third-party/lp_solve_5.5/doc/get_nameindex.htm present_version/third-party/lp_solve_5.5/doc/get_negrange.htm present_version/third-party/lp_solve_5.5/doc/get_nonzeros.htm present_version/third-party/lp_solve_5.5/doc/get_obj_bound.htm present_version/third-party/lp_solve_5.5/doc/get_objective.htm present_version/third-party/lp_solve_5.5/doc/get_orig_index.htm present_version/third-party/lp_solve_5.5/doc/get_pivoting.htm present_version/third-party/lp_solve_5.5/doc/get_presolve.htm present_version/third-party/lp_solve_5.5/doc/get_presolveloops.htm present_version/third-party/lp_solve_5.5/doc/get_primal_solution.htm present_version/third-party/lp_solve_5.5/doc/get_print_sol.htm present_version/third-party/lp_solve_5.5/doc/get_rh.htm present_version/third-party/lp_solve_5.5/doc/get_rh_range.htm present_version/third-party/lp_solve_5.5/doc/get_row.htm present_version/third-party/lp_solve_5.5/doc/get_row_name.htm present_version/third-party/lp_solve_5.5/doc/get_scalelimit.htm present_version/third-party/lp_solve_5.5/doc/get_scaling.htm present_version/third-party/lp_solve_5.5/doc/get_sensitivity_obj.htm present_version/third-party/lp_solve_5.5/doc/get_sensitivity_rhs.htm present_version/third-party/lp_solve_5.5/doc/get_simplextype.htm present_version/third-party/lp_solve_5.5/doc/get_solutioncount.htm present_version/third-party/lp_solve_5.5/doc/get_solutionlimit.htm present_version/third-party/lp_solve_5.5/doc/get_status.htm present_version/third-party/lp_solve_5.5/doc/get_statustext.htm present_version/third-party/lp_solve_5.5/doc/get_timeout.htm present_version/third-party/lp_solve_5.5/doc/get_total_iter.htm present_version/third-party/lp_solve_5.5/doc/get_total_nodes.htm present_version/third-party/lp_solve_5.5/doc/get_upbo.htm present_version/third-party/lp_solve_5.5/doc/get_var_branch.htm present_version/third-party/lp_solve_5.5/doc/get_var_priority.htm present_version/third-party/lp_solve_5.5/doc/get_variables.htm present_version/third-party/lp_solve_5.5/doc/get_verbose.htm present_version/third-party/lp_solve_5.5/doc/get_working_objective.htm present_version/third-party/lp_solve_5.5/doc/guess_basis.htm present_version/third-party/lp_solve_5.5/doc/has_BFP.htm present_version/third-party/lp_solve_5.5/doc/has_XLI.htm present_version/third-party/lp_solve_5.5/doc/index.htm present_version/third-party/lp_solve_5.5/doc/index.html present_version/third-party/lp_solve_5.5/doc/integer.htm present_version/third-party/lp_solve_5.5/doc/is_SOS_var.htm present_version/third-party/lp_solve_5.5/doc/is_add_rowmode.htm present_version/third-party/lp_solve_5.5/doc/is_anti_degen.htm present_version/third-party/lp_solve_5.5/doc/is_binary.htm present_version/third-party/lp_solve_5.5/doc/is_break_at_first.htm present_version/third-party/lp_solve_5.5/doc/is_constr_type.htm present_version/third-party/lp_solve_5.5/doc/is_debug.htm present_version/third-party/lp_solve_5.5/doc/is_feasible.htm present_version/third-party/lp_solve_5.5/doc/is_infinite.htm present_version/third-party/lp_solve_5.5/doc/is_int.htm present_version/third-party/lp_solve_5.5/doc/is_integerscaling.htm present_version/third-party/lp_solve_5.5/doc/is_lag_trace.htm present_version/third-party/lp_solve_5.5/doc/is_maxim.htm present_version/third-party/lp_solve_5.5/doc/is_nativeBFP.htm present_version/third-party/lp_solve_5.5/doc/is_nativeXLI.htm present_version/third-party/lp_solve_5.5/doc/is_negative.htm present_version/third-party/lp_solve_5.5/doc/is_obj_in_basis.htm present_version/third-party/lp_solve_5.5/doc/is_piv_mode.htm present_version/third-party/lp_solve_5.5/doc/is_piv_rule.htm present_version/third-party/lp_solve_5.5/doc/is_presolve.htm present_version/third-party/lp_solve_5.5/doc/is_scalemode.htm present_version/third-party/lp_solve_5.5/doc/is_scaletype.htm present_version/third-party/lp_solve_5.5/doc/is_semicont.htm present_version/third-party/lp_solve_5.5/doc/is_trace.htm present_version/third-party/lp_solve_5.5/doc/is_unbounded.htm present_version/third-party/lp_solve_5.5/doc/is_use_names.htm present_version/third-party/lp_solve_5.5/doc/lag_solve.htm present_version/third-party/lp_solve_5.5/doc/links.htm present_version/third-party/lp_solve_5.5/doc/list.gif present_version/third-party/lp_solve_5.5/doc/lp-format.htm present_version/third-party/lp_solve_5.5/doc/lp_solve.htm present_version/third-party/lp_solve_5.5/doc/lp_solveAPIreference.htm present_version/third-party/lp_solve_5.5/doc/lp_solve_5.5.0.12.chw present_version/third-party/lp_solve_5.5/doc/lp_solve_5.5.0.13.chw present_version/third-party/lp_solve_5.5/doc/lp_solve_5.5.0.14.chw present_version/third-party/lp_solve_5.5/doc/lp_solve_5.5.0.14_doc.tar present_version/third-party/lp_solve_5.5/doc/lp_solve_version.htm present_version/third-party/lp_solve_5.5/doc/make_lp.htm present_version/third-party/lp_solve_5.5/doc/mps-format.htm present_version/third-party/lp_solve_5.5/doc/open.gif present_version/third-party/lp_solve_5.5/doc/print_constraints.htm present_version/third-party/lp_solve_5.5/doc/print_debugdump.htm present_version/third-party/lp_solve_5.5/doc/print_duals.htm present_version/third-party/lp_solve_5.5/doc/print_lp.htm present_version/third-party/lp_solve_5.5/doc/print_objective.htm present_version/third-party/lp_solve_5.5/doc/print_scales.htm present_version/third-party/lp_solve_5.5/doc/print_solution.htm present_version/third-party/lp_solve_5.5/doc/print_str.htm present_version/third-party/lp_solve_5.5/doc/print_tableau.htm present_version/third-party/lp_solve_5.5/doc/put_abortfunc.htm present_version/third-party/lp_solve_5.5/doc/put_bb_branchfunc.htm present_version/third-party/lp_solve_5.5/doc/put_bb_nodefunc.htm present_version/third-party/lp_solve_5.5/doc/put_logfunc.htm present_version/third-party/lp_solve_5.5/doc/put_msgfunc.htm present_version/third-party/lp_solve_5.5/doc/quickstart.htm present_version/third-party/lp_solve_5.5/doc/ratio.htm present_version/third-party/lp_solve_5.5/doc/read_XLI.htm present_version/third-party/lp_solve_5.5/doc/read_basis.htm present_version/third-party/lp_solve_5.5/doc/read_lp.htm present_version/third-party/lp_solve_5.5/doc/read_mps.htm present_version/third-party/lp_solve_5.5/doc/read_params.htm present_version/third-party/lp_solve_5.5/doc/reset_basis.htm present_version/third-party/lp_solve_5.5/doc/reset_params.htm present_version/third-party/lp_solve_5.5/doc/resize_lp.htm present_version/third-party/lp_solve_5.5/doc/scaling.htm present_version/third-party/lp_solve_5.5/doc/search.htm present_version/third-party/lp_solve_5.5/doc/semi-cont.htm present_version/third-party/lp_solve_5.5/doc/sensitivity.htm present_version/third-party/lp_solve_5.5/doc/set_BFP.htm present_version/third-party/lp_solve_5.5/doc/set_XLI.htm present_version/third-party/lp_solve_5.5/doc/set_add_rowmode.htm present_version/third-party/lp_solve_5.5/doc/set_anti_degen.htm present_version/third-party/lp_solve_5.5/doc/set_basis.htm present_version/third-party/lp_solve_5.5/doc/set_basiscrash.htm present_version/third-party/lp_solve_5.5/doc/set_basisvar.htm present_version/third-party/lp_solve_5.5/doc/set_bb_depthlimit.htm present_version/third-party/lp_solve_5.5/doc/set_bb_floorfirst.htm present_version/third-party/lp_solve_5.5/doc/set_bb_rule.htm present_version/third-party/lp_solve_5.5/doc/set_binary.htm present_version/third-party/lp_solve_5.5/doc/set_bounds.htm present_version/third-party/lp_solve_5.5/doc/set_bounds_tighter.htm present_version/third-party/lp_solve_5.5/doc/set_break_at_first.htm present_version/third-party/lp_solve_5.5/doc/set_break_at_value.htm present_version/third-party/lp_solve_5.5/doc/set_col_name.htm present_version/third-party/lp_solve_5.5/doc/set_column.htm present_version/third-party/lp_solve_5.5/doc/set_constr_type.htm present_version/third-party/lp_solve_5.5/doc/set_debug.htm present_version/third-party/lp_solve_5.5/doc/set_epsb.htm present_version/third-party/lp_solve_5.5/doc/set_epsd.htm present_version/third-party/lp_solve_5.5/doc/set_epsel.htm present_version/third-party/lp_solve_5.5/doc/set_epsint.htm present_version/third-party/lp_solve_5.5/doc/set_epslevel.htm present_version/third-party/lp_solve_5.5/doc/set_epsperturb.htm present_version/third-party/lp_solve_5.5/doc/set_epspivot.htm present_version/third-party/lp_solve_5.5/doc/set_improve.htm present_version/third-party/lp_solve_5.5/doc/set_infinite.htm present_version/third-party/lp_solve_5.5/doc/set_int.htm present_version/third-party/lp_solve_5.5/doc/set_lag_trace.htm present_version/third-party/lp_solve_5.5/doc/set_lowbo.htm present_version/third-party/lp_solve_5.5/doc/set_lp_name.htm present_version/third-party/lp_solve_5.5/doc/set_mat.htm present_version/third-party/lp_solve_5.5/doc/set_maxim.htm present_version/third-party/lp_solve_5.5/doc/set_maxpivot.htm present_version/third-party/lp_solve_5.5/doc/set_minim.htm present_version/third-party/lp_solve_5.5/doc/set_mip_gap.htm present_version/third-party/lp_solve_5.5/doc/set_negrange.htm present_version/third-party/lp_solve_5.5/doc/set_obj_bound.htm present_version/third-party/lp_solve_5.5/doc/set_obj_fn.htm present_version/third-party/lp_solve_5.5/doc/set_obj_in_basis.htm present_version/third-party/lp_solve_5.5/doc/set_output.htm present_version/third-party/lp_solve_5.5/doc/set_pivoting.htm present_version/third-party/lp_solve_5.5/doc/set_preferdual.htm present_version/third-party/lp_solve_5.5/doc/set_presolve.htm present_version/third-party/lp_solve_5.5/doc/set_print_sol.htm present_version/third-party/lp_solve_5.5/doc/set_rh.htm present_version/third-party/lp_solve_5.5/doc/set_rh_range.htm present_version/third-party/lp_solve_5.5/doc/set_rh_vec.htm present_version/third-party/lp_solve_5.5/doc/set_row.htm present_version/third-party/lp_solve_5.5/doc/set_row_name.htm present_version/third-party/lp_solve_5.5/doc/set_scalelimit.htm present_version/third-party/lp_solve_5.5/doc/set_scaling.htm present_version/third-party/lp_solve_5.5/doc/set_semicont.htm present_version/third-party/lp_solve_5.5/doc/set_sense.htm present_version/third-party/lp_solve_5.5/doc/set_simplextype.htm present_version/third-party/lp_solve_5.5/doc/set_solutionlimit.htm present_version/third-party/lp_solve_5.5/doc/set_timeout.htm present_version/third-party/lp_solve_5.5/doc/set_trace.htm present_version/third-party/lp_solve_5.5/doc/set_unbounded.htm present_version/third-party/lp_solve_5.5/doc/set_upbo.htm present_version/third-party/lp_solve_5.5/doc/set_use_names.htm present_version/third-party/lp_solve_5.5/doc/set_var_branch.htm present_version/third-party/lp_solve_5.5/doc/set_var_weights.htm present_version/third-party/lp_solve_5.5/doc/set_verbose.htm present_version/third-party/lp_solve_5.5/doc/simpletree.css present_version/third-party/lp_solve_5.5/doc/simpletreemenu.js present_version/third-party/lp_solve_5.5/doc/solve.htm present_version/third-party/lp_solve_5.5/doc/time_elapsed.htm present_version/third-party/lp_solve_5.5/doc/unscale.htm present_version/third-party/lp_solve_5.5/doc/write_XLI.htm present_version/third-party/lp_solve_5.5/doc/write_basis.htm present_version/third-party/lp_solve_5.5/doc/write_lp.htm present_version/third-party/lp_solve_5.5/doc/write_mps.htm present_version/third-party/lp_solve_5.5/doc/write_params.htm present_version/third-party/lp_solve_5.5/fortify.c present_version/third-party/lp_solve_5.5/fortify.h present_version/third-party/lp_solve_5.5/ini.c present_version/third-party/lp_solve_5.5/ini.h present_version/third-party/lp_solve_5.5/lp_Hash.c present_version/third-party/lp_solve_5.5/lp_Hash.h present_version/third-party/lp_solve_5.5/lp_MDO.c present_version/third-party/lp_solve_5.5/lp_MDO.h present_version/third-party/lp_solve_5.5/lp_MPS.c present_version/third-party/lp_solve_5.5/lp_MPS.h present_version/third-party/lp_solve_5.5/lp_SOS.c present_version/third-party/lp_solve_5.5/lp_SOS.h present_version/third-party/lp_solve_5.5/lp_crash.c present_version/third-party/lp_solve_5.5/lp_crash.h present_version/third-party/lp_solve_5.5/lp_explicit.h present_version/third-party/lp_solve_5.5/lp_fortify.h present_version/third-party/lp_solve_5.5/lp_lib.c present_version/third-party/lp_solve_5.5/lp_lib.h present_version/third-party/lp_solve_5.5/lp_matrix.c present_version/third-party/lp_solve_5.5/lp_matrix.h present_version/third-party/lp_solve_5.5/lp_mipbb.c present_version/third-party/lp_solve_5.5/lp_mipbb.h present_version/third-party/lp_solve_5.5/lp_params.c present_version/third-party/lp_solve_5.5/lp_presolve.c present_version/third-party/lp_solve_5.5/lp_presolve.h present_version/third-party/lp_solve_5.5/lp_price.c present_version/third-party/lp_solve_5.5/lp_price.h present_version/third-party/lp_solve_5.5/lp_pricePSE.c present_version/third-party/lp_solve_5.5/lp_pricePSE.h present_version/third-party/lp_solve_5.5/lp_report.c present_version/third-party/lp_solve_5.5/lp_report.h present_version/third-party/lp_solve_5.5/lp_rlp.bat present_version/third-party/lp_solve_5.5/lp_rlp.c present_version/third-party/lp_solve_5.5/lp_rlp.h present_version/third-party/lp_solve_5.5/lp_rlp.l present_version/third-party/lp_solve_5.5/lp_rlp.y present_version/third-party/lp_solve_5.5/lp_scale.c present_version/third-party/lp_solve_5.5/lp_scale.h present_version/third-party/lp_solve_5.5/lp_simplex.c present_version/third-party/lp_solve_5.5/lp_simplex.h present_version/third-party/lp_solve_5.5/lp_solve/ present_version/third-party/lp_solve_5.5/lp_solve/Makefile.msc present_version/third-party/lp_solve_5.5/lp_solve/bin/ present_version/third-party/lp_solve_5.5/lp_solve/bin/win32/ present_version/third-party/lp_solve_5.5/lp_solve/bin/win64/ present_version/third-party/lp_solve_5.5/lp_solve/cbcc32.bat present_version/third-party/lp_solve_5.5/lp_solve/ccc present_version/third-party/lp_solve_5.5/lp_solve/ccc.osx present_version/third-party/lp_solve_5.5/lp_solve/cgcc.bat present_version/third-party/lp_solve_5.5/lp_solve/cvc6.bat present_version/third-party/lp_solve_5.5/lp_solve/cvc6d.bat present_version/third-party/lp_solve_5.5/lp_solve/cvc8.bat present_version/third-party/lp_solve_5.5/lp_solve/lp_solve.c present_version/third-party/lp_solve_5.5/lp_solve/lp_solve.sln present_version/third-party/lp_solve_5.5/lp_solve/lp_solve.vcproj present_version/third-party/lp_solve_5.5/lp_solve/readme.txt present_version/third-party/lp_solve_5.5/lp_solve.def present_version/third-party/lp_solve_5.5/lp_solveDLL.c present_version/third-party/lp_solve_5.5/lp_solveDLL.h present_version/third-party/lp_solve_5.5/lp_types.h present_version/third-party/lp_solve_5.5/lp_utils.c present_version/third-party/lp_solve_5.5/lp_utils.h present_version/third-party/lp_solve_5.5/lp_wlp.c present_version/third-party/lp_solve_5.5/lp_wlp.h present_version/third-party/lp_solve_5.5/lpkit.h present_versi... [truncated message content] |
From: <mio...@us...> - 2011-07-21 20:36:15
|
Revision: 255 http://pntool.svn.sourceforge.net/pntool/?rev=255&view=rev Author: miordache Date: 2011-07-21 20:36:08 +0000 (Thu, 21 Jul 2011) Log Message: ----------- Modified Paths: -------------- pnheaders/pns.c pnheaders/pns.h Modified: pnheaders/pns.c =================================================================== --- pnheaders/pns.c 2011-07-21 14:49:26 UTC (rev 254) +++ pnheaders/pns.c 2011-07-21 20:36:08 UTC (rev 255) @@ -2087,6 +2087,11 @@ return pn->t[t].l; } +inline int get_marking(pns* pn, int place) { +/* Returns the (initial) marking of the place */ + if(!pn->marking) return 0; + return pn->marking[place]; +} //========================================================================= Modified: pnheaders/pns.h =================================================================== --- pnheaders/pns.h 2011-07-21 14:49:26 UTC (rev 254) +++ pnheaders/pns.h 2011-07-21 20:36:08 UTC (rev 255) @@ -1,5 +1,5 @@ -/* PNS.H -- Version 2.2 (12/13/2010) +/* PNS.H -- Version 2.3 (July 2011) This is the main header file. It defines the data types used for Petri net representation as well as other data types used for the input specification @@ -13,8 +13,8 @@ #include<stdlib.h> #include<stdarg.h> #include<string.h> -#include "general.h" -#include "matrix.h" +#include"general.h" +#include"matrix.h" typedef struct TransInfo { @@ -138,6 +138,10 @@ /* Returns the label of t or zero if no label is defined */ +inline int get_marking(pns* pn, int place); +/* Returns the (initial) marking of the place */ + + pns createpn(const char *str, ...); /* Creates pns objects. This is the format: createpn("param1 param2 param3 ...", param1, param2, param3, ...) @@ -445,6 +449,11 @@ } specs; +int satisfied_expr(expression2 *expr); +/* Returns 1 if the expression is satisfied at the initial marking. Otherwise, + it returns 0. */ + + void extractLHCB(specs* sp, pns* pn, matrix* L, matrix* H, matrix* C, int** B); /* Extracts a SC specification of the form Lm + Hq + Cv <= B from sp. Also This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-21 14:49:32
|
Revision: 254 http://pntool.svn.sourceforge.net/pntool/?rev=254&view=rev Author: miordache Date: 2011-07-21 14:49:26 +0000 (Thu, 21 Jul 2011) Log Message: ----------- Added Paths: ----------- examples/README examples/inteq.sp Added: examples/README =================================================================== --- examples/README (rev 0) +++ examples/README 2011-07-21 14:49:26 UTC (rev 254) @@ -0,0 +1,4 @@ +Here is the list of examples: + +inteq.sp: a simple example illustrating how to write concurrent program specifications. It specifies a concurrent program for finding integer solutions to the equation w^2 = x^2 + y^2 + z^2. + Added: examples/inteq.sp =================================================================== --- examples/inteq.sp (rev 0) +++ examples/inteq.sp 2011-07-21 14:49:26 UTC (rev 254) @@ -0,0 +1,119 @@ +// inteq.hl -- a concurrent program for finding integer solutions to the +// equation w^2 = x^2 + y^2 + z^2 +// Fastest if built with the option -s2 + +thread t_one { + + /* + Let's create the following Petri net + + t3 + --->| + | + p0 t0 p1| t1 p2 + O-->|--->O-->|-->O + | | + | | + ---|<---- + t2 + */ + + places: p0 p1 p2 p3 + transitions: t0 t1 t2 t3 + + (p0, t0, p1); (p1, t3) { i > N }; (p1, t1, p2) { i <= N }; (p2, t2, p1); +} + + +thread t_calc { // The thread group used to perform the calculations + + // The PN structure used here is simpler: + + // |-->O-->|-->O-->| + // t0 p1 t1 p2 t2 + + places: p1 p2 + transitions: t0 t1 t2 + + (t0, p1); (p1, t1, p2); (p2, t2) +} + + +sync t_one.t1 t_calc.t0 +sync t_one.t2 t_calc.t1 + +initialize: t_one(p0:1) + +// Here is the code + +t_one.include { +int lo, hi, id, mx; // these are global variables +} + +t_one.main { +// here are local variables +int max = -1; +int N = -1; +int i, j; +} + +t_one.p0 { + +while(1) { + fprintf(stderr,"Enter the number of threads: "); + scanf("%d", &N); + if(N < 1 || N > 20) + fprintf(stderr,"The number must be between 1 and 20.\n"); + else + break; +} +while(1) { + fprintf(stderr,"Enter the maximum value of the variables: "); + scanf("%d", &max); + if(max < N) + fprintf(stderr,"The maximum value should be greater than %d\n", N); + else + break; +} + +j = max/N; +i = 0; mx = max; + +} // here is the end of the t_one.p0 code + + +t_one.p1 { + lo = i*j; + i++; + if(i < N) hi = i*j; + else hi = max; + id = i; +} + + +t_calc.include { +#include<math.h> +extern id, lo, hi, mx; +} + +t_calc.main { + int i, x, y, z, w, u, tid, t_lo, t_hi; +} + +t_calc.p1 { + // get parameters from t_one + tid = id; t_lo = lo; t_hi = hi; + fprintf(stderr, "Thread %d has began\n", id); fflush(0); +} + +t_calc.p2 { + for(x = t_lo; x < t_hi; x++) + for(y = x; y <= mx; y++) + for(z = y; z <= mx; z++) { + u = x*x + y*y + z*z; + w = (int) sqrt((double) u); + if(w*w == u) { + fprintf(stdout, "%d^2 = %d^2 + %d^2 + %d^2\n", w, x, y, z);fflush(0); + } + } +} \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-21 14:48:49
|
Revision: 253 http://pntool.svn.sourceforge.net/pntool/?rev=253&view=rev Author: miordache Date: 2011-07-21 14:48:43 +0000 (Thu, 21 Jul 2011) Log Message: ----------- Modified Paths: -------------- parser/read.y Modified: parser/read.y =================================================================== --- parser/read.y 2011-07-15 16:51:19 UTC (rev 252) +++ parser/read.y 2011-07-21 14:48:43 UTC (rev 253) @@ -3,7 +3,7 @@ #include "pns.h" #define YYERROR_VERBOSE 0 -#define ENABLE_ERR_MSG 1 /* set to nonzero to see error reports from bison */ +#define ENABLE_ERR_MSG 0 /* set to nonzero to see error reports from bison */ extern FILE* yyin; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-15 16:51:25
|
Revision: 252 http://pntool.svn.sourceforge.net/pntool/?rev=252&view=rev Author: miordache Date: 2011-07-15 16:51:19 +0000 (Fri, 15 Jul 2011) Log Message: ----------- Modified Paths: -------------- doc/GettingStarted.htm Modified: doc/GettingStarted.htm =================================================================== --- doc/GettingStarted.htm 2011-07-15 15:22:06 UTC (rev 251) +++ doc/GettingStarted.htm 2011-07-15 16:51:19 UTC (rev 252) @@ -26,8 +26,7 @@ <p>To create your own specification files: <ul> -<li>See the example directory of the source code. -<li>Check also input2.sp. However, note that the features of input2.sp are not fully implemented in the translator module (which is unfinished at this time) and input2.sp is not a complete description of the low level specification language. Some syntax details (such as semicolon separators and braces) are not described in this version of input2.sp. +<li>Check format2.hl for a description of the specification format. </ul> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-07-15 15:22:15
|
Revision: 251 http://pntool.svn.sourceforge.net/pntool/?rev=251&view=rev Author: miordache Date: 2011-07-15 15:22:06 +0000 (Fri, 15 Jul 2011) Log Message: ----------- new software version Modified Paths: -------------- Makefile doc/input2.sp pnheaders/general.c pnheaders/general.h pnheaders/pns.c pnheaders/pns.h Added Paths: ----------- Makefile_old.mak doc/format2.hl examples-old/ examples-old/+README+ examples-old/catandmouse.sp examples-old/loop.sp examples-old/loop3.sp examples-old/reader.sp examples-old/test.sp examples-old/test2.sp examples-old/test2a.sp examples-old/test2b.sp examples-old/test2c.sp examples-old/test2d.sp examples-old/test2e.sp examples-old/test2f.sp examples-old/test2g.sp examples-old/test3a.sp examples-old/test3b.sp examples-old/test3c.sp examples-old/test3d.sp parser/ parser/Makefile parser/actions.c parser/dict.c parser/dict.h parser/read.h parser/read.lex parser/read.y pnheaders/main_function2.c Removed Paths: ------------- examples/+README+ examples/catandmouse.sp examples/loop.sp examples/loop3.sp examples/reader.sp examples/test.sp examples/test2.sp examples/test2a.sp examples/test2b.sp examples/test2c.sp examples/test2d.sp examples/test2e.sp examples/test2f.sp examples/test2g.sp examples/test3a.sp examples/test3b.sp examples/test3c.sp examples/test3d.sp Modified: Makefile =================================================================== --- Makefile 2011-06-20 23:01:38 UTC (rev 250) +++ Makefile 2011-07-15 15:22:06 UTC (rev 251) @@ -6,11 +6,11 @@ SPNBOX=spnbox CODEGEN=newcodegen CODEGENOBJS = $(CODEGEN) -TRANSLATOR=translator +TRANSLATOR=parser -ct: objectfiles main_function.o +ct: objectfiles main_function2.o $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ - main_function.o $(SPNBOX)/*.a $(TRANSLATOR)/libtranslator.a + main_function2.o $(SPNBOX)/*.a $(TRANSLATOR)/*.o objectfiles: cd $(PNHEADERS); make @@ -18,11 +18,11 @@ cd $(SPNBOX); make cd $(TRANSLATOR); make -main_function.o: $(PNHEADERS)/main_function.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h - $(COMPILER) -c $(PNHEADERS)/main_function.c -Ispnbox -I$(CODEGEN) -I$(PNHEADERS) +main_function2.o: $(PNHEADERS)/main_function2.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function2.c -Ispnbox -I$(CODEGEN) -I$(PNHEADERS) clean: - rm -f main_function.o + rm -f main_function2.o cd $(PNHEADERS); make clean cd $(CODEGEN); make clean cd $(TRANSLATOR); make clean Copied: Makefile_old.mak (from rev 250, Makefile) =================================================================== --- Makefile_old.mak (rev 0) +++ Makefile_old.mak 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,34 @@ +# This is the make file of the old version (the one that uses the translator) + +COMPILER=gcc -g + +PNHEADERS=pnheaders +SPNBOX=spnbox +CODEGEN=newcodegen +CODEGENOBJS = $(CODEGEN) +TRANSLATOR=translator + +ct: objectfiles main_function.o + $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ + main_function.o $(SPNBOX)/*.a $(TRANSLATOR)/libtranslator.a + +objectfiles: + cd $(PNHEADERS); make + cd $(CODEGEN); make static + cd $(SPNBOX); make + cd $(TRANSLATOR); make + +main_function.o: $(PNHEADERS)/main_function.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function.c -Ispnbox -I$(CODEGEN) -I$(PNHEADERS) + +clean: + rm -f main_function.o + cd $(PNHEADERS); make clean + cd $(CODEGEN); make clean + cd $(TRANSLATOR); make clean + cd $(SPNBOX); make clean + +distclean: clean + cd $(CODEGEN); make distclean + cd $(TRANSLATOR); make distclean + Added: doc/format2.hl =================================================================== --- doc/format2.hl (rev 0) +++ doc/format2.hl 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,188 @@ +// This file describes the specification language. +// July 6, 2011. + +// In this document both threads and processes are called processes. + +// The specification describes processes and how they should be coordinated. +// The program implementing the specification consists of a coordinator +// that runs the processes described in the specification and supervises +// their execution. The coordinator is called supervisor. + +// The specification defines groups of processes. A group may have any number +// of processes (0, 1, 2, ...). This number may change during the execution of +// the program. The specification determines the initial number of processes +// in a group and how this number may change. Processes in a group are +// identical in the sense that they have the same executable code. However, +// processes in the same group do not have to be in the same stage of +// execution. + +// A group of processes is implemented by means of executable programs if +// it is defined with the keyword "process". Otherwise, it is implemented +// by means of threads of the supervisor if it is defined with the keyword +// "thread". + +// The following defines a group or processes + +process p1 { + + // The following defines the Petri net representation of the process + + places: p1 p2 p3 + transitions: t0 + transitions: t1 t2 t3 t4 + + // The following describes the arcs connecting places and transitions + + (p1, t0) + (p1, t1, p3) + + // A semicolon must be used between instructions on the same row + + (p3, t4, p1); (t3, p3) + + // The following arc is conditional. The generated program will + // contain an "if(i >= 1)" instruction before attempting to fire t2. Thus, + // the variable i must be defined in the context of the C code associated + // with the place p2. + + (p2, t2) {i >= 1} + +} + +// The following defines a group or processes implemented as threads + + +thread t1 { + + // The following defines the Petri net representation of the process + + places: p1 p2 p3 + transitions: t1 t2 t3 t4 + + // The following describes the arcs connecting places and transitions + + (p1, t1) + (p1, t2, p3) + (p3, t3, p2); (p2, t4, p1); + +} + + +// The Petri net associated with a supervisor is generated automatically. +// However, the user has the option to specify additional components to be +// included in the Petri net of the supervisor. The following block defines +// such a component. + +supervisor sc { + places: p1 p2 + transitions: t1 + + (p1, t1, p2) +} + + +// The following synchronizes the transition t1 of process p1 with the +// transition t3 of the process t1. + +sync p1.t1 t1.t3 + +// Constraints can be described by means of inequalities + +2*p1.q.t2 - t1.p3 <= 1 // firing vector element: process.q.transition + // marking vector element: process.place + +t1.v.t1 <= t1.v.t2 // Parikh vector element: process.v.transition + + +// The following describes the initial number of processes in each group. +// It also describes the stage in which each process should be started. + +initialize: p1(p1:1, p2:2) +initialize: t1(p2:1) sc(p1:5) + +// The group p1 will have three processes: one starting in p1 and two starting +// in p2. The group t1 will have only one process and that process will start +// in p2. Now, sc is not a process group but a supervisor component. The +// initialization of sc requests that the Petri net of sc will have an initial +// marking with 5 tokens in p1. + +// By default, a group of processes is initialized with zero processes. + +// Transitions that should be live can be specified as follows. +// NOTE: Avoid this instruction when possible, since the synthesis of a +// deadlock prevention policy is computationally intensive and can take much +// time. + +live: t1.t2 // the supervisor should ensure that the transition t2 of the + // process group t1 is live. + + +// The following blocks are OPTIONAL. + +// A segment of code can be associated with each place. The following +// instruction defines the code of the place p3 of the process p1. + +p1.p3 { + i = i + 1; + j = 10*i; +} + +// Any instructions that a process should execute when it is started +// can be specified by means of a main block + +p1.main { + i = 0; + j = 1; +} + +// Header files and other definitions that should appear in the source file of +// a process can be specified by means of an include block + +p1.include { + #include"string.h" + #define MAX 10 + + int i, j; + + struct myarray { int i; float k; }; + + static struct myarray array[MAX]; +} + +// Instructions on how to build the executable file associated with a process +// can be specified in a build block. Note that the software will replace $$$ +// with the name of the file defining the process (without extension). + +p1.build { gcc -g -o $$$.exe $$$.c } + +// Copies of a process group can be specified as follows + +p1c = p1 // p1c is another process group + +// Note that p1 has been defined with the keyword 'process'. Thus, p1c will +// also be of the type 'process'. If the copy should have a different type, +// the desired type should be stated before the assignment. + +thread p1c2 = p1 + +// On the line above, p1c2 is defined as a copy of p1 of the type 'thread'. + +// Instructions that the supervisor should execute when it is started +// can be specified by means of a main block + +main { + fprintf(stdout, "The supervisor is starting ..."); +} + +// An include block can also be defined for the supervisor + +include { + #define MAX_INP 3 + #include"ctype.h" +} + + +// The build block of the supervisor can be used to specify additional +// command line parameters that should be used when building the program + +build { -I. } Modified: doc/input2.sp =================================================================== --- doc/input2.sp 2011-06-20 23:01:38 UTC (rev 250) +++ doc/input2.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,4 +1,5 @@ -// This is a preliminary description of the low level specification language. +// THIS DOCUMENT DESCRIBES THE *OLD* VERSION OF THE SPECIFICATION LANGUAGE. +// SEE format2.hl FOR A DESCRIPTION OF THE CURRENT SPECIFICATION LANGUAGE. // FOR REFERENCE ONLY. ON ONE HAND, NOT ALL FEATURES HAVE BEEN IMPLEMENTED // IN THE TRANSLATOR. ON THE OTHER HAND, SOME IMPLEMENTED FEATURES ARE NOT Deleted: examples/+README+ =================================================================== --- examples/+README+ 2011-06-20 23:01:38 UTC (rev 250) +++ examples/+README+ 2011-07-15 15:22:06 UTC (rev 251) @@ -1,44 +0,0 @@ - -Here is the list of test examples: - -loop.sp: illustrates how to create loops - -loop3.sp: illustrates how to create loops and how to specify code for the main function of the generated program. - - -test2.sp: When running this example a single process (not thread) is started. The process prints messages indicating its state until it terminates. - -Variants: - -test2a.sp: a single processes (not thread) is started. - -test2b.sp: several identical processes (not threads) are started. - -test2c.sp: only one thread (not forked process) will run this time. - -test2d.sp: multiple threads (not forked processes) will run this time. - -test2e.sp: synchronization by means of transitions between single threads. - -test2f.sp: synchronization by means of transitions between multiple threads. - -test2g.sp: same as test2f.sp except for using forked processes (not threads). - - - -test3: A dining philosopher example. - -test3a.sp: Tests that the deadlock prevention function works fine when no deadlock is possible. Only one philosopher with two resources. - -test3b.sp: A test involving two philosophers. - -test3c.sp: A test involving 5 philosophers. - -test3d.sp: A test involving 5 philosophers. Here, the resources (chopsticks) are defined as supervisor components, not as threads. - - - -reader.sp: A reader, inserter, deleter problem. - - -catandmouse.sp: This is the cat and mouse maze example. Implemented by Micah Martin. Deleted: examples/catandmouse.sp =================================================================== --- examples/catandmouse.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/catandmouse.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,116 +0,0 @@ -// This is a cat and mouse room example - -process CAT; -build: {<thread>}; - -process MOUSE; -build: {<thread>}; - -CAT.PN: - -places: p1 p2 p3 p4 p5; - -transitions: c1 c2 c3 c4 c5 c6 c7 c8; - -// This function defines the places a cat can go. - -p1.code: { -// Room 1 - fprintf(stderr, "\n\nCat is in Room 1"); - sleep(1); -}; - -p2.code: { -// Room 2 - fprintf(stderr, "\n\nCat is in Room 2"); - sleep(1); -}; - -p3.code: { -// Room 3 - fprintf(stderr, "\n\nCat is in Room 3"); - sleep(1); -}; - -p4.code: { -// Room 4 - fprintf(stderr, "\n\nCat is in Room 4"); - sleep(1); -}; - -p5.code: { -// Room 5 - fprintf(stderr, "\n\nCat is in Room 5"); - sleep(1); -}; - -(p1, c1, p2); -(p2, c2, p3); -(p3, c3, p1); -(p1, c4, p4); -(p4, c5, p5); -(p5, c6, p1); -(p2, c7, p4); -(p4, c8, p2); - - -MOUSE.PN: - -places: p6 p7 p8 p9 p10; - -transitions: m1 m2 m3 m4 m5 m6; - -// This function defines the places a mouse can go. - -p6.code: { -// Room 1 - fprintf(stderr, "\n\nMouse is in Room 1"); - sleep(1); -}; - -p7.code: { -// Room 2 - fprintf(stderr, "\n\nMouse is in Room 2"); - sleep(1); -}; - -p8.code: { -// Room 3 - fprintf(stderr, "\n\nMouse is in Room 3"); - sleep(1); -}; - -p9.code: { -// Room 4 - fprintf(stderr, "\n\nMouse is in Room 4"); - sleep(1); -}; - -p10.code: { -// Room 5 - fprintf(stderr, "\n\nMouse is in Room 5"); - sleep(1); -}; - -(p6, m1, p8); -(p8, m2, p7); -(p7, m3, p6); -(p6, m4, p10); -(p10, m5, p9); -(p9, m6, p6); - - -CAT cat(p3:1); // defines one cat initialized in Room 3 -MOUSE mouse(p10:1); // defines one mouse initialized in Room 5 - - - -global.constraints: - -// No room can contain a cat and mouse simultaneously - -cat.p1 + mouse.p6 <= 1; -cat.p2 + mouse.p7 <= 1; -cat.p3 + mouse.p8 <= 1; -cat.p4 + mouse.p9 <= 1; -cat.p5 + mouse.p10 <= 1; \ No newline at end of file Deleted: examples/loop.sp =================================================================== --- examples/loop.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/loop.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,38 +0,0 @@ -// This is an example illustrating conditional transitions and loops. - - - -process MLOOP; - -build: {<thread>}; - -include: { - #include<stdio.h> - static int i = 0; // 'i' shared by threads in the same group; the 'static' - // keyword ensures that it is not visible to other threads -}; - -MLOOP.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -(p0, t0, p1); -(p1, t1, p0).{i < 4}; // Transition takes place only if i < 4. -(p1, t2).{i >= 4}; // exit via t2 if i is greater than 4. - -p0.code: { - fprintf(stderr, "\nState 0, i = %d", i); - fflush(0); - sleep(1); - i++; -}; - -p1.code: { - fprintf(stderr, "\nState 1, i = %d", i); - fflush(0); - sleep(1); -}; - -MLOOP pr1(p0:1); Deleted: examples/loop3.sp =================================================================== --- examples/loop3.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/loop3.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,159 +0,0 @@ - -process SPR; - -build: {<supervisor>}; - -include: { - #include<stdio.h> - int result, N; // these will be used as shared variable - int a[10]; // declares a shared array of 10 integers - -<main> - - // <main> indicates that what follows is part of the main function of the - // supervisor. - - N = 5; - result = 0; - - /* The following function call will execute the code of the supervisor, - which in turn will start and execute the code of the specified processes - and/or threads. */ - - ___run_supervisor(); - - // The result of the program is verified: - - printf("\nThe result is %d. The expected result was %d.\n", result, 3*N); - - // A return instruction is ESSENTIAL when the code calls - // ___run_supervisor(). Otherwise, this function will be called again by - // the default instructions of the generated code. - - return 0; -}; - - -process LOOP_1; - -build: {<thread>}; - -include: { - #include<stdio.h> - extern int result; - extern int N; - extern int a[]; - static int i; - static int j; - - // 'extern' indicates a variable defined in another C file of the project - // 'static' defines a variable invisible to the other C files of the project - -<main> // This indicates code for the main function of the thread - - fprintf(stderr, "\nA LOOP_1 thread was started."); - fflush(0); - i = 0; - -}; - - -process LOOP_2; - -build: {<thread>}; - -include: { - #include<stdio.h> - extern int result; - extern int N; - static int i; - static int j; - - // 'extern' indicates a variable defined in another C file of the project - // 'static' defines a variable invisible to the other C files of the project - -<main> // This indicates code for the main function of the thread - - fprintf(stderr, "\nA LOOP_2 thread was started."); - fflush(0); - i = 0; - -}; - - - -SPR.PN: - -places: p0; - -transitions: t0; - -(p0, t0); - - - - -LOOP_1.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -(p0, t0, p1); -(p1, t1, p0).{i < N}; // Transition takes place only if i < N. -(p1, t2).{i >= N}; // exit via t2 if i is greater than N. - -p0.code: { - fprintf(stderr, "\nLOOP_1: State 0, i = %d", i); - fflush(0); - sleep(1); - i++; -}; - -p1.code: { - j = result + 1; - fprintf(stderr, "\nLOOP_1: State 1, i = %d", i); - fflush(0); - sleep(1); - result = j; -}; - - - -LOOP_2.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -(p0, t0, p1); -(p1, t1, p0).{i < N}; // Transition takes place only if i < N. -(p1, t2).{i >= N}; // exit via t2 if i is greater than N. - -p0.code: { - fprintf(stderr, "\nLOOP_2: State 0, i = %d", i); - fflush(0); - sleep(1); - i++; -}; - -p1.code: { - j = result + 2; - fprintf(stderr, "\nLOOP_2: State 1, i = %d", i); - fflush(0); - sleep(1); - result = j; -}; - - - - - -LOOP_1 a(p0:1); -LOOP_2 b(p0:1); -SPR sp; - - -global.constraints: - -a.p1 + b.p1 <= 1; // implement mutual exclusion Deleted: examples/reader.sp =================================================================== --- examples/reader.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/reader.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,124 +0,0 @@ -// This is a reader/writer/inserter example - -process READER; -build: {<thread>}; - -process DELETER; -build: {<thread>}; - -process INSERTER; -build: {<thread>}; - -READER.PN: - -places: pv pc pd; - -transitions: tv tc td; - -// The main function for a thread/process defines a void* type pointer p___ initialized to zero. -// This is useful when several copies of a thread run in parallel, so that each thread copy -// has a known variable to allocate so that it can save its own data. Further, an initialization -// function can be called if p___ = 0. - -pv.code: { -//evaluate_data(&p___); - debugInfo("READER: Entering the evaluation block"); - sleep(1); -}; - -pc.code: { -//read_data(&p___); - debugInfo("READER: Entering the read block"); - sleep(1); - debugInfo("READER: Exiting the read block"); -}; - -pd.code: { -//process_data(&p___); - debugInfo("READER: Entering the processing block"); - sleep(1); -}; - -(pv, tv, pc); -(pc, tc, pd); -(pd, td, pv); - - -DELETER.PN: - -places: pv pc pd; - -transitions: tv tc td; - -pv.code: { -//d_evaluate_data(&p___); - debugInfo("DELETER: Entering the evaluation block"); - sleep(1); - -}; - -pc.code: { -//delete_data(&p___); - debugInfo("DELETER: Entering the read block"); - sleep(1); - debugInfo("DELETER: Exiting the read block"); - -}; - -pd.code: { -//d_process_data(&p___); - debugInfo("DELETER: Entering the processing block"); - sleep(1); - -}; - -(pv, tv, pc); -(pc, tc, pd); -(pd, td, pv); - - -INSERTER.PN: - -places: pv pc pd; - -transitions: tv tc td; - -pv.code: { -//i_evaluate_data(&p___); - debugInfo("INSERTER: Entering the evaluation block"); - sleep(1); -}; - -pc.code: { -//insert_data(&p___); - debugInfo("INSERTER: Entering the read block"); - sleep(1); - debugInfo("INSERTER: Exiting the read block"); -}; - -pd.code: { -//i_process_data(&p___); - debugInfo("INSERTER: Entering the processing block"); - sleep(1); -}; - -(pv, tv, pc); -(pc, tc, pd); -(pd, td, pv); - - -READER read(pv:5); // defines five reader processes starting in state pv -INSERTER insert(pv:3); -DELETER delete(pv:3); - - -global.constraints: - -insert.pc <= 1; - -// delete.pc <= 1; // not necessary: see constraint below - -// The following should be read.pc + insert.pc + 6*delete.pc <= 6 -// However, the translator has a bug preventing it from recognizing multipliers - -read.pc + insert.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc<= 6; // 6 is max(reader.pc + inserter.pc) Deleted: examples/test.sp =================================================================== --- examples/test.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,23 +0,0 @@ -// This is a test file created in order to check the functionality of the -// pn translator. - -process TST; - -include: { - int i; -}; - -TST.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2; - -(p0, t0); -(t2, p0); -(p1, t1, p2, p0); // this is not a state machine; -(p1, t1, p2, p0); // the code generator assumes state machines. -(p2, t2, p1).{i == 3}; - -TST testpn(p0:2,p1:1); - Deleted: examples/test2.sp =================================================================== --- examples/test2.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,126 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {gcc -g -o $$$.exe $$$.c}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN: State 0 u = %d", u); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1"); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2"); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - u++; - printf("\nPN3: State 0 u = %d", u); - delay(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - delay(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:1); - -PN3 pr2; - Deleted: examples/test2a.sp =================================================================== --- examples/test2a.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2a.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,126 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {gcc -g -o $$$.exe $$$.c}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN: State 0 u = %d", u); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1"); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2"); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - u++; - printf("\nPN3: State 0 u = %d", u); - delay(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - delay(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:1); - -PN3 pr2; - Deleted: examples/test2b.sp =================================================================== --- examples/test2b.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2b.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,126 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {gcc -g -o $$$.exe $$$.c}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN: State 0 u = %d", u); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1"); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2"); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - u++; - printf("\nPN3: State 0 u = %d", u); - delay(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - delay(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:3,p1:0,p2:0); - -PN3 pr2; - Deleted: examples/test2c.sp =================================================================== --- examples/test2c.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2c.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,126 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {<thread>}; - -include: { - #include<stdio.h> - int v = 0; - - void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN: State 0 u = %d", u); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1"); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2"); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - v--; - printf("\nPN3: State 0 v = %d", v); - delay2(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - delay2(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:1); - -PN3 pr2; - Deleted: examples/test2d.sp =================================================================== --- examples/test2d.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2d.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,126 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {<thread>}; - -include: { - #include<stdio.h> - int v = 0; - - void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN: State 0 u = %d", u); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1"); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2"); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - v--; - printf("\nPN3: State 0 v = %d", v); - delay2(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - delay2(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:4); - -PN3 pr2; - Deleted: examples/test2e.sp =================================================================== --- examples/test2e.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2e.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,134 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {<thread>}; - -include: { - #include<stdio.h> - int v = 0; - - void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN: State 0 u = %d", u); - fflush(0); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1"); - fflush(0); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2"); - fflush(0); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - v--; - printf("\nPN3: State 0 v = %d", v); - fflush(0); - delay2(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - fflush(0); - delay2(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:1); - -PN3 pr2; - -sync pr1.t1 pr2.t2; -sync pr1.t4 pr2.t2; -sync pr1.t2 pr2.t1; Deleted: examples/test2f.sp =================================================================== --- examples/test2f.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2f.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,134 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {<thread>}; - -include: { - #include<stdio.h> - int v = 0; - - void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN: State 0 u = %d", u); - fflush(0); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1"); - fflush(0); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2"); - fflush(0); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - v--; - printf("\nPN3: State 0 v = %d", v); - fflush(0); - delay2(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - fflush(0); - delay2(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:4); - -PN3 pr2; - -sync pr1.t1 pr2.t2; -sync pr1.t4 pr2.t2; -sync pr1.t2 pr2.t1; Deleted: examples/test2g.sp =================================================================== --- examples/test2g.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test2g.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,134 +0,0 @@ -// This is a test file intended to check the code generation module -// The example of this file was adapted from compexample.c - -process TYPE1; - -build: {gcc -g -o $$$.exe $$$.c}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } - - int f1(int z) { - struct ___trans ___TR[1]; - if(u > 5) { - ___TR[0].no_output = 1; - ___TR[0].label = -4; - ___TR[0].trans = 3; - } - else { - ___TR[0].no_output = 0; - ___TR[0].label = -2; - ___TR[0].trans = 1; - ___TR[0].place = 2; - } - return 1; - } -}; - - -process PN3; - -build: {gcc -g -o $$$.exe $$$.c}; - -include: { - #include<stdio.h> - int v = 0; - - void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -TYPE1.PN: - -places: p0 p1 p2; - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPN (%d): State 0 u = %d", (int) getpid(), u); - //fflush(0); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN (%d): State 1", (int) getpid()); - //fflush(0); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN (%d): State 2", (int) getpid()); - //fflush(0); - delay(1); -}; - - - // Let's create the following PN: - // - // t2 - // -------|<---- - // | p0 p1 |p2 - // ->O->|->O->|->O<-- - // | t0 | t1 | - // | | | - // | V | - // | --- t3 | - // | | - // ------>|------- - // t4 - -(p0, t4, p2); -(p1, t3); -(p2, t2, p0); -(p1, t1, p2); -(p0, t0, p1); - -PN3.PN: - -places: p0 p1; - -transitions: t0 t1 t2; - -p0.code: { - v--; - printf("\nPN3: State 0 v = %d", v); - //fflush(0); - delay2(2); -}; - -p1.code: { - printf("\nPN3: State 1"); - //fflush(0); - delay2(2); -}; - - // Let's create this PN: - // - // p0 p1 - // |->O->|->O->| - // t2 t0 t1 - // - -(t2, p0); -(p0, t0, p1); -(p1, t1); - - - -TYPE1 pr1(p0:4); - -PN3 pr2; - -sync pr1.t1 pr2.t2; -sync pr1.t4 pr2.t2; -sync pr1.t2 pr2.t1; Deleted: examples/test3a.sp =================================================================== --- examples/test3a.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test3a.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,105 +0,0 @@ -// This is a test file intended to check the code generation module - -process PHIL; - -build: {<thread>}; - -include: { - #include<stdio.h> - int pr1_state = 0, i, j, u = 0; - - void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - - -process RESOURCE; - -build: {<thread>}; - -include: { - #include<stdio.h> - static int v = 0; - - static void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -PHIL.PN: - -places: p0 p1 p2 p3; // think, request right fork, request left fork, eat - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); - fflush(0); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1 (requesting right fork)"); - fflush(0); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2 (requesting left fork)"); - fflush(0); - delay(1); -}; - -p3.code: { - fprintf(stderr, "\nPN: State 3 (eat)"); - fflush(0); - delay(1); -}; - -(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); - -// t3 -// ------------|<--------------- -// | | -// ->O-->|-->O-->|-->O-->|-->O-- -// p0 t0 p1 t1 p2 t2 p3 - - -RESOURCE.PN: - -places: p; - -transitions: t0 t2; - -// --->| t2 -// p | -// t0 |--->O -// - - -(p, t2); (t0, p); - -p.code: { - fprintf(stderr, "\nResource %s is available", ___NAME); - fflush(0); -}; - -RESOURCE left(p:1); -RESOURCE right(p:1); - -PHIL ph1(p0:1); - -sync ph1.t1 left.t2; -sync ph1.t2 right.t2; -sync ph1.t3 left.t0; -sync ph1.t3 right.t0; - -ph1.constraints: - -live: t1; Deleted: examples/test3b.sp =================================================================== --- examples/test3b.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test3b.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,113 +0,0 @@ -// This is a test file intended to check the code generation module - -process PHIL; - -build: {<thread>}; - -include: { - #include<stdio.h> - static int pr1_state = 0, i, j, u = 0; - - static void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - - -process RESOURCE; - -build: {<thread>}; - -include: { - #include<stdio.h> - static int v = 0; - - static void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -PHIL.PN: - -places: p0 p1 p2 p3; // think, request right fork, request left fork, eat - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); - fflush(0); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\nPN: State 1 (requesting right fork)"); - fflush(0); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\nPN: State 2 (requesting left fork)"); - fflush(0); - delay(1); -}; - -p3.code: { - fprintf(stderr, "\nPN: State 3 (eat)"); - fflush(0); - delay(1); -}; - -(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); - -// t3 -// ------------|<--------------- -// | | -// ->O-->|-->O-->|-->O-->|-->O-- -// p0 t0 p1 t1 p2 t2 p3 - - -RESOURCE.PN: - -places: p; - -transitions: t0 t1 t2 t3; - -// --->| t2 -// p | -// t0 |--->O<---| t1 -// | -// --->| t3 - - -(p, t2); (p, t3); (t0, p); (t1, p); - -p.code: { - fprintf(stderr, "\nResource %s is available", ___NAME); - fflush(0); -}; - -RESOURCE left(p:1); -RESOURCE right(p:1); - -PHIL ph1(p0:1); -PHIL ph2(p0:1); - -sync ph1.t1 left.t2; -sync ph2.t1 right.t2; -sync ph1.t2 right.t3; -sync ph2.t2 left.t3; -sync ph1.t3 left.t0; -sync ph1.t3 right.t0; -sync ph2.t3 left.t1; -sync ph2.t3 right.t1; - -ph1.constraints: -live: t1; - -ph2.constraints: -live: t1; \ No newline at end of file Deleted: examples/test3c.sp =================================================================== --- examples/test3c.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test3c.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,113 +0,0 @@ -// This is a test file intended to check the code generation module - -process PHIL; - -build: {<thread>}; - -include: { - #include<stdio.h> - static int pr1_state = 0, i, j, u = 0; - - static void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - - -process RESOURCE; - -build: {<thread>}; - -include: { - #include<stdio.h> - static int v = 0; - - static void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -PHIL.PN: - -places: p0 p1 p2 p3; // think, request right fork, request left fork, eat - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\n%s (%s): State 0 (think) u = %d",___INSTANCE,___NAME, u); - fflush(0); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\n%s (%s): State 1 (requesting right fork)",___INSTANCE,___NAME); - fflush(0); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\n%s (%s): State 2 (requesting left fork)",___INSTANCE,___NAME); - fflush(0); - delay(1); -}; - -p3.code: { - fprintf(stderr, "\n%s (%s): State 3 (eat)",___INSTANCE,___NAME); - fflush(0); - delay(1); -}; - -(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); - -// t3 -// ------------|<--------------- -// | | -// ->O-->|-->O-->|-->O-->|-->O-- -// p0 t0 p1 t1 p2 t2 p3 - - -RESOURCE.PN: - -places: p; - -transitions: t0 t1 t2 t3; - -// --->| t2 -// p | -// t0 |--->O<---| t1 -// | -// --->| t3 - - -(p, t2); (p, t3); (t0, p); (t1, p); - -p.code: { - fprintf(stderr, "\nResource %s is available", ___NAME); - fflush(0); -}; - -RESOURCE r1(p:1); RESOURCE r2(p:1); RESOURCE r3(p:1); RESOURCE r4(p:1); RESOURCE r5(p:1); - -PHIL ph1(p0:1); PHIL ph2(p0:1); PHIL ph3(p0:1); PHIL ph4(p0:1); PHIL ph5(p0:1); - -sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2; - -sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3; - -sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1; - -ph1.constraints: -live: t1; -ph2.constraints: -live: t1; -ph3.constraints: -live: t1; -ph4.constraints: -live: t1; -ph5.constraints: -live: t1; Deleted: examples/test3d.sp =================================================================== --- examples/test3d.sp 2011-06-20 23:01:38 UTC (rev 250) +++ examples/test3d.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -1,113 +0,0 @@ -// This is a test file intended to check the code generation module - -process PHIL; - -build: {<thread>}; - -include: { - #include<stdio.h> - static int pr1_state = 0, i, j, u = 0; - - static void delay(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - - -process RESOURCE; - -build: {<supervisor>}; // code is ignored for supervisor components - -include: { - #include<stdio.h> - static int v = 0; - - static void delay2(int n) { - time_t a, b; - for(time(&a), time(&b); a + n > b; time(&b)); - } -}; - - -PHIL.PN: - -places: p0 p1 p2 p3; // think, request right fork, request left fork, eat - -transitions: t0 t1 t2 t3 t4; - -p0.code: { - u++; - fprintf(stderr, "\n%s (%s): State 0 (think) u = %d",___INSTANCE,___NAME, u); - fflush(0); - delay(1); -}; - -p1.code: { - fprintf(stderr, "\n%s (%s): State 1 (requesting right fork)",___INSTANCE,___NAME); - fflush(0); - delay(1); -}; - -p2.code: { - fprintf(stderr, "\n%s (%s): State 2 (requesting left fork)",___INSTANCE,___NAME); - fflush(0); - delay(1); -}; - -p3.code: { - fprintf(stderr, "\n%s (%s): State 3 (eat)",___INSTANCE,___NAME); - fflush(0); - delay(1); -}; - -(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); - -// t3 -// ------------|<--------------- -// | | -// ->O-->|-->O-->|-->O-->|-->O-- -// p0 t0 p1 t1 p2 t2 p3 - - -RESOURCE.PN: - -places: p; - -transitions: t0 t1 t2 t3; - -// --->| t2 -// p | -// t0 |--->O<---| t1 -// | -// --->| t3 - - -(p, t2); (p, t3); (t0, p); (t1, p); - -p.code: { - fprintf(stderr, "\nResource %s is available", ___NAME); - fflush(0); -}; - -RESOURCE r1(p:1); RESOURCE r2(p:1); RESOURCE r3(p:1); RESOURCE r4(p:1); RESOURCE r5(p:1); - -PHIL ph1(p0:1); PHIL ph2(p0:1); PHIL ph3(p0:1); PHIL ph4(p0:1); PHIL ph5(p0:1); - -sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2; - -sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3; - -sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1; - -ph1.constraints: -live: t1; -ph2.constraints: -live: t1; -ph3.constraints: -live: t1; -ph4.constraints: -live: t1; -ph5.constraints: -live: t1; Copied: examples-old/+README+ (from rev 250, examples/+README+) =================================================================== --- examples-old/+README+ (rev 0) +++ examples-old/+README+ 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,44 @@ + +Here is the list of test examples: + +loop.sp: illustrates how to create loops + +loop3.sp: illustrates how to create loops and how to specify code for the main function of the generated program. + + +test2.sp: When running this example a single process (not thread) is started. The process prints messages indicating its state until it terminates. + +Variants: + +test2a.sp: a single processes (not thread) is started. + +test2b.sp: several identical processes (not threads) are started. + +test2c.sp: only one thread (not forked process) will run this time. + +test2d.sp: multiple threads (not forked processes) will run this time. + +test2e.sp: synchronization by means of transitions between single threads. + +test2f.sp: synchronization by means of transitions between multiple threads. + +test2g.sp: same as test2f.sp except for using forked processes (not threads). + + + +test3: A dining philosopher example. + +test3a.sp: Tests that the deadlock prevention function works fine when no deadlock is possible. Only one philosopher with two resources. + +test3b.sp: A test involving two philosophers. + +test3c.sp: A test involving 5 philosophers. + +test3d.sp: A test involving 5 philosophers. Here, the resources (chopsticks) are defined as supervisor components, not as threads. + + + +reader.sp: A reader, inserter, deleter problem. + + +catandmouse.sp: This is the cat and mouse maze example. Implemented by Micah Martin. Copied: examples-old/catandmouse.sp (from rev 250, examples/catandmouse.sp) =================================================================== --- examples-old/catandmouse.sp (rev 0) +++ examples-old/catandmouse.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,116 @@ +// This is a cat and mouse room example + +process CAT; +build: {<thread>}; + +process MOUSE; +build: {<thread>}; + +CAT.PN: + +places: p1 p2 p3 p4 p5; + +transitions: c1 c2 c3 c4 c5 c6 c7 c8; + +// This function defines the places a cat can go. + +p1.code: { +// Room 1 + fprintf(stderr, "\n\nCat is in Room 1"); + sleep(1); +}; + +p2.code: { +// Room 2 + fprintf(stderr, "\n\nCat is in Room 2"); + sleep(1); +}; + +p3.code: { +// Room 3 + fprintf(stderr, "\n\nCat is in Room 3"); + sleep(1); +}; + +p4.code: { +// Room 4 + fprintf(stderr, "\n\nCat is in Room 4"); + sleep(1); +}; + +p5.code: { +// Room 5 + fprintf(stderr, "\n\nCat is in Room 5"); + sleep(1); +}; + +(p1, c1, p2); +(p2, c2, p3); +(p3, c3, p1); +(p1, c4, p4); +(p4, c5, p5); +(p5, c6, p1); +(p2, c7, p4); +(p4, c8, p2); + + +MOUSE.PN: + +places: p6 p7 p8 p9 p10; + +transitions: m1 m2 m3 m4 m5 m6; + +// This function defines the places a mouse can go. + +p6.code: { +// Room 1 + fprintf(stderr, "\n\nMouse is in Room 1"); + sleep(1); +}; + +p7.code: { +// Room 2 + fprintf(stderr, "\n\nMouse is in Room 2"); + sleep(1); +}; + +p8.code: { +// Room 3 + fprintf(stderr, "\n\nMouse is in Room 3"); + sleep(1); +}; + +p9.code: { +// Room 4 + fprintf(stderr, "\n\nMouse is in Room 4"); + sleep(1); +}; + +p10.code: { +// Room 5 + fprintf(stderr, "\n\nMouse is in Room 5"); + sleep(1); +}; + +(p6, m1, p8); +(p8, m2, p7); +(p7, m3, p6); +(p6, m4, p10); +(p10, m5, p9); +(p9, m6, p6); + + +CAT cat(p3:1); // defines one cat initialized in Room 3 +MOUSE mouse(p10:1); // defines one mouse initialized in Room 5 + + + +global.constraints: + +// No room can contain a cat and mouse simultaneously + +cat.p1 + mouse.p6 <= 1; +cat.p2 + mouse.p7 <= 1; +cat.p3 + mouse.p8 <= 1; +cat.p4 + mouse.p9 <= 1; +cat.p5 + mouse.p10 <= 1; \ No newline at end of file Copied: examples-old/loop.sp (from rev 250, examples/loop.sp) =================================================================== --- examples-old/loop.sp (rev 0) +++ examples-old/loop.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,38 @@ +// This is an example illustrating conditional transitions and loops. + + + +process MLOOP; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int i = 0; // 'i' shared by threads in the same group; the 'static' + // keyword ensures that it is not visible to other threads +}; + +MLOOP.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +(p0, t0, p1); +(p1, t1, p0).{i < 4}; // Transition takes place only if i < 4. +(p1, t2).{i >= 4}; // exit via t2 if i is greater than 4. + +p0.code: { + fprintf(stderr, "\nState 0, i = %d", i); + fflush(0); + sleep(1); + i++; +}; + +p1.code: { + fprintf(stderr, "\nState 1, i = %d", i); + fflush(0); + sleep(1); +}; + +MLOOP pr1(p0:1); Copied: examples-old/loop3.sp (from rev 250, examples/loop3.sp) =================================================================== --- examples-old/loop3.sp (rev 0) +++ examples-old/loop3.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,159 @@ + +process SPR; + +build: {<supervisor>}; + +include: { + #include<stdio.h> + int result, N; // these will be used as shared variable + int a[10]; // declares a shared array of 10 integers + +<main> + + // <main> indicates that what follows is part of the main function of the + // supervisor. + + N = 5; + result = 0; + + /* The following function call will execute the code of the supervisor, + which in turn will start and execute the code of the specified processes + and/or threads. */ + + ___run_supervisor(); + + // The result of the program is verified: + + printf("\nThe result is %d. The expected result was %d.\n", result, 3*N); + + // A return instruction is ESSENTIAL when the code calls + // ___run_supervisor(). Otherwise, this function will be called again by + // the default instructions of the generated code. + + return 0; +}; + + +process LOOP_1; + +build: {<thread>}; + +include: { + #include<stdio.h> + extern int result; + extern int N; + extern int a[]; + static int i; + static int j; + + // 'extern' indicates a variable defined in another C file of the project + // 'static' defines a variable invisible to the other C files of the project + +<main> // This indicates code for the main function of the thread + + fprintf(stderr, "\nA LOOP_1 thread was started."); + fflush(0); + i = 0; + +}; + + +process LOOP_2; + +build: {<thread>}; + +include: { + #include<stdio.h> + extern int result; + extern int N; + static int i; + static int j; + + // 'extern' indicates a variable defined in another C file of the project + // 'static' defines a variable invisible to the other C files of the project + +<main> // This indicates code for the main function of the thread + + fprintf(stderr, "\nA LOOP_2 thread was started."); + fflush(0); + i = 0; + +}; + + + +SPR.PN: + +places: p0; + +transitions: t0; + +(p0, t0); + + + + +LOOP_1.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +(p0, t0, p1); +(p1, t1, p0).{i < N}; // Transition takes place only if i < N. +(p1, t2).{i >= N}; // exit via t2 if i is greater than N. + +p0.code: { + fprintf(stderr, "\nLOOP_1: State 0, i = %d", i); + fflush(0); + sleep(1); + i++; +}; + +p1.code: { + j = result + 1; + fprintf(stderr, "\nLOOP_1: State 1, i = %d", i); + fflush(0); + sleep(1); + result = j; +}; + + + +LOOP_2.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +(p0, t0, p1); +(p1, t1, p0).{i < N}; // Transition takes place only if i < N. +(p1, t2).{i >= N}; // exit via t2 if i is greater than N. + +p0.code: { + fprintf(stderr, "\nLOOP_2: State 0, i = %d", i); + fflush(0); + sleep(1); + i++; +}; + +p1.code: { + j = result + 2; + fprintf(stderr, "\nLOOP_2: State 1, i = %d", i); + fflush(0); + sleep(1); + result = j; +}; + + + + + +LOOP_1 a(p0:1); +LOOP_2 b(p0:1); +SPR sp; + + +global.constraints: + +a.p1 + b.p1 <= 1; // implement mutual exclusion Copied: examples-old/reader.sp (from rev 250, examples/reader.sp) =================================================================== --- examples-old/reader.sp (rev 0) +++ examples-old/reader.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,124 @@ +// This is a reader/writer/inserter example + +process READER; +build: {<thread>}; + +process DELETER; +build: {<thread>}; + +process INSERTER; +build: {<thread>}; + +READER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +// The main function for a thread/process defines a void* type pointer p___ initialized to zero. +// This is useful when several copies of a thread run in parallel, so that each thread copy +// has a known variable to allocate so that it can save its own data. Further, an initialization +// function can be called if p___ = 0. + +pv.code: { +//evaluate_data(&p___); + debugInfo("READER: Entering the evaluation block"); + sleep(1); +}; + +pc.code: { +//read_data(&p___); + debugInfo("READER: Entering the read block"); + sleep(1); + debugInfo("READER: Exiting the read block"); +}; + +pd.code: { +//process_data(&p___); + debugInfo("READER: Entering the processing block"); + sleep(1); +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +DELETER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +pv.code: { +//d_evaluate_data(&p___); + debugInfo("DELETER: Entering the evaluation block"); + sleep(1); + +}; + +pc.code: { +//delete_data(&p___); + debugInfo("DELETER: Entering the read block"); + sleep(1); + debugInfo("DELETER: Exiting the read block"); + +}; + +pd.code: { +//d_process_data(&p___); + debugInfo("DELETER: Entering the processing block"); + sleep(1); + +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +INSERTER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +pv.code: { +//i_evaluate_data(&p___); + debugInfo("INSERTER: Entering the evaluation block"); + sleep(1); +}; + +pc.code: { +//insert_data(&p___); + debugInfo("INSERTER: Entering the read block"); + sleep(1); + debugInfo("INSERTER: Exiting the read block"); +}; + +pd.code: { +//i_process_data(&p___); + debugInfo("INSERTER: Entering the processing block"); + sleep(1); +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +READER read(pv:5); // defines five reader processes starting in state pv +INSERTER insert(pv:3); +DELETER delete(pv:3); + + +global.constraints: + +insert.pc <= 1; + +// delete.pc <= 1; // not necessary: see constraint below + +// The following should be read.pc + insert.pc + 6*delete.pc <= 6 +// However, the translator has a bug preventing it from recognizing multipliers + +read.pc + insert.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc<= 6; // 6 is max(reader.pc + inserter.pc) Copied: examples-old/test.sp (from rev 250, examples/test.sp) =================================================================== --- examples-old/test.sp (rev 0) +++ examples-old/test.sp 2011-07-15 15:22:06 UTC (rev 251) @@ -0,0 +1,23 @@ +// This is a test file created in order to check the functionality of the +// pn translator. + +process TST; + +include: { + int i; +}; + +TST.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2; + +(p0, t0); +(t2, p0); +(p1, t1, p2, p0); // this is not a state machine; +(p1, t1, p2, p0); // the code generator assumes state machines. +(p2, t2, p1).{i == 3}; + +TST testpn(p0:2,p1:1); + Copied: examples-old/test2.sp (from rev 250, examples/test2.sp) =================================================================== --- examples-old/test2.sp ... [truncated message content] |
From: <mio...@us...> - 2011-06-20 23:01:47
|
Revision: 250 http://pntool.svn.sourceforge.net/pntool/?rev=250&view=rev Author: miordache Date: 2011-06-20 23:01:38 +0000 (Mon, 20 Jun 2011) Log Message: ----------- enhancements Modified Paths: -------------- examples/+README+ examples/test.sp newcodegen/ProcessTemplate.c newcodegen/SupervisorTemplate.c newcodegen/codegen.h newcodegen/filltmpl.lex newcodegen/plantCompiler.c newcodegen/spcommon.h newcodegen/supervisorCompiler.c pnheaders/general.c pnheaders/general.h pnheaders/main_function.c pnheaders/pns.c pnheaders/pns.h translator/Makefile translator/dataStructures.h translator/main.c Added Paths: ----------- examples/catandmouse.sp examples/loop.sp examples/loop3.sp Modified: examples/+README+ =================================================================== --- examples/+README+ 2011-05-17 13:45:15 UTC (rev 249) +++ examples/+README+ 2011-06-20 23:01:38 UTC (rev 250) @@ -1,6 +1,11 @@ Here is the list of test examples: +loop.sp: illustrates how to create loops + +loop3.sp: illustrates how to create loops and how to specify code for the main function of the generated program. + + test2.sp: When running this example a single process (not thread) is started. The process prints messages indicating its state until it terminates. Variants: @@ -34,3 +39,6 @@ reader.sp: A reader, inserter, deleter problem. + + +catandmouse.sp: This is the cat and mouse maze example. Implemented by Micah Martin. Added: examples/catandmouse.sp =================================================================== --- examples/catandmouse.sp (rev 0) +++ examples/catandmouse.sp 2011-06-20 23:01:38 UTC (rev 250) @@ -0,0 +1,116 @@ +// This is a cat and mouse room example + +process CAT; +build: {<thread>}; + +process MOUSE; +build: {<thread>}; + +CAT.PN: + +places: p1 p2 p3 p4 p5; + +transitions: c1 c2 c3 c4 c5 c6 c7 c8; + +// This function defines the places a cat can go. + +p1.code: { +// Room 1 + fprintf(stderr, "\n\nCat is in Room 1"); + sleep(1); +}; + +p2.code: { +// Room 2 + fprintf(stderr, "\n\nCat is in Room 2"); + sleep(1); +}; + +p3.code: { +// Room 3 + fprintf(stderr, "\n\nCat is in Room 3"); + sleep(1); +}; + +p4.code: { +// Room 4 + fprintf(stderr, "\n\nCat is in Room 4"); + sleep(1); +}; + +p5.code: { +// Room 5 + fprintf(stderr, "\n\nCat is in Room 5"); + sleep(1); +}; + +(p1, c1, p2); +(p2, c2, p3); +(p3, c3, p1); +(p1, c4, p4); +(p4, c5, p5); +(p5, c6, p1); +(p2, c7, p4); +(p4, c8, p2); + + +MOUSE.PN: + +places: p6 p7 p8 p9 p10; + +transitions: m1 m2 m3 m4 m5 m6; + +// This function defines the places a mouse can go. + +p6.code: { +// Room 1 + fprintf(stderr, "\n\nMouse is in Room 1"); + sleep(1); +}; + +p7.code: { +// Room 2 + fprintf(stderr, "\n\nMouse is in Room 2"); + sleep(1); +}; + +p8.code: { +// Room 3 + fprintf(stderr, "\n\nMouse is in Room 3"); + sleep(1); +}; + +p9.code: { +// Room 4 + fprintf(stderr, "\n\nMouse is in Room 4"); + sleep(1); +}; + +p10.code: { +// Room 5 + fprintf(stderr, "\n\nMouse is in Room 5"); + sleep(1); +}; + +(p6, m1, p8); +(p8, m2, p7); +(p7, m3, p6); +(p6, m4, p10); +(p10, m5, p9); +(p9, m6, p6); + + +CAT cat(p3:1); // defines one cat initialized in Room 3 +MOUSE mouse(p10:1); // defines one mouse initialized in Room 5 + + + +global.constraints: + +// No room can contain a cat and mouse simultaneously + +cat.p1 + mouse.p6 <= 1; +cat.p2 + mouse.p7 <= 1; +cat.p3 + mouse.p8 <= 1; +cat.p4 + mouse.p9 <= 1; +cat.p5 + mouse.p10 <= 1; \ No newline at end of file Added: examples/loop.sp =================================================================== --- examples/loop.sp (rev 0) +++ examples/loop.sp 2011-06-20 23:01:38 UTC (rev 250) @@ -0,0 +1,38 @@ +// This is an example illustrating conditional transitions and loops. + + + +process MLOOP; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int i = 0; // 'i' shared by threads in the same group; the 'static' + // keyword ensures that it is not visible to other threads +}; + +MLOOP.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +(p0, t0, p1); +(p1, t1, p0).{i < 4}; // Transition takes place only if i < 4. +(p1, t2).{i >= 4}; // exit via t2 if i is greater than 4. + +p0.code: { + fprintf(stderr, "\nState 0, i = %d", i); + fflush(0); + sleep(1); + i++; +}; + +p1.code: { + fprintf(stderr, "\nState 1, i = %d", i); + fflush(0); + sleep(1); +}; + +MLOOP pr1(p0:1); Added: examples/loop3.sp =================================================================== --- examples/loop3.sp (rev 0) +++ examples/loop3.sp 2011-06-20 23:01:38 UTC (rev 250) @@ -0,0 +1,159 @@ + +process SPR; + +build: {<supervisor>}; + +include: { + #include<stdio.h> + int result, N; // these will be used as shared variable + int a[10]; // declares a shared array of 10 integers + +<main> + + // <main> indicates that what follows is part of the main function of the + // supervisor. + + N = 5; + result = 0; + + /* The following function call will execute the code of the supervisor, + which in turn will start and execute the code of the specified processes + and/or threads. */ + + ___run_supervisor(); + + // The result of the program is verified: + + printf("\nThe result is %d. The expected result was %d.\n", result, 3*N); + + // A return instruction is ESSENTIAL when the code calls + // ___run_supervisor(). Otherwise, this function will be called again by + // the default instructions of the generated code. + + return 0; +}; + + +process LOOP_1; + +build: {<thread>}; + +include: { + #include<stdio.h> + extern int result; + extern int N; + extern int a[]; + static int i; + static int j; + + // 'extern' indicates a variable defined in another C file of the project + // 'static' defines a variable invisible to the other C files of the project + +<main> // This indicates code for the main function of the thread + + fprintf(stderr, "\nA LOOP_1 thread was started."); + fflush(0); + i = 0; + +}; + + +process LOOP_2; + +build: {<thread>}; + +include: { + #include<stdio.h> + extern int result; + extern int N; + static int i; + static int j; + + // 'extern' indicates a variable defined in another C file of the project + // 'static' defines a variable invisible to the other C files of the project + +<main> // This indicates code for the main function of the thread + + fprintf(stderr, "\nA LOOP_2 thread was started."); + fflush(0); + i = 0; + +}; + + + +SPR.PN: + +places: p0; + +transitions: t0; + +(p0, t0); + + + + +LOOP_1.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +(p0, t0, p1); +(p1, t1, p0).{i < N}; // Transition takes place only if i < N. +(p1, t2).{i >= N}; // exit via t2 if i is greater than N. + +p0.code: { + fprintf(stderr, "\nLOOP_1: State 0, i = %d", i); + fflush(0); + sleep(1); + i++; +}; + +p1.code: { + j = result + 1; + fprintf(stderr, "\nLOOP_1: State 1, i = %d", i); + fflush(0); + sleep(1); + result = j; +}; + + + +LOOP_2.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +(p0, t0, p1); +(p1, t1, p0).{i < N}; // Transition takes place only if i < N. +(p1, t2).{i >= N}; // exit via t2 if i is greater than N. + +p0.code: { + fprintf(stderr, "\nLOOP_2: State 0, i = %d", i); + fflush(0); + sleep(1); + i++; +}; + +p1.code: { + j = result + 2; + fprintf(stderr, "\nLOOP_2: State 1, i = %d", i); + fflush(0); + sleep(1); + result = j; +}; + + + + + +LOOP_1 a(p0:1); +LOOP_2 b(p0:1); +SPR sp; + + +global.constraints: + +a.p1 + b.p1 <= 1; // implement mutual exclusion Modified: examples/test.sp =================================================================== --- examples/test.sp 2011-05-17 13:45:15 UTC (rev 249) +++ examples/test.sp 2011-06-20 23:01:38 UTC (rev 250) @@ -1,7 +1,7 @@ // This is a test file created in order to check the functionality of the // pn translator. -process TST +process TST; include: { int i; Modified: newcodegen/ProcessTemplate.c =================================================================== --- newcodegen/ProcessTemplate.c 2011-05-17 13:45:15 UTC (rev 249) +++ newcodegen/ProcessTemplate.c 2011-06-20 23:01:38 UTC (rev 250) @@ -7,6 +7,7 @@ #include<pthread.h> #include<limits.h> #include<sys/types.h> +#include<signal.h> #ifdef ___PROCESS int ___debug = 0; // value determined by parameters of main function @@ -18,6 +19,16 @@ static void* ___main_function(void* ___v); +#ifdef ___PROCESS +inline void ___pr_send_signal() { +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + kill(getppid(), SIGUSR1); +#endif +#endif +} +#endif + // +++++++ OTHER DECLARATIONS (GENERATED CODE HERE) @@ -32,6 +43,10 @@ #endif + +// ++++++++++++++++++++++++++ USER CODE--DECLARATIONS (GENERATED CODE HERE) + + static void* ___main_function(void* ___v) { int ___i, ___j, ___flag, ___ntran; time_t ___ctime; @@ -47,12 +62,12 @@ int ___place; // denotes the value of the current place int ___finish; // the program terminates when its value is nonzero + sigset_t ___set; // set of signals that should be blocked ___finish = 0; ___flag = 0; ___place = ___pthr->state; - // !!! To define communication parameters ... time(&___ctime);//___ctime used to initialize the random number generator // Next, ___ctime is modified so that different processes started at the @@ -62,9 +77,19 @@ ___ctime += (int) getpid(); #else ___ctime += (int) getpid() + (int)___pthr->id; + #ifndef SINGLE_READ_CHANNEL + // block SIGUSR1 which may be used to notify main program of new messages + sigemptyset(&___set); + sigaddset(&___set, SIGUSR1); + pthread_sigmask(SIG_BLOCK, &___set, 0); + #endif #endif srand(___ctime%64000); + + // +++++++++++++++++++ USER CODE--MAIN FUNCTION (GENERATED CODE HERE) + + while(!___finish) { switch(___place) { @@ -156,8 +181,6 @@ int main(int argc, char* argv[]) { - // Update to read from pipe parameters! See ___upd_comm_param - int ___i, ___j, ___flag = 0, ___vplace; char* ___str; struct ___thread_data *___pthr = 0; Modified: newcodegen/SupervisorTemplate.c =================================================================== --- newcodegen/SupervisorTemplate.c 2011-05-17 13:45:15 UTC (rev 249) +++ newcodegen/SupervisorTemplate.c 2011-06-20 23:01:38 UTC (rev 250) @@ -1,8 +1,6 @@ // TO DO: check pipe size and adjust it if necessary or terminate if impossible -// enable SIGPIPE for sread pipe of supervisor. +// Enable SIGIO for sread pipe of supervisor. O_ASYNC would be used. // use fcntl for both -// The plant must use fcntl so that its write is not blocked! -// Plant: Blocking read, nonblocking write! // // Note: read() from pipe with O_NOBLOCK set returns 0 if the sender has closed // its end of the pipe or -1 and errno = EAGAIN if the pipe is empty. @@ -16,8 +14,6 @@ // of data as they arrive, and one integer indicating how many bytes are in the // buffer. // -// The plant should send a notification message to the supervisor when terminating. -// // The debugInfo of the supervisor should use a lock. #define ___SUPERVISOR @@ -32,21 +28,26 @@ #include<fcntl.h> #include<signal.h> + #define MSG_READ_LIMIT 10 // max number of messages read from a single process during an iteration char ___debug; // value determined by parameters of main function int ___finish; // the program terminates when its value is nonzero pid_t ___pid; -pthread_t ___tid; +pthread_t ___tid; // thread id of the main program FILE* ___f; char* ___name; + #include"spcommon.h" // The following is used for unnamed pipe communication between plant // and supervisor. +int ___read_ch, ___write_ch; // the read and write ends of the pipe to which +// plant components write. + struct ___comm { int sread, swrite; int pread, pwrite; @@ -165,20 +166,33 @@ const int *oweight; // vector of nopl elements }; +static char ___no_msg; // indicates absence of plant messages in main function +static sigset_t ___set; // set of signals that may be blocked by main thread +static unsigned char ___start_flag; // used in the main function + +int ___run_supervisor(); // this is the main function of the sup. program + + // +++++++ OTHER DECLARATIONS (GENERATED CODE HERE) -// default values included below for debugging puroposes -#ifndef n___prtypes -#define n___prtypes 1 -#endif -struct proc *___prtype[n___prtypes]; +struct proc *___prtype[n___prtypes]; // n___prtypes defined in generated code -int ___marking[___pnum]; // supervisor marking +int ___marking[___pnum]; // supervisor marking; ___pnum defined in gen. code +inline void ___th_send_signal() { +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + if(pthread_self() != ___tid) + pthread_kill(___tid, SIGUSR1); +// it may be that all threads receive the signal, though handler executed only by ___tid +#endif +#endif +} + inline int ___is_enabled(int ___t) { // checks whether ___t is enabled int ___i, ___nipl; const int *___iplace, *___iweight; @@ -472,6 +486,14 @@ return 0; } + +#ifdef SINGLE_READ_CHANNEL + + ___p->sread = ___read_ch; + ___p->pwrite = ___write_ch; + +#else + ___p->sread = ___ip[0]; ___p->pwrite = ___ip[1]; @@ -483,12 +505,15 @@ return 0; } + fcntl( ___p->sread, F_SETFL, O_NONBLOCK); // supervisor has nonblocking read + fcntl( ___p->pwrite, F_SETFL, O_NONBLOCK); // plant has nonblocking write + +#endif + ___p->swrite = ___ip[1]; ___p->pread = ___ip[0]; - fcntl( ___p->sread, F_SETFL, O_NONBLOCK); - fcntl( ___p->swrite, F_SETFL, O_NONBLOCK); - fcntl( ___p->pwrite, F_SETFL, O_NONBLOCK); + fcntl( ___p->swrite, F_SETFL, O_NONBLOCK); // sup. has nonblocking write return ___p; } @@ -538,10 +563,18 @@ void ___free_comm(struct ___comm *___pc) { if(___pc) { + +#ifdef SINGLE_READ_CHANNEL + close(___pc->swrite); + if( ! ___pc->pclosed ) // plant end of pipes already closed for processes + close(___pc->pread); // line reached in the case of threads +#else close(___pc->sread); close(___pc->swrite); - if( ! ___pc->pclosed ) { + if( ! ___pc->pclosed ) {// plant end of pipes already closed for processes close(___pc->pread); close(___pc->pwrite); } +#endif + free(___pc); } } @@ -652,14 +685,19 @@ for(___pa = ___prlist; ___pa; ___pa = ___pa->next_in_prlist) { if(___pa == ___p) continue; + +#ifndef SINGLE_READ_CHANNEL close(((struct ___comm*)___pa->comm)->sread); +#endif close(((struct ___comm*)___pa->comm)->swrite); } return 1; } else { // if this is the supervisor process close(((struct ___comm*)___p->comm)->pread); +#ifndef SINGLE_READ_CHANNEL close(((struct ___comm*)___p->comm)->pwrite); +#endif ((struct ___comm*)___p->comm)->pclosed = 1; // send parameters to child process @@ -702,7 +740,7 @@ } -struct proc* ___StartProcess(int ___type, int ___where) { +inline struct proc* ___StartProcess_sub(int ___type, int ___where) { struct proc *___pr; int ___i; struct ___thread_data *___pthr; @@ -778,8 +816,30 @@ +struct proc* ___StartProcess(int ___type, int ___where) { + struct proc* ___p; + +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + pthread_sigmask(SIG_BLOCK, &___set, 0); +#endif +#endif + + ___p = ___StartProcess_sub(___type, ___where); + +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + pthread_sigmask(SIG_UNBLOCK, &___set, 0); +#endif +#endif + + return ___p; +} + + void ___finish_sig_handler(int ___sig) { struct proc* ___p; + void* ___v; if(getpid() != ___pid) exit(EXIT_FAILURE); @@ -787,18 +847,59 @@ pthread_exit(0); else { debugInfo("A signal has been received and the program will be terminated"); - for(___p = ___prlist; ___p; ___p = ___p->next_in_prlist) - ___terminate_process(___p); // also calls___free_proc(___p); - exit(EXIT_SUCCESS); + for(___p = ___prlist; ___p; ___p = ___p->next_in_prlist) { + //___terminate_process(___p); // also calls ___free_proc(___p); + if(___p->pid) // then this is a forked process + kill(___p->pid, SIGTERM); + /*else { // then this is a thread + pthread_kill(___p->thread_id, SIGINT); + pthread_join(___p->thread_id, &___v); // wait for it to terminate + }*/ + ___free_proc(___p); + } + debugInfo("The program is terminating ... "); + //sleep(1); + raise(SIGTERM); + //exit(EXIT_SUCCESS); } } +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + +void ___newmsg_sig_handler(int ___sig) { + + debugInfo("SIGUSR1 received"); + if(getpid() == ___pid) + if(pthread_self() == ___tid) + ___no_msg = 0; + return; +} + +#endif +#endif + + inline int ___check_for_msg(struct proc *___p, struct ___msg *p___ms) { // The function returns 0 if there are no messages + int ___i; - return ___get_msg(((struct ___comm*)___p->comm)->sread, p___ms, \ - sizeof(*p___ms), debugInfo); + // Block signals while receiving data + +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + pthread_sigmask(SIG_BLOCK, &___set, 0); +#endif +#endif + ___i = ___get_msg(((struct ___comm*)___p->comm)->sread, p___ms, \ + sizeof(*p___ms), debugInfo); +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + pthread_sigmask(SIG_UNBLOCK, &___set, 0); +#endif +#endif + return ___i; } @@ -937,28 +1038,39 @@ inline void ___send_permission_msg(struct proc *___p) { +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + pthread_sigmask(SIG_BLOCK, &___set, 0); +#endif +#endif + ___send_msg(&___p->fireable, sizeof(int), ((struct ___comm*)___p->comm)->swrite, debugInfo); +#ifndef SINGLE_READ_CHANNEL +#ifdef ___SIGNALS + pthread_sigmask(SIG_UNBLOCK, &___set, 0); +#endif +#endif + } -int main(int argc, char* argv[]) { - int ___i, ___j, ___a; - char* ___str, ___no_msg, ___start_flag; + +// Define the main function of the supervisor program + +int ___run_supervisor() { + int ___i, ___j, ___a, ___ip[2]; + long ___def_flags; struct proc *___p, *___pa, *___pn; struct sigaction ___act; struct ___msg ___ms; time_t ___ctime; - char ___help_msg[] = "\nOptions: \n\ - -e: suppress error and status messages\n\ - -s: start the program right away without displaying introductory message\n\n\ - Ctrl-C (SIGINT) can be used to stop the program. This will terminate all\n\ - its processes.\n"; + ___pid = getpid(); ___tid = pthread_self(); - ___debug = 0; + //___debug = 0; ___finish = 0; ___f = stderr; ___name = 0; @@ -973,46 +1085,31 @@ ___act.sa_handler = ___finish_sig_handler; sigaction(SIGINT, &___act, 0); // initialize act +#ifdef SINGLE_READ_CHANNEL + + if (pipe(___ip) == -1) { + debugInfo("Could not open unnamed pipes"); + return 1; + } + ___read_ch = ___ip[0]; // read end of supervisor + ___write_ch = ___ip[1]; // write end of plant components + ___def_flags = fcntl(___read_ch, F_GETFL); +#else +#ifdef ___SIGNALS + sigaction(SIGUSR1, 0, &___act); // initialize act + ___act.sa_flags = SA_RESTART; + ___act.sa_handler = ___newmsg_sig_handler; + sigaction(SIGUSR1, &___act, 0); // initialize act + sigemptyset(&___set); + sigaddset(&___set, SIGUSR1); +#endif +#endif + time(&___ctime); srand(___ctime%64000); - ___debug = 1; - ___start_flag = (argc <= 1); - for(___i = 1; ___i < argc; ___i++) { - if(!strcmp(argv[___i], "-e")) - ___debug = 0; - else if(!strcmp(argv[___i], "-h") || !strcmp(argv[___i], "--help")) { - fprintf(stdout, ___help_msg); - return 0; - } - else if(!strcmp(argv[___i], "-s")) { - ___start_flag = 0; // "-s" is for future use; unnecessary right now - } - } - if(___start_flag) { - fprintf(stdout, "%s\nThe program will start in five seconds.\n", ___help_msg); - sleep(5); - } - if(___debug) { - if(argc <= 1) - debugInfo("The main function was entered. The main functions has no parameters."); - else { - for(___i = 0, ___j = 0; ___i < argc; ___i++) - ___j += strlen(argv[___i]); - ___j += argc + 1; - ___str = malloc(___j*sizeof(char)); - for(___i = 0, ___j = 0; ___i < argc - 1; ___i++) { - sprintf(___str + ___j, "%s ", argv[___i]); - ___j += strlen(argv[___i]) + 1; - } - sprintf(___str + ___j, "%s", argv[___i]); - debugInfo("The process was started with the following command line\n\t%s", ___str); - free(___str); - } - } - // initialize supervisor ___marking memset(___marking, 0, sizeof(*___marking)*___pnum); for(___i = 0; ___i < n___m0; ___i++) @@ -1032,10 +1129,21 @@ // Check all processes for new messages +#ifdef SINGLE_READ_CHANNEL + fcntl(___read_ch, F_SETFL, ___def_flags); // next read will be blocking + for(___i = 0; ___i < MSG_READ_LIMIT; ___i++) { + ___j = ___get_msg(___read_ch, &___ms, sizeof(___ms), debugInfo); + if(!___j) + break; // exit loop since there are no more messages + ___process_msg(&___ms); + if(!___i) + fcntl(___read_ch, F_SETFL, O_NONBLOCK); // next reads nonblocking + } +#else for(___p = ___prlist, ___no_msg = 1; ___p; ___p = ___pn) { ___pn = ___p->next_in_prlist; // process_msg below may deallocate ___p for(___i = 0; ___i < MSG_READ_LIMIT; ___i++) { - ___j = ___check_for_msg(___p, &___ms); + ___j = ___check_for_msg(___p, &___ms); if( ! ___j ) break; // exit loop, since there are no messages ___no_msg = 0; @@ -1044,10 +1152,13 @@ } } - if(___no_msg) { - sleep(2); // any interrupt will awake the process + if(___no_msg) { // if SIGUSR1 occurs between if and sleep --> ignored! + #ifdef ___SLEEP + sleep(___SLEEP); // any signal will awake the process + #endif continue; } +#endif // Check for queued requests that can be resolved @@ -1096,8 +1207,81 @@ } // end of while( ! ___finish) (the main loop) - debugInfo("The end of the main function was reached.\n"); +#ifdef SINGLE_READ_CHANNEL + close(___read_ch); + close(___write_ch); +#endif + + debugInfo("The end of the supervisor function was reached.\n"); - return 1; + return 0; } + + + +// ++++++++++++++++++++++++++ USER CODE--DECLARATIONS (GENERATED CODE HERE) + + + +int ___smain_fn() { + + + // +++++++++++++++++++ USER CODE--MAIN FUNCTION (GENERATED CODE HERE) + + + return ___run_supervisor(); +} + + +#ifdef ___MAIN_FUNCTION + +int main(int argc, char* argv[]) { + int ___i, ___j; + char *___str, ___help_msg[] = "\nOptions: \n\ + -e: suppress error and status messages\n\ + -s: start the program right away without displaying introductory message\n\n\ + Ctrl-C (SIGINT) can be used to stop the program. This will terminate all\n\ + its processes.\n"; + + ___debug = 1; + ___start_flag = (argc <= 1); + for(___i = 1; ___i < argc; ___i++) { + if(!strcmp(argv[___i], "-e")) + ___debug = 0; + else if(!strcmp(argv[___i], "-h") || !strcmp(argv[___i], "--help")) { + fprintf(stdout, ___help_msg); + return 0; + } + else if(!strcmp(argv[___i], "-s")) { + ___start_flag = 0; + } + } + + if(___start_flag) { + fprintf(stdout, "%s\nThe program will start in five seconds.\n", ___help_msg); + sleep(5); + } + + if(___debug) { + if(argc <= 1) + debugInfo("The main function was entered. The main functions has no parameters."); + else { + for(___i = 0, ___j = 0; ___i < argc; ___i++) + ___j += strlen(argv[___i]); + ___j += argc + 1; + ___str = malloc(___j*sizeof(char)); + for(___i = 0, ___j = 0; ___i < argc - 1; ___i++) { + sprintf(___str + ___j, "%s ", argv[___i]); + ___j += strlen(argv[___i]) + 1; + } + sprintf(___str + ___j, "%s", argv[___i]); + debugInfo("The program was started with the following command line\n\t%s", ___str); + free(___str); + } + } + + return ___smain_fn(); +} + +#endif Modified: newcodegen/codegen.h =================================================================== --- newcodegen/codegen.h 2011-05-17 13:45:15 UTC (rev 249) +++ newcodegen/codegen.h 2011-06-20 23:01:38 UTC (rev 250) @@ -43,9 +43,8 @@ char* GetFileName(const char* s, const char *ext); // Similar to "asprintf(&x, "%s.%s", s, ext); return x;" -void compileSupervisor(pns *supervisor, char* sname, process **procTypes, \ - int nbrTypes, TrData** TrInfo, struct synclist* sl, \ - const char* buildparam); +void compileSupervisor(specs *sp, pns *supervisor, process **procTypes, \ + int nbrTypes, TrData** TrInfo, struct synclist* sl); -void compileProcessArray(process **procArray, int nbrElements, TrData** TrInfo, \ - int** actlabels); +void compileProcessArray(specs *sp, process **procArray, int nbrElements, \ + TrData** TrInfo, int** actlabels); Modified: newcodegen/filltmpl.lex =================================================================== --- newcodegen/filltmpl.lex 2011-05-17 13:45:15 UTC (rev 249) +++ newcodegen/filltmpl.lex 2011-06-20 23:01:38 UTC (rev 250) @@ -23,10 +23,12 @@ cc = yytext[i]; yytext[i] = 0; // get indentation string stmp = va_arg(param, char*); // get string to insert - for(j = 0; stmp[j]; j++) { - fwrite(stmp+j, sizeof(stmp[j]), 1, out); - if(stmp[j] == '\r' || stmp[j] == '\n') - fprintf(out, "%s", yytext); + if(stmp) { + for(j = 0; stmp[j]; j++) { + fwrite(stmp+j, sizeof(stmp[j]), 1, out); + if(stmp[j] == '\r' || stmp[j] == '\n') + fprintf(out, "%s", yytext); + } } yytext[i] = cc; // restore yytext fprintf(out, "\n%s (END OF CODE)\n", yytext); Modified: newcodegen/plantCompiler.c =================================================================== --- newcodegen/plantCompiler.c 2011-05-17 13:45:15 UTC (rev 249) +++ newcodegen/plantCompiler.c 2011-06-20 23:01:38 UTC (rev 250) @@ -31,7 +31,7 @@ } -struct myinsert genDefineBlock(process* pr, TrData* TrInfo) { +struct myinsert genDefineBlock(specs *sp, process* pr, TrData* TrInfo) { struct myinsert ins; int i, j, k, ntr; pns *pn; @@ -71,9 +71,14 @@ }\n", pr->name); } - ins = SInsert("\n\n//----- BEGINNING OF USER DEFINITIONS -----\n\n", ins); - ins = SInsert(pr->include, ins); // get include data of process - ins = SInsert("\n\n//----- END OF USER DEFINITIONS -----\n\n", ins); + if(sp->signals) + ins = SInsert("#define ___SIGNALS\n", ins); + if(sp->singlechannel) + ins = SInsert("#define SINGLE_READ_CHANNEL\n", ins); + + //ins = SInsert("\n\n//----- BEGINNING OF USER DEFINITIONS -----\n\n", ins); + //ins = SInsert(pr->include, ins); // get include data of process + //ins = SInsert("\n\n//----- END OF USER DEFINITIONS -----\n\n", ins); //if(DBG3) // if yes, then generated executables should also be in debug mode // incl = SInsert("\n#define ___DEBUG\n", incl); @@ -169,8 +174,8 @@ } -void compileProcessArray(process **procArray, int nbrElements, TrData** TrInfo, \ - int** actlabels) { +void compileProcessArray(specs *sp, process **procArray, int nbrElements, \ + TrData** TrInfo, int** actlabels) { // Note that TrInfo[i][j] indicates whether transition j of process i is // controlled and/or observed by the supervisor. @@ -203,7 +208,7 @@ fprintf(plantFile,"#define ___INSTANCE \"%s\"\n", procArray[i]->instance); // generate declarations/definitions - incl = genDefineBlock(procArray[i], TrInfo[i]); + incl = genDefineBlock(sp, procArray[i], TrInfo[i]); // generate block for main() mblock = genMainBlock(procArray[i], actlabels[i]); @@ -211,7 +216,8 @@ // Write output file rewind(f); - FillTemplate(f, plantFile, GetInsertBuf(&incl), GetInsertBuf(&mblock)); + FillTemplate(f, plantFile, GetInsertBuf(&incl), procArray[i]->include, \ + procArray[i]->main, GetInsertBuf(&mblock)); free(fileName); free(GetInsertBuf(&incl)); Modified: newcodegen/spcommon.h =================================================================== --- newcodegen/spcommon.h 2011-05-17 13:45:15 UTC (rev 249) +++ newcodegen/spcommon.h 2011-06-20 23:01:38 UTC (rev 250) @@ -6,7 +6,6 @@ #define SPCOMMON #include<errno.h> - // The following type describes data transmitted to a thread when it is created struct ___thread_data { @@ -58,6 +57,8 @@ int trans; // transition number }; +inline void ___pr_send_signal(); +inline void ___th_send_signal(); void ___debugInfoSub(int ___type, int ___id, char* ___vname, char* ___str, va_list ___param); @@ -132,6 +133,14 @@ } } + // Notify supervisor that a message has been sent + +#ifdef ___PROCESS + ___pr_send_signal(); +#else + ___th_send_signal(); +#endif + //if(write(pwrite, ___pdata, ___n) == -1) // return 0; @@ -153,11 +162,15 @@ //dbgfn("Inside get_msg"); ___ret = read(___read_end, p___ms, ___n); - if(___ret == -1 || ___ret == 0) // -1 indicates error + //if(___ret == -1 || ___ret == 0) // -1 indicates error + // return 0; + if(___ret <= 0) { + // ignore a common condition: nonblocking read from empty pipe + if(___ret == -1 && errno == EAGAIN) + return 0; + // report other conditions + dbgfn("read() has returned %d in ___get_msg(); errno = %d", ___ret, (int)errno); return 0; - if(___ret < 0) { - dbgfn("read() has returned %d in ___get_msg()", ___ret); - return 0; } if(___ret < ___n) { // Try to recover the remaining bytes dbgfn("read() has returned %d out of %d bytes in ___get_msg()",\ Modified: newcodegen/supervisorCompiler.c =================================================================== --- newcodegen/supervisorCompiler.c 2011-05-17 13:45:15 UTC (rev 249) +++ newcodegen/supervisorCompiler.c 2011-06-20 23:01:38 UTC (rev 250) @@ -691,7 +691,7 @@ */ -struct myinsert supDefineBlock(pns *sup, process **prs, int nprs, \ +struct myinsert supDefineBlock(pns *sup, process **prs, int nprs, specs* sp, \ TrData** TrInfo, struct synclist *sl) { struct myinsert ins; int i, j, n, p, t, *mk, *ip, first; @@ -884,6 +884,19 @@ ins = FSInsert(ins,"#define ___MASK %d\n", MaxNo); ins = SInsert("char ___mask[___MASK]; // Masked transitions are not fired\n\n",ins); } + + // Implement the settings of sp + + if(!(sp->nomain)) + ins = SInsert("#define ___MAIN_FUNCTION\n", ins); + if(sp->signals) + ins = SInsert("#define ___SIGNALS\n", ins); + if(sp->singlechannel) + ins = SInsert("#define SINGLE_READ_CHANNEL\n", ins); + if(sp->sleep) + ins = SInsert("#define ___SLEEP 2\n", ins); + ins = SInsert("\n", ins); + return ins; } @@ -973,15 +986,17 @@ free(thr); } -void compileSupervisor(pns *supervisor, char* sname, process **procTypes, \ - int nbrTypes, TrData** TrInfo, struct synclist* sl, \ - const char* buildparam) { +void compileSupervisor(specs* sp, pns *supervisor, process **procTypes, \ + int nbrTypes, TrData** TrInfo, struct synclist* sl) { FILE* f, *supFile; - char *fileName; + char *fileName, *sname, *buildparam; struct myinsert incl; time_t currentTime; + sname = sp->name; + buildparam = sp->sbuildparam; + f = searchTemplate(TEMPL); fileName = GetFileName(sname, "c"); supFile = fopen(fileName, "w"); @@ -999,12 +1014,12 @@ fprintf(supFile,"#define ___NAME \"%s\"\n", sname); - incl = supDefineBlock(supervisor, procTypes, nbrTypes, TrInfo, sl); + incl = supDefineBlock(supervisor, procTypes, nbrTypes, sp, TrInfo, sl); // Write output file rewind(f); - FillTemplate(f, supFile, GetInsertBuf(&incl)); + FillTemplate(f, supFile, GetInsertBuf(&incl), sp->include, sp->main); free(fileName); free(GetInsertBuf(&incl)); fclose(f); fclose(supFile); @@ -1112,14 +1127,19 @@ } -int CodeGenerator(pns *supervisor, char* sname, process** prarray, int num,\ - struct synclist* sl, TrData** TInf, const char* sbuildparam) { +int CodeGenerator(pns *supervisor, specs* sp, process** prarray, int num,\ + struct synclist* sl, TrData** TInf) { process* pr; int i, j, k, m; char *s; struct myinsert ins; + if(!sp) { + merror(0,"NEWCODEGEN: Empty specification object!"); + return 1; + } + // 2. Preprocess the array of prarray // 2.1. Update 'name' to correspond to the file name that will be @@ -1171,8 +1191,8 @@ // 3. Generate the code. - compileSupervisor(supervisor, sname, prarray, num, TInf, sl, sbuildparam); - compileProcessArray(prarray, num, TInf, plabels); + compileSupervisor(sp, supervisor, prarray, num, TInf, sl); + compileProcessArray(sp, prarray, num, TInf, plabels); // plabels is generated by compileSupervisor // Free data Modified: pnheaders/general.c =================================================================== --- pnheaders/general.c 2011-05-17 13:45:15 UTC (rev 249) +++ pnheaders/general.c 2011-06-20 23:01:38 UTC (rev 250) @@ -62,9 +62,10 @@ as intended approximately N bytes. */ if(!x->N) merror(0, "Uninitialized allocation structure!"); - x->i -= nbytes; - if(x->i >= 0) + if(x->i >= nbytes) { + x->i -= nbytes; return (x->mem) + (x->i); + } x->pos->next = tcalloc(1, sizeof(*(x->data))); x->pos = x->pos->next; x->mem = tmalloc(x->N + nbytes); x->pos->mem = x->mem; x->i = x->N; @@ -72,6 +73,14 @@ } +inline void* szalloc(struct alloc* x, size_t nbytes) { + void *ret; + ret = smalloc(x, nbytes); + memset(ret, 0, nbytes); + return ret; +} + + void sfree(struct alloc *x) { struct _alist *p, *q; for(p = x->data; p; ) { Modified: pnheaders/general.h =================================================================== --- pnheaders/general.h 2011-05-17 13:45:15 UTC (rev 249) +++ pnheaders/general.h 2011-06-20 23:01:38 UTC (rev 250) @@ -37,7 +37,9 @@ void initalloc(struct alloc* x, size_t N); /* Must be called before using the allocation object! - N determines the number of bytes of the memory blocks that are allocated. + N determines the number of bytes of the memory blocks that are allocated. + N does not limit the maximum size but the minimum size of the allocated + blocks. */ inline void* smalloc(struct alloc* x, size_t nbytes); @@ -46,6 +48,11 @@ allocated memory is in the worst case (max(nbytes)-1)/(x->N + 1), where max(nbytes) is the maximum value given by the program to nbytes. */ + +inline void* szalloc(struct alloc* x, size_t nbytes); +/* Same as smalloc except it initializes to zero the allocated memory */ + + void sfree(struct alloc *x); /* Deallocates the memory blocks addressed by the object. */ @@ -61,10 +68,10 @@ /* The structures is organized in blocks of memory called here pages. Each page can store N bytes. A page stores elements of size sz bytes. */ struct qalloc { - size_t N, sz; /* N: bytes per page, sz: bytes per element */ - size_t front, rear; /* front: position of last element; + long N, sz; /* N: bytes per page, sz: bytes per element */ + long front, rear; /* front: position of last element; rear: position of first element; */ - size_t nitems; /* number of items in the queue */ + long nitems; /* number of items in the queue */ struct _qlist *frpage, *rrpage; /*the pages of front and rear, respectively*/ struct _qlist *last; /* pointer to the last element of the chain of pages */ Modified: pnheaders/main_function.c =================================================================== --- pnheaders/main_function.c 2011-05-17 13:45:15 UTC (rev 249) +++ pnheaders/main_function.c 2011-06-20 23:01:38 UTC (rev 250) @@ -55,9 +55,54 @@ } +void main_filter(char **inc, char **newinc, char **main, char *pattern) { + // Copy/append to newinc everything in *inc up to 'pattern'. + // Copy/append to *main everything in *inc following 'pattern'. + // If newinc is zero, keep in inc everything up to 'pattern'. + // If newinc is nonzero, dealloc *inc and set it to zero. + + int i, n; + char *p, *p2; + + if(!inc) return; + p = *inc; + if(!p || !pattern) return; + n = strlen(pattern); + for(i = 0; p[i]; i++) { + if(p[i] == ' ' || p[i] == '\t') + continue; + if(!strncmp(p+i, pattern, n)) // then 'pattern' has been found + break; + } + + if(main && p[i]) { // p[i] is nonzero if 'pattern' was found + if(*main) { // append to text in *main + asprintf(&p2, "%s\n\n%s", *main, p+i+n); + free(*main); + *main = p2; + } + else // write text to *main + asprintf(main, "%s", p+i+n); + } + + p[i] = 0; // keep in inc everything up to 'pattern' + if(newinc) { + if(!*newinc) + *newinc = *inc; + else { // append to text in newinc + asprintf(&p2, "%s\n\n%s", *newinc, *inc); + free(*newinc); + *newinc = p2; + free(*inc); + } + *inc = 0; + } +} + + void sp_filter(specs *sp) { - // Removes beginning and end braces. - // Processes <thread> instructions. + // Removes beginning and end braces. Processes embedded instructions. + // Sets default values for fields not processed by the translator. int i, j; pns *pn; arcs *pa; @@ -65,13 +110,20 @@ return; if(!sp->process_array) return; + + // Default values + + sp->main = 0; + sp->include = 0; + for(i = 0; i < sp->process_num; i++) { if(!sp->process_array[i]) continue; + + sp->process_array[i]->main = 0; // not processed by the translator + br_filter(sp->process_array[i]->build); br_filter(sp->process_array[i]->include); - //if(th_filter(&(sp->process_array[i]->build))) - //sp->process_array[i]->thread = 1; // Is this a thread? sp->process_array[i]->thread = th_filter(&(sp->process_array[i]->build),\ @@ -79,6 +131,13 @@ // Is this a supervisor component? sp->process_array[i]->supervisor=th_filter(&(sp->process_array[i]->build),\ "<supervisor>"); + // Process the <main> instructions if any + if(sp->process_array[i]->supervisor) + main_filter(&(sp->process_array[i]->include), &(sp->include), \ + &(sp->main), "<main>"); + else + main_filter(&(sp->process_array[i]->include), 0, \ + &(sp->process_array[i]->main), "<main>"); pn = sp->process_array[i]->pn; if(pn) { if(pn->segment) @@ -117,33 +176,74 @@ struct label_lst* lls; TrData** TInf; + // These are flags + unsigned char no_main = 0, signals = 0, sleep = 1, single_ch = 0; +char help[] = "\ +The program generates concurrency control code based on a specification file.\ +\n\ +\nUsage: ct [options] [specification file] [-b list]\ +\n\ +\n'list' stands for a list of files and compiler options that should be\ +\ncopied to the command line used to build the executable file.\ +\n\ +\nOptions:\ +\n -d<number> Comment on execution progress. More information displayed for\ +\n higher values of <number>, where <number> = 1 ... 20.\ +\n -m Do not generate a main function.\ +\n -s<number> Depending on the value of <number> the supervisor can be built\ +\n as follows:\ +\n 0: The supervisor waits actively for events. \ +\n 1: The supervisor is built as in option 0 except it enters a \ +\n sleep state (for a finite amount of time) when no events\ +\n are detected. \ +\n 2: The supervisor blocks when no events occur. This option is \ +\n best when the number of concurrent processes or threads is \ +\n small. The supervisor has the least computational overhead \ +\n under this option. \ +\n\ +\nExamples: ct manf.sp\ +\n ct -d3 input.sp\n"; + +// About single channe (option 2) all plant components write to the same pipe. +// Use this option if it is unlikely that the pipe would keep getting full +// (i.e. if there are not many processes). Otherwise, fairness depends on +// whether the OS is fair in deciding which requests to serve when the pipe +// keeps getting full and there are competing requests to write to the pipe. + + // 1. INITIALIZATION ins = InitInsert(512); // used to store command line parameters verb = 0; input = 0; - if(na <= 1 || na > 3) { - printf("\nACTS--A Concurrency Tool Suite for concurrent programming and concurrent \nsystem design. This software is part of ongoing research to apply supervisory\ncontrol and related approaches to concurrency problems. While various \nsupervisory control tools should be implemented in the future, currently only\nmethods of the supervision based on place invariants are implemented. For \nmore information please refer to the documentation.\n\ -\nUsage: ct [-dnum] file [-b ...]\ -\nOptions:\ -\n -b ... List of files and compiler options that should be copied to\ -\n the command line that builds the main program.\ -\n -d<num> Comment on execution progress. More information displayed for\ -\n high values of <num>.\ -\n\ -\nExamples: ct manf.sp\ -\n ct -d3 input.sp\n"); - + if(na <= 1) { + puts(help); finish = 1; } for(i = 1; i < na && !finish; i++) { + if(!strcmp(argv[i], "--help")) { + finish = 1; + puts(help); + break; + } if(argv[i][0] == '-') { switch(argv[i][1]) { case 'd': verb = atoi(argv[i]+2); break; + case 'm': no_main = 1; + break; + case 's': j = atoi(argv[i]+2); + switch(j) { + case 0: sleep = 0; break; + case 1: sleep = 1; break; + case 2: single_ch = 1; break; + case 3: signals = 1; break; + default: fprintf(stderr,"Unexpected parameter %s.\n", argv[i]); + } + break; case 'b': if(argv[i][2]) ins = FSInsert(ins, " %s", argv[i]+2); for(i = i + 1; i < na; i++) @@ -200,6 +300,13 @@ return 0; } + // Set settings not detected by translator + + sp->signals = signals; + sp->sleep = sleep; + sp->singlechannel = single_ch; + sp->nomain = no_main; + sp_filter(sp); // detect settings and remove extra braces if(is_verbose() >= 3) { // For debugging @@ -247,6 +354,7 @@ // 2.3 Obtain SC specification. Currently: // extract the L, C, H, and b matrices (more complex specs to be done later) + // the function calculates also the composed PN extractLHCB(sp, &pn, &L, &H, &C, &B); @@ -418,10 +526,10 @@ /*CodeGenerator(apnsv, sp->name, sp->process_array, sp->process_num, \ syncl, TInf, build); */ + sp->sbuildparam = build; + CodeGenerator(apnsv, sp, plant_array, plcnum, syncl, TInf); - CodeGenerator(apnsv, sp->name, plant_array, plcnum, syncl, TInf, build); - // 5. TERMINATE if(apnsv) { @@ -431,7 +539,6 @@ free(plant_array); free(spv_array); dealloc_specs(sp); - if(build) free(build); free_label_list(lls); free_synclist(syncl); free_TrData(TInf, plcnum); Modified: pnheaders/pns.c =================================================================== --- pnheaders/pns.c 2011-05-17 13:45:15 UTC (rev 249) +++ pnheaders/pns.c 2011-06-20 23:01:38 UTC (rev 250) @@ -1,6 +1,6 @@ /**************************************************************************** PNS.C -Written in 2008-2010 by M. V. Iordache. +Written in 2008-2011 by M. V. Iordache. ****************************************************************************/ #include"pns.h" @@ -680,6 +680,12 @@ dealloc_process(sp->process_array[i]); free(sp->process_array); } + if(sp->include) + free(sp->include); + if(sp->main) + free(sp->main); + if(sp->sbuildparam) + free(sp->sbuildparam); } @@ -702,6 +708,12 @@ free(p->build); if(p->include) free(p->include); + if(p->main) + free(p->main); + if(p->pn) { + deallocpn(p->pn); + free(p->pn); + } } @@ -746,14 +758,144 @@ } +inline void dealloc_tarray(struct tarray* p) { + if(p) { + sfree(&(p->mem)); + if(p->T) + free(p->T); + free(p); + } +} + /*************************************************************************** COMPOSEPN ****************************************************************************/ -pns composepn(pns* pn1, pns* pn2) { - pns pn; - /* Algorithm: +void inline insert_tranlist_sub(struct tranlist where, pns* pn, int t, \ + struct alloc* mem) { + // subroutine of ComposePN; inserts a tranlist element in the chain such that + // the pn fields in the chain are sorted in increasing order. + + struct tranlist *p, *q; + + if(!where.pn) { // this indicates an empty chain + where.pn = pn; + where.t = t; + return; + } + + p = smalloc(mem, sizeof(*p)); + + if(pn < where.pn) { // if this must be the first chain element + p->pn = where.pn; + p->t = where.t; + p->next = where.next; + where.next = p; + where.pn = pn; + where.t = t; + return; + } + p->pn = pn; + p->t = t; + for(q = &where; q->next; q = q->next) { + if(q->next->pn >= p->pn) { // insert p in chain + p->next = q->next; + q->next = p; + return; + } + } + q->next = p; // line reached if p must be at the end of the chain + p->next = 0; // smalloc does not initialize memory to 0 when it allocates p +} + + +void inline insert_tranlist(struct tranlist where, struct tranlist* what, \ + struct alloc* mem) { + // subroutine of ComposePN; inserts a tranlist element in the chain such that + // the pn fields in the chain are sorted in increasing order. + + insert_tranlist_sub(where, what->pn, what->t, mem); +} + + +void update_TR(int i, int i1, int i2, struct tarray *T1, struct tarray *T2, \ + struct tarray *TR) { + // This is a subroutine of ComposePN. Copies T1[i1] and T2[i2] to TR[i]. + // + // Relies on TR->T having its elements initialized to zero (satisfied when + // TR->T is allocated with (t)calloc. + + struct tranlist *p; + + if(T1) + if(T1->T) + for(p = (T1->T)+i1; p; p = p->next) + insert_tranlist((TR->T)[i], p, &(TR->mem)); + + if(T2) + if(T2->T) + for(p = (T2->T)+i2; p; p = p->next) + insert_tranlist((TR->T)[i], p, &(TR->mem)); +} + + +void set_TR(pns* pn, struct tarray* T, struct tarray **TR) { + // This is a subroutine of ComposePN and PNComposition. + // It is used to initialize TR based on pn and T. + int nt, i; + struct tranlist* TL, *p; + + if(!TR) + return; + + *TR = tcalloc(1, sizeof(**TR)); + initalloc(&((*TR)->mem), 50*sizeof(*(*TR)->T)); + if(!T) { + nt = pn->tnum; + (*TR)->n = nt; + TL = tcalloc(nt, sizeof(*(*TR)->T)); + for(i = 0; i < nt; i++) { + TL[i].pn = pn; + TL[i].t = i; + } + (*TR)->T = TL; + return; + } + + // This is the case T != 0 + nt = T->n; + TL = tcalloc(nt, sizeof(*(*TR)->T)); + for(i = 0; i < nt; i++) { + TL[i].pn = T->T[i].pn; + TL[i].t = T->T[i].t; + for(p = T->T[i].next; p; p = p->next) + insert_tranlist(TL[i], p, &((*TR)->mem)); + } + (*TR)->T = TL; +} + + + +pns ComposePN(pns* pn1, pns* pn2, struct tarray* T1, struct tarray* T2,\ + struct tarray **TR) { + +/* Returns the parallel composition of pn1 and pn2. + + The remaining parameters are ignored when TR = 0. + + The role of T1, T2, and TR is as follows. If TR != 0, then *TR is + initialized to an array of N elements, where N is the number of transitions + of the parallel composition of the two PNs. Thus, (*TR)[i] is the element + associated with the transition i of the PN result. Note that i = 0 ... N-1. + The element i of *TR lists all transitions (and the pns to which they + belong) that form the transition i of the PN result. T1 and T2 should be + zero if pn1 and pn2 are not the result of previous PN compositions. + Otherwise, T1 and T2 may be set to the *TR of the previous PN + compositions. */ + + + /* Algorithm of pn composition: - Create the vector "lcount". For all t of pn1 lcount(t) indicates how many times the label of t appears in pn2. For all t of pn2 lcount(t) is 1 if the label of t appears in pn1. Otherwise it is 0. @@ -763,13 +905,15 @@ */ int *lcount, np, np1, np2, nt, nt1, nt2, i, j, k, z, label; + pns pn; if(!pn1 && !pn2) { memset(&pn, 0, sizeof(pn)); + if(TR) *TR = 0; return pn; } - if(!pn1) return copypn(pn2); - if(!pn2) return copypn(pn1); + if(!pn1) { set_TR(pn2, T2, TR); return copypn(pn2);} + if(!pn2) { set_TR(pn1, T1, TR); return copypn(pn1);} nt1 = pn1->tnum; /* determine the number of transitions */ nt2 = pn2->tnum; @@ -810,6 +954,17 @@ /* Create the composed pn */ pn = createpn("pnum tnum", np, nt); + if(TR) // { // if TR is to be used, then allocate *TR + alloc_tarray(*TR, nt); + /* if(!nt) + *TR = 0; + else { + *TR = tcalloc(1, sizeof(**TR)); + (*TR)->n = nt; + (*TR)->T = tcalloc(nt, sizeof(*(*TR)->T)); + initalloc(&((*TR)->mem), 50*sizeof(*(*TR)->T)); + } + }*/ /* Initialize the capacity and marking entries */ @@ -843,6 +998,10 @@ Copy2ZeroColumn(&(pn2->in),j,&(pn.in),j,np1); Copy2ZeroColumn(&(pn2->out),j,&(pn.out),j,np1); } + if(TR) { + if(nt1) set_TR(pn1, T1, TR); + if(nt2) set_TR(pn2, T2, TR); + } return pn; } @@ -861,7 +1020,7 @@ /* Next the transitions of pn1 are considered */ - for(i = 0, z = 0; i < nt1; i++) { + for(i = 0, z = 0; i < nt1; i++) { // lcount[i] != 0 only if both pns labeled if(lcount[i]) { /* pn2 has lcount[i] transitions with the same label */ label = pn1->t[i].l; for(j = 0, k = 0; k < lcount[i]; j++) { @@ -887,7 +1046,7 @@ pn2->t[j].uncontrollable; pn.t[z].unobservable=pn1->t[i].unobservable | pn2->t[j].unobservable; pn.t[z].live = pn1->t[i].live | pn2->t[j].live; - + if(TR) update_TR(z, i, j, T1, T2, *TR); z++; /* z: number of next empty column in the matrices of pn */ k++; } @@ -903,6 +1062,7 @@ pn.t = tcalloc(pn.tnum,sizeof(pn.t[0]));/*elements initialized to 0*/ memcpy((pn.t)+z, (pn1->t)+i, sizeof(pn.t[0])); } + if(TR) update_TR(z, i, 0, T1, 0, *TR); z++; } } @@ -921,6 +1081,7 @@ pn.t = tcalloc(pn.tnum,sizeof(pn.t[0]));/*elements initialized to 0*/ memcpy((pn.t)+z, (pn2->t)+j, sizeof(pn.t[0])); } + if(TR) update_TR(z, 0, j, 0, T2, *TR); z++; } @@ -931,26 +1092,36 @@ -pns pn_composition(process** process_array, int num) { +pns PNComposition(process** process_array, int num, struct tarray **TR) { /* Composes the PNs in the process array and returns the result. */ pns pn, pn1, *apn; int i; + struct tarray *T; - if(num <= 0 || !process_array) + if(num <= 0 || !process_array) { memset(&pn, 0, sizeof(pn)); // return null pn - else if(num == 1) + if(TR) *TR = 0; + return pn; + } + else if(num == 1) { pn = copypn(process_array[0]->pn); - else { - apn = process_array[0]->pn; - for(i = 1; i < num; i++) { - if(i > 1) { - pn1 = pn; // save intermediary result for subsequent deallocation - apn = &pn1; - } - pn = composepn(apn, process_array[i]->pn); - if(i > 1) - deallocpn(&pn1); // free intermediary result + if(TR) set_TR(process_array[0]->pn, 0, TR); + return pn; + } + + apn = process_array[0]->pn; + for(i = 1, T = 0; i < num; i++) { + if(i > 1) { + pn1 = pn; // save intermediary result for subsequent deallocation + apn = &pn1; + if(TR) + T = *TR; } + pn = ComposePN(apn, process_array[i]->pn, T, 0, TR); + if(i > 1) + deallocpn(&pn1); // free intermediary result + if(T) + dealloc_tarray(T); } return pn; @@ -1220,22 +1391,27 @@ EXTRACTLHCB ****************************************************************************/ -/* This is a temporary implementation; future work should take in account that - sp can contain more general specifications */ - /* The implementation assumes that no disjunctive constraints are present. */ +struct _extractLCHB { + int i; + struct tarray* p; +}; -int find_var_index(variable* var, pns* pn, specs* sp) { + +struct _extractLCHB find_var_index(variable* var, pns* pn, specs* sp) { int i, k; int lab; + struct _extractLCHB u; if(var->type == MARKINGV) { if(var->index >= var->pn->pnum) merror(0, "EXTRACTLHCB: index %d >= place number (%d)", var->index, var->pn->pnum); for(i = 0, k = 0; i < sp->process_num; i++) { - if(var->pn == sp->process_array[i]->pn) - return var->index + k; + if(var->pn == sp->process_array[i]->pn) { + u.i = var->index + k; + return u; + } k += sp->process_array[i]->pn->pnum; } merror(0, "EXTRACTLHCB: Marking variable does not match specified PNs"); @@ -1245,12 +1421,15 @@ merror(0, "EXTRACTLHCB expects labeled Petri nets"); if(var->index >= var->pn->tnum) merror(0, "EXTRACTLHCB: index %d >= tran. number (%d)", var->index, var->pn->tnum); - lab = var->pn->t[var->index].l; - for(i = 0; i < pn->tnum; i++) - if(pn->t[i].l == lab) // Assumes free-labeled PN - return i; - merror(0, "EXTRACTLHCB: Variable does not match specified PNs"); + u.p = var->pn->data; + u.i = var->index; + /* lab = var->pn->t[var->index].l; + for(i = 0; i < pn->tnum; i++) + if(pn->t[i].l == lab) // Assumes free-labeled PN + return i; + merror(0, "EXTRACTLHCB: Variable does not match specified PNs"); */ } + return u; } void extractLHCB(specs* sp, pns* pn, matrix* L, matrix* H, matrix* C, int** B) { @@ -1260,11 +1439,33 @@ int cnum; /* constraint number */ variable* var; inequality* in; + struct tarray *TR; + struct tranlist *p; + void **data; + struct _extractLCHB u; /* Find the composed PN */ - *pn = pn_composition(sp->process_array, sp->process_num); + *pn = PNComposition(sp->process_array, sp->process_num, &TR); + if(!TR) + merror(0, "EXTRACTLHCB: PN composition failed to extract required data"); + + /* Extract from TR transition information */ + data = tcalloc(sp->process_num, sizeof(*data)); + for(i = 0; i < sp->process_num; i++) { /* save 'data' content of each pn */ + data[i] = sp->process_array[i]->pn->data; + alloc_tarray(sp->process_array[i]->pn->data, sp->process_array[i]->pn->tnum); + } + for(i = 0; i < TR->n; i++) { + for(p = (TR->T)+i; p; p = p->next) + if(p->pn) + insert_tranlist_sub(((struct tarray*) p->pn->data)->T[p->t], \ + pn, i, &((struct tarray*) p->pn->data)->mem); + /* 2nd par of insert_... must be nonzero; value not essential */ + } + + /* May be deleted after testing pn_composition above if(sp->process_num == 1) *pn = copypn(sp->process_array[0]->pn); @@ -1308,15 +1509,31 @@ merror(0, "EXTRACTLCHB: Unexpected expression format"); (*B)[i] = in->free_term; for(var = in->variable_list; var; var = var->next) { - j = find_var_index(var, pn, sp); - if(var->type == MARKINGV) - SetMatrixEl(L, i, j, var->coefficient + GetMatrixEl(L, i, j)); - if(var->type == FIRINGV) - SetMatrixEl(H, i, j, var->coefficient + GetMatrixEl(H, i, j)); - if(var->type == PARIKHV) - SetMatrixEl(C, i, j, var->coefficient + GetMatrixEl(C, i, j)); + u = find_var_index(var, pn, sp); + if(var->type == MARKINGV) /* L(i, u.i) = L(i, u.i) + var->coefficient */ + SetMatrixEl(L, i, u.i, var->coefficient + GetMatrixEl(L, i, u.i)); + else { + /* A loop is needed in order to account for ALL transitions of the + composed pn corresponding to var->index */ + for(p = (u.p)->T+(u.i); p; p++) { + if(!(p->pn)) break; + j = p->t; + if(var->type == FIRINGV) + SetMatrixEl(H, i, j, var->coefficient + GetMatrixEl(H, i, j)); + if(var->type == PARIKHV) + SetMatrixEl(C, i, j, var->coefficient + GetMatrixEl(C, i, j)); + } + } } } + + for(i = 0; i < sp->process_num; i++) {/* restore data content of each pn */ + dealloc_tarray(sp->process_array[i]->pn->data); + sp->process_array[i]->pn->data = data[i]; + } + free(data); + dealloc_tarray(TR); + } Modified: pnheaders/pns.h =================================================================== --- pnheaders/pns.h 2011-05-17 13:45:15 UTC (rev 249) +++ pnheaders/pns.h 2011-06-20 23:01:38 UTC (rev 250) @@ -121,6 +121,9 @@ in software. Note that arc_list[i] is the list of arcs corresponding to the transition i. Currently used for plant PNs, not supervisor PNs. */ + + void* data; /* provides a way to associate arbitrary data with a PN */ + } pns; @@ -218,9 +221,6 @@ void deallocpn(pns *pn); /* frees the space used by the arrays inside the pns structure */ -pns composepn(pns* p1, pns* p2); -/* Performs the parallel composition of two pns */ - void displaypn(pns pn, FILE *f); /* Write pn information into a file. */ @@ -232,7 +232,56 @@ /* Returns nonzero when t is a source transition of pn */ +/* The following structures are used in ComposePN in order to associate to + each transition of the composed PN the list of transitions from which it + is obtained. */ +struct tranlist { + pns* pn; + int t; /* the transition of pn */ + struct tranlist *next; +}; + +struct tarray { + struct tranlist *T; /* array of n elements */ + int n; /* the number of elements in the array T */ + struct alloc mem; // struct alloc defined in general.h for memory management +}; + +#define alloc_tarray(p,m) \ + if(!m) p = 0; \ + else { \ + p = tcalloc(1, sizeof(struct tarray)); \ + ((struct tarray*) (p))->n = m; \ + ((struct tarray*) (p))->T = tcalloc(m, sizeof(struct tranlist)); \ + initalloc(&(((struct tarray*) (p))->mem), 50*sizeof(struct tranlist)); \ + } + +inline void dealloc_tarray(struct tarray* p); /* in pns.c */ +/* deallocates everything, including p itself */ + + +pns ComposePN(pns* pn1, pns* pn2, struct tarray* T1, struct tarray* T2,\ + struct tarray **TR); +/* Returns the parallel composition of pn1 and pn2. + + The remaining parameters are ignored when TR = 0. + + The role of T1, T2, and TR is as follows. If TR != 0, then *TR is + initialized to an array of N elements, where N is the number of transitions + of the parallel composition of the two PNs. Thus, (*TR)[i] is the element + associated with the transition i of the PN result. Note that i = 0 ... N-1. + The element i of *TR lists all transitions (and the pns to which they + belong) that form the transition i of the PN result. T1 and T2 should be + zero if pn1 and pn2 are not the result of previous PN compositions. + Otherwise, T1 and T2 may be set to the *TR of the previous PN + compositions. */ + + +#define composepn(x,y) ComposePN(x,y,0,0,0); + + + #define MARKINGV 0 /* marking */ #define FIRINGV 1 /* firing vector */ #define PARIKHV 2 /* Parikh vector (firing count vector) */ @@ -354,12 +403,18 @@ char* instance; /* name of process instance */ pns* pn; /* underlying PN structure.*/ char* build; /* the command that should be used to build the process */ - char* include; /* What should be included at the beginning of the source + char* include; /* text to be included at the beginning of the source file of the process. */ + char* main; /* text to be included in the main function of the process */ + + char thread:1; /* set to 1 if process should be implemented as a thread */ + char supervisor:1; /* set to 1 if the process is a supervisor component */ + + /* The following are not used */ + int type:1; /* type = 1 indicates an external process */ int start:1; /* start = 1 if the supervisor should start this process */ - char thread:1; /* set to 1 if process should be implemented as a thread */ - char supervisor:1; /* set to 1 if the process is a supervisor component */ + } process; @@ -373,6 +428,20 @@ process **process_array; /* each array element contains the address of one process object */ int process_num; /* the number of elements of the process array */ + + char* include; /* text to be included at the beginning of the + supervisor file */ + char* main; /* text to be included in the main function of the supervisor */ + + char* sbuildparam; /* Indicates additional parameters that should be included + in the command line building main executable file. + Used in WriteMakefile of supervisorCompiler.c */ + unsigned char signals:1; /* if implementation should use signals */ + unsigned char sleep:1; /* if false, the supervisor does not enter a "sleep" + state when there are no events */ + unsig... [truncated message content] |
From: <mio...@us...> - 2011-05-17 13:45:21
|
Revision: 249 http://pntool.svn.sourceforge.net/pntool/?rev=249&view=rev Author: miordache Date: 2011-05-17 13:45:15 +0000 (Tue, 17 May 2011) Log Message: ----------- corrections Modified Paths: -------------- examples/test.sp newcodegen/plantCompiler.c newcodegen/supervisorCompiler.c pnheaders/pns.c translator/main.c Modified: examples/test.sp =================================================================== --- examples/test.sp 2011-05-13 22:48:19 UTC (rev 248) +++ examples/test.sp 2011-05-17 13:45:15 UTC (rev 249) @@ -1,8 +1,12 @@ // This is a test file created in order to check the functionality of the -// pn translator. +// pn translator. -process TST; +process TST +include: { + int i; +}; + TST.PN: places: p0 p1 p2; @@ -11,8 +15,8 @@ (p0, t0); (t2, p0); -(p1, t1, p2, p0); -(p1, t1, p2, p0); +(p1, t1, p2, p0); // this is not a state machine; +(p1, t1, p2, p0); // the code generator assumes state machines. (p2, t2, p1).{i == 3}; TST testpn(p0:2,p1:1); Modified: newcodegen/plantCompiler.c =================================================================== --- newcodegen/plantCompiler.c 2011-05-13 22:48:19 UTC (rev 248) +++ newcodegen/plantCompiler.c 2011-05-17 13:45:15 UTC (rev 249) @@ -95,7 +95,8 @@ for(i = 0; i < pn->pnum; i++) { ins = FSInsert(ins, "\ncase %d:\n", i); - ins = SInsert(pn->segment[i], ins); + if(pn->segment) + ins = SInsert(pn->segment[i], ins); // Inserting/creating select functions // The output of the select function is the ___TR list. Modified: newcodegen/supervisorCompiler.c =================================================================== --- newcodegen/supervisorCompiler.c 2011-05-13 22:48:19 UTC (rev 248) +++ newcodegen/supervisorCompiler.c 2011-05-17 13:45:15 UTC (rev 249) @@ -718,15 +718,21 @@ ins = SInsert(";\n", ins); ins = FSInsert(ins, "#define n___in %d // Number of rows of ___in\n", j); */ - if(!sup->marking) { // initialize it to zero - ip = calloc(sup->pnum, sizeof(*ip)); - updatepn(sup, "m0", ip); - free(ip); + if(sup->pnum) { + if(!sup->marking) { // initialize it to zero + ip = calloc(sup->pnum, sizeof(*ip)); + updatepn(sup, "m0", ip); + free(ip); + } + ins = SInsert("const int ___m0[][2] = ", ins); + ins = cinsert1D(sup->marking, sup->pnum, &j, ins); + ins = SInsert(";\n", ins); + ins = FSInsert(ins,"#define n___m0 %d // Number of rows of ___m0\n\n",j); } - ins = SInsert("const int ___m0[][2] = ", ins); - ins = cinsert1D(sup->marking, sup->pnum, &j, ins); - ins = SInsert(";\n", ins); - ins = FSInsert(ins, "#define n___m0 %d // Number of rows of ___m0\n\n", j); + else { + ins = SInsert("const int ___m0[][2] = {};\n", ins); + ins = FSInsert(ins, "#define n___m0 0 // Number of rows of ___m0\n\n"); + } } // end of if(sup) else { ins = SInsert("#define ___pnum 0\n", ins); Modified: pnheaders/pns.c =================================================================== --- pnheaders/pns.c 2011-05-13 22:48:19 UTC (rev 248) +++ pnheaders/pns.c 2011-05-17 13:45:15 UTC (rev 249) @@ -764,6 +764,13 @@ int *lcount, np, np1, np2, nt, nt1, nt2, i, j, k, z, label; + if(!pn1 && !pn2) { + memset(&pn, 0, sizeof(pn)); + return pn; + } + if(!pn1) return copypn(pn2); + if(!pn2) return copypn(pn1); + nt1 = pn1->tnum; /* determine the number of transitions */ nt2 = pn2->tnum; Modified: translator/main.c =================================================================== --- translator/main.c 2011-05-13 22:48:19 UTC (rev 248) +++ translator/main.c 2011-05-17 13:45:15 UTC (rev 249) @@ -264,7 +264,8 @@ if(is_verbose() >= 10) { printf("Threads dealloced\n"); } - nodes ->free (nodes); nodes = NULL; + if(errors != true) // line added by MVI + nodes ->free (nodes); nodes = NULL; if(is_verbose() >= 10) { printf("Nodes freed\n"); } @@ -454,4 +455,4 @@ var = var->next; } printf(" <= \%i\n", ineq->free_term); -} \ No newline at end of file +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-05-13 22:48:26
|
Revision: 248 http://pntool.svn.sourceforge.net/pntool/?rev=248&view=rev Author: miordache Date: 2011-05-13 22:48:19 +0000 (Fri, 13 May 2011) Log Message: ----------- added some examples Added Paths: ----------- doc/ doc/GettingStarted.htm doc/input2.sp examples/ examples/+README+ examples/reader.sp examples/test.sp examples/test2.sp examples/test2a.sp examples/test2b.sp examples/test2c.sp examples/test2d.sp examples/test2e.sp examples/test2f.sp examples/test2g.sp examples/test3a.sp examples/test3b.sp examples/test3c.sp examples/test3d.sp Added: doc/GettingStarted.htm =================================================================== --- doc/GettingStarted.htm (rev 0) +++ doc/GettingStarted.htm 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,41 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + <head> + <title></title> + </head> + + <body> + <h1></h1> + +<p><b>A Concurrency Tool Suite--Getting Started</b> + +<p>The software is intended for Unix operating systems. If you use a Windows computer, you may download cygwin from <a href="http://www.cygwin.com">http://www.cygwin.com</a>. The cygwin program runs in Windows and emulates Linux. Thus, you may run the software in Windows by means of cygwin. + +<p>To build the software, type the command "make" in the main directory of the source code. This will execute the commands of the file called "Makefile" and build an executable file called "ct.exe". In spite of its extension, this is not a Windows executable file. It can only be executed within cygwin or in Unix. + +<p>If you run ct.exe you can see a description of its options. + +<p>In order to run the program on a specification file: +<ul> +<li> Copy the files SupervisorTemplate.c ProcessTemplate.c and spcommon.h from the newcodegen directory to your working directory. +<li> Run ct.exe on your specification file. For instance, if spec.sp is the specification file, you could type "./ct.exe -d4 spec.sp". The d4 option can be used in order to have ct.exe display messages describing what it is doing. +<li>If the specification file is correct, ct.exe will exit normally and create a number of sources files allowing you to build your program. +<li> You can build your program using "make" and the makefile generated by ct.exe. For instance, to build the program from the source code generated for spec.sp, type "make -f spec.mak". +<li> The previous step will generate an executable file. When you run it, you can force it to terminate with Ctrl-c. This should terminate also all other processes (if any) started by the executable file. +</ul> + +<p>To create your own specification files: +<ul> +<li>See the example directory of the source code. +<li>Check also input2.sp. However, note that the features of input2.sp are not fully implemented in the translator module (which is unfinished at this time) and input2.sp is not a complete description of the low level specification language. Some syntax details (such as semicolon separators and braces) are not described in this version of input2.sp. +</ul> + + + + <hr> +<!-- Created: Fri May 13 17:16:03 CDT 2011 --> +<!-- hhmts start --> +Last modified: Fri May 13 17:43:01 CDT 2011 +<!-- hhmts end --> + </body> +</html> Added: doc/input2.sp =================================================================== --- doc/input2.sp (rev 0) +++ doc/input2.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,342 @@ +// This is a preliminary description of the low level specification language. + +// FOR REFERENCE ONLY. ON ONE HAND, NOT ALL FEATURES HAVE BEEN IMPLEMENTED +// IN THE TRANSLATOR. ON THE OTHER HAND, SOME IMPLEMENTED FEATURES ARE NOT +// DESCRIBED HERE. THIS FILE MAY NOT DESCRIBE THE ENTIRE SYNTAX. SEE THE +// EXAMPLES FOR INFORMATION ON THE SYNTAX. + +// Version 2.1.1 - 04/21/2011 +// The keyword "init" was added for initialization code. +// Version 2.1 - 05/19/2009 +// Compared to version 2, the following keywords were added: +// "nondeterministic", "select", "uncontrollable", and "unobservable". +// The low level (PN level) specification language is illustrated on a +// specification of independent reader and writer processes with shared memory. +// The high level language has not been developed yet. + +// The concurrent programming tool operates as follows. +// +// Given a specification file (say input.sp), the tool generates +// - input.c containing the code of the supervisor; +// - input.mak a makefile; +// - additional c files, one for each process defined below. +// +// After the application is built, the user can start it by +// running the supervisor program (say input.exe). The supervisor program +// will start all other processes and ensure that they operate +// correctly. Terminating the supervisor program will also +// terminate children processes. + + +// The specification file consists of three parts containing +// - process-type declarations +// - definitions +// - process declarations and dependencies +// - instructions on supervisor design + +// 1. PROCESS-TYPE DECLARATIONS + +// Format: +// +// process type // Write here the name of the process type. + // Note that all processes of the same type have the same + // executable file. +// build command: // Write here the line(s) used to build the executable. + // For instance: 'make -f process_name.mak' or + // 'gcc -o process_name process_name.sp.c functions.c ...' + // Note that process_name.sp.c is the c file generated + // by the concurrent programing tool for the process_name + // type. +// include: // Write here what should be included at the beginning of + // process_name.sp.c, such as #include directives. +// extern process type // Declares a process type for which the tool should + // not generate code. Such a process type may describe + // hardware or software functions already implemented. + // If such external processes impose relevant + // constraints, the specification should + // describe them. This may help: + // - simplify some supervisory control methods + // - reveal potential deadlock situations + // A process may not be external unless all transitions + // unique to the process are uncontrollable and + // unobservable. + +process type READER + +build command: make -f reader.mak + +include: { + #include<stdio.h> + #include<string.h> + + int state = 0; /* variables can be declared here as well */ +} + + +init: { + // include here declarations and initialization code +} + +process type WRITER + +build command: make -f writer.mak + +include: #include "writer.h" + + +extern process type ARBITER // Note that no build or include commands follow + // the declaration of an external process type. + + +// 2. DEFINITIONS + +// This version of the specification format describes only a low level PN +// definition of the processes. + +// Format: + +// process_name.PN: +// places: list of place names +// transitions: list of transition names +// place.code: gives the C code associated with a place. The C code +// is not parsed here! Rather the "text" structure associated +// to the PN place is initialized with the position of the C code. +// *place: list of input transitions +// place*: list of the output transition of place +// ([place], transition, [place, ...])[.{c code}] where items between +// square brackets are optional. +// Note that the c code is not parsed but its position is copied to a "text" +// structure associated with the arc. + + + +ARBITER.PN: + +places: p1 p2 // place names do not have to start with a 'p' + +transitions: t1 t2 // transition names do not have to start with a 't' + +// Note the absence of place.code lines for an external process. + +*p1: t1 +p1*: t2 +*p2: t2 +p2*: t1 + + +// The format *place: input transition(s), place*: output transition(s) +// is ideal for representing a PN structure and this is what we need for an +// external process. However, the format it is ambiguous for the processes for +// which code should be generated. For instance, assume a transition t such +// that *t: p1 p2 and t*: p3 p4. Recall that each process of type X is a +// token in the underlying PN. Thus, assuming two processes, one in the stage +// p1 and one in the stage p2, it is not clear what action should be taken +// when t is fired. The following format will be used to describe the outcome +// of firing t. +// 1. The process in p1 goes to p3 and the one in p2 to p4 +// (p1, t, p3) (p2, t, p4) +// 2. The process in p1 goes to p3 and forks one child process in p4. The +// process in p2 terminates. +// (p1, t, p3, p4) (p2, t) +// 3. Both processes in p1 and p2 terminate and two new processes are created +// in p3 and p4. +// (p1, t) (p2, t) (t, p3) (t, p4) +// 4. ... +// ... + +READER.PN: + +places: p1 p1b p2 p3 + +transitions: t1 t2 t3 t4 ti t_end + +p1.code: initialize_r(); + +p1b.code: initialize_r_b(); + +p2.code: { + str = read_data(); +} + +p3.code: process_data(str); + +// The following lines describe the structure of the PN + +(p1b, ti, p1) +(p1, t1, p2).{i != 0} // the transition will be taken only if the condition + // between braces is TRUE. +// The expression between braces should only be copied; it does not have to +// be parsed. + +(p2, t2, p3) +(p3, t3, p1) +(p1, t_end).{exit_v == TRUE} +(p1, t4, p3) + +// Note that a process in p1 has three choices. +// if(i != 0) then fire t1 +// else if(exit_v == TRUE) then fire t_end +// else fire t4 + +// Instead of using the conditions above to determine which transitions to +// fire, a function to select them could be specified. + +select function p1.{select_t} // select_t is the name of the function + +// Thus, when there is a token in p1, the function select_f is invoked to +// to determine which transition should be fired. + +nondeterministic places: p1 + +// By default a place p is deterministic. For a deterministic place, one of the +// enabled output transition is selected and then the process waits until the +// supervisor permits its firing. However, if the place p is nondeterministic, +// a protocol such as the one below is used. +// +// 1. The select function is invoked to produce the list of enabled transitions +// in the order of firing preference (first in list is the transition the +// process is most interested to fire). +// 1.b. Optionally, the supervisor is inquired about the transitions it +// enables. However, note that the set of transitions enabled by the +// supervisor can change before the process asks the supervisor for +// permission to fire. +// 2. The list of transitions is sent to the supervisor. Then, the process +// sleeps until the supervisor replies. +// 4. The supervisor gives permission to fire one of the transitions on the +// list. +// +// The main difference between a deterministic and a nondetermistic place is +// as follows. For a deterministic place a transition is selected and then the +// process sleeps until it can continue by firing that transition. For a +// nondeterministic place the choice of the next transition depends on the +// transitions enabled by the supervisor. + + + +WRITER.PN: + +places: p pwr_1 pwr2 + +transitions: t1 t2 t3 t4 + +p.code: process_wrdata(); + +pwr_1.code: write_dest1(); + +pwr_2.code: write_dest2(); + +(p, t1, pwr_1).{dest == 1} +(p, t2, pwr_2) +(pwr_1, t3, p) +(pwr_2, t4, p) + + + +// 3. PROCESS DECLARATIONS + +READER r_group(p1:2, p3:1) // This declares a group of 2+1= 3 READER + // processes. Two processes begin in the state + // p1 and one in the state p3. + // The name of this group of processes is 'r_group'. + // They will be implemented by the READER.PN with + // initial marking m(p1) = 2 and m(p3) = 1. + +READER reader1(p1b) // This declares a single READER process that begins in + // the state p1b. The name of the process is reader1. + +WRITER writer1(p) + +WRITER w_group(p:2) + +ARBITER arbiter(p1) + + +// DEPENDENCIES (transitions that processes synchronize on their own) + +sync reader1.t1 arbiter.t1 + // mentions that the two transitions are synchronized + // (they take place simultaneously). + +sync writer1.t2 arbiter.t2 + +// Remark: all transitions of the external processes are considered to be +// uncontrollable and unobservable, excepting the transitions synchronized +// with transitions of internal processes. Such transitions have the type +// specified by the internal process. + + +// 4. INSTRUCTIONS ON THE DESIGN OF THE SUPERVISOR + +// These describe what the objectives of the supervisor. +// - 'start' commands describe what processes the supervisor should start +// - 'constraints' commands describe what constraints should be enforced +// Constraints have the form +// weighted sum <= free term +// Since we deal with integers, <, >, and >= are all equivalent to this +// form. For instance, a < b is the same as a <= b - 1. +// Disjunctive constraints are also allowed +// (weighted sum <= free term) || (weighted sum 2 <= free term 2) +// The keyword 'live' is used to introduce a list of transitions that +// should always be eventually firable. +// Similarly, the keywords "uncontrollable" and "unobservable" introduce +// lists of transitions that the supervisor should not attempt to control +// and observe, respectively. + +start r_group w_group reader1 writer1 // Unimplemented as of May 2011. + + +// CONSTRAINTS + +r_group.constraints: // these are constraints on the PN of r_group + +live: t2 t4 // requests that the transitions t2 and t4 of r_group be live + // (i.e. they never deadlock). + +uncontrollable: t1 t_end t4 + +unobservable: t1 t_end t4 + + +w_group.constraints: // these are constraints on the PN of w_group + +// Here are some constraints that two writers may not be at the same time +// in the same critical section. + +pwr_1 <= 1 // requests that the marking of pwr_1 does not exceed 1 +pwr_2 <= 1 // requests that the marking of pwr_2 does not exceed 1 + +live: all // requests all transitions of w_group to be live. + + +// NOTE: Some constraint features are not implemented as of May 2011. + +global.constraints: // these are constraints on all PNs + +(r_group.p2 <= 0) || (w_group.pwr_1 <= 0) + +// The line above requests that at all times either the place p2 of r_group +// has no tokens or the place pwr_1 of w_group has no tokens. That is, any +// number of readers may be at the same time in the critical section, but +// a reader and a writer may not be there at the same time. + +q.reader1.t1 - writer1.p <= 0 //'q.' denotes the firing vector. The constraint + // requires that t1 of reader1 may be fired only + // if there is one token in the place p of + // writer1. + +2*reader1.t1 - 2*reader1.t2 + w_group.pwr_2 <= 2 +// reader1.t1 denotes the number of firings of t1. This constraint is +// another way of requesting 2*reader1.p2 + w_group.pwr_2 <= 2 + + + +// More general constraints, such as requiring a certain language to be +// generated, will be implemented when the need will arise. + + + +// 5. OTHER COMMANDS + +print supervisor to debug.log // 'print supervisor to file_name' requests the + // PN produced by the supervisory control + // algorithms to be written to file_name. Added: examples/+README+ =================================================================== --- examples/+README+ (rev 0) +++ examples/+README+ 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,36 @@ + +Here is the list of test examples: + +test2.sp: When running this example a single process (not thread) is started. The process prints messages indicating its state until it terminates. + +Variants: + +test2a.sp: a single processes (not thread) is started. + +test2b.sp: several identical processes (not threads) are started. + +test2c.sp: only one thread (not forked process) will run this time. + +test2d.sp: multiple threads (not forked processes) will run this time. + +test2e.sp: synchronization by means of transitions between single threads. + +test2f.sp: synchronization by means of transitions between multiple threads. + +test2g.sp: same as test2f.sp except for using forked processes (not threads). + + + +test3: A dining philosopher example. + +test3a.sp: Tests that the deadlock prevention function works fine when no deadlock is possible. Only one philosopher with two resources. + +test3b.sp: A test involving two philosophers. + +test3c.sp: A test involving 5 philosophers. + +test3d.sp: A test involving 5 philosophers. Here, the resources (chopsticks) are defined as supervisor components, not as threads. + + + +reader.sp: A reader, inserter, deleter problem. Added: examples/reader.sp =================================================================== --- examples/reader.sp (rev 0) +++ examples/reader.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,124 @@ +// This is a reader/writer/inserter example + +process READER; +build: {<thread>}; + +process DELETER; +build: {<thread>}; + +process INSERTER; +build: {<thread>}; + +READER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +// The main function for a thread/process defines a void* type pointer p___ initialized to zero. +// This is useful when several copies of a thread run in parallel, so that each thread copy +// has a known variable to allocate so that it can save its own data. Further, an initialization +// function can be called if p___ = 0. + +pv.code: { +//evaluate_data(&p___); + debugInfo("READER: Entering the evaluation block"); + sleep(1); +}; + +pc.code: { +//read_data(&p___); + debugInfo("READER: Entering the read block"); + sleep(1); + debugInfo("READER: Exiting the read block"); +}; + +pd.code: { +//process_data(&p___); + debugInfo("READER: Entering the processing block"); + sleep(1); +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +DELETER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +pv.code: { +//d_evaluate_data(&p___); + debugInfo("DELETER: Entering the evaluation block"); + sleep(1); + +}; + +pc.code: { +//delete_data(&p___); + debugInfo("DELETER: Entering the read block"); + sleep(1); + debugInfo("DELETER: Exiting the read block"); + +}; + +pd.code: { +//d_process_data(&p___); + debugInfo("DELETER: Entering the processing block"); + sleep(1); + +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +INSERTER.PN: + +places: pv pc pd; + +transitions: tv tc td; + +pv.code: { +//i_evaluate_data(&p___); + debugInfo("INSERTER: Entering the evaluation block"); + sleep(1); +}; + +pc.code: { +//insert_data(&p___); + debugInfo("INSERTER: Entering the read block"); + sleep(1); + debugInfo("INSERTER: Exiting the read block"); +}; + +pd.code: { +//i_process_data(&p___); + debugInfo("INSERTER: Entering the processing block"); + sleep(1); +}; + +(pv, tv, pc); +(pc, tc, pd); +(pd, td, pv); + + +READER read(pv:5); // defines five reader processes starting in state pv +INSERTER insert(pv:3); +DELETER delete(pv:3); + + +global.constraints: + +insert.pc <= 1; + +// delete.pc <= 1; // not necessary: see constraint below + +// The following should be read.pc + insert.pc + 6*delete.pc <= 6 +// However, the translator has a bug preventing it from recognizing multipliers + +read.pc + insert.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc + delete.pc<= 6; // 6 is max(reader.pc + inserter.pc) Added: examples/test.sp =================================================================== --- examples/test.sp (rev 0) +++ examples/test.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,19 @@ +// This is a test file created in order to check the functionality of the +// pn translator. + +process TST; + +TST.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2; + +(p0, t0); +(t2, p0); +(p1, t1, p2, p0); +(p1, t1, p2, p0); +(p2, t2, p1).{i == 3}; + +TST testpn(p0:2,p1:1); + Added: examples/test2.sp =================================================================== --- examples/test2.sp (rev 0) +++ examples/test2.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + u++; + printf("\nPN3: State 0 u = %d", u); + delay(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + Added: examples/test2a.sp =================================================================== --- examples/test2a.sp (rev 0) +++ examples/test2a.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + u++; + printf("\nPN3: State 0 u = %d", u); + delay(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + Added: examples/test2b.sp =================================================================== --- examples/test2b.sp (rev 0) +++ examples/test2b.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + u++; + printf("\nPN3: State 0 u = %d", u); + delay(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:3,p1:0,p2:0); + +PN3 pr2; + Added: examples/test2c.sp =================================================================== --- examples/test2c.sp (rev 0) +++ examples/test2c.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + Added: examples/test2d.sp =================================================================== --- examples/test2d.sp (rev 0) +++ examples/test2d.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,126 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:4); + +PN3 pr2; + Added: examples/test2e.sp =================================================================== --- examples/test2e.sp (rev 0) +++ examples/test2e.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,134 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + fflush(0); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + fflush(0); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + fflush(0); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:1); + +PN3 pr2; + +sync pr1.t1 pr2.t2; +sync pr1.t4 pr2.t2; +sync pr1.t2 pr2.t1; Added: examples/test2f.sp =================================================================== --- examples/test2f.sp (rev 0) +++ examples/test2f.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,134 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {<thread>}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN: State 0 u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2"); + fflush(0); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + fflush(0); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + fflush(0); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:4); + +PN3 pr2; + +sync pr1.t1 pr2.t2; +sync pr1.t4 pr2.t2; +sync pr1.t2 pr2.t1; Added: examples/test2g.sp =================================================================== --- examples/test2g.sp (rev 0) +++ examples/test2g.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,134 @@ +// This is a test file intended to check the code generation module +// The example of this file was adapted from compexample.c + +process TYPE1; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } + + int f1(int z) { + struct ___trans ___TR[1]; + if(u > 5) { + ___TR[0].no_output = 1; + ___TR[0].label = -4; + ___TR[0].trans = 3; + } + else { + ___TR[0].no_output = 0; + ___TR[0].label = -2; + ___TR[0].trans = 1; + ___TR[0].place = 2; + } + return 1; + } +}; + + +process PN3; + +build: {gcc -g -o $$$.exe $$$.c}; + +include: { + #include<stdio.h> + int v = 0; + + void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +TYPE1.PN: + +places: p0 p1 p2; + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPN (%d): State 0 u = %d", (int) getpid(), u); + //fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN (%d): State 1", (int) getpid()); + //fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN (%d): State 2", (int) getpid()); + //fflush(0); + delay(1); +}; + + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + +(p0, t4, p2); +(p1, t3); +(p2, t2, p0); +(p1, t1, p2); +(p0, t0, p1); + +PN3.PN: + +places: p0 p1; + +transitions: t0 t1 t2; + +p0.code: { + v--; + printf("\nPN3: State 0 v = %d", v); + //fflush(0); + delay2(2); +}; + +p1.code: { + printf("\nPN3: State 1"); + //fflush(0); + delay2(2); +}; + + // Let's create this PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + +(t2, p0); +(p0, t0, p1); +(p1, t1); + + + +TYPE1 pr1(p0:4); + +PN3 pr2; + +sync pr1.t1 pr2.t2; +sync pr1.t4 pr2.t2; +sync pr1.t2 pr2.t1; Added: examples/test3a.sp =================================================================== --- examples/test3a.sp (rev 0) +++ examples/test3a.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,105 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + int pr1_state = 0, i, j, u = 0; + + void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1 (requesting right fork)"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2 (requesting left fork)"); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\nPN: State 3 (eat)"); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t2; + +// --->| t2 +// p | +// t0 |--->O +// + + +(p, t2); (t0, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE left(p:1); +RESOURCE right(p:1); + +PHIL ph1(p0:1); + +sync ph1.t1 left.t2; +sync ph1.t2 right.t2; +sync ph1.t3 left.t0; +sync ph1.t3 right.t0; + +ph1.constraints: + +live: t1; Added: examples/test3b.sp =================================================================== --- examples/test3b.sp (rev 0) +++ examples/test3b.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,113 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\nPhil. State 0 (think) u = %d", u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\nPN: State 1 (requesting right fork)"); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\nPN: State 2 (requesting left fork)"); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\nPN: State 3 (eat)"); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t1 t2 t3; + +// --->| t2 +// p | +// t0 |--->O<---| t1 +// | +// --->| t3 + + +(p, t2); (p, t3); (t0, p); (t1, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE left(p:1); +RESOURCE right(p:1); + +PHIL ph1(p0:1); +PHIL ph2(p0:1); + +sync ph1.t1 left.t2; +sync ph2.t1 right.t2; +sync ph1.t2 right.t3; +sync ph2.t2 left.t3; +sync ph1.t3 left.t0; +sync ph1.t3 right.t0; +sync ph2.t3 left.t1; +sync ph2.t3 right.t1; + +ph1.constraints: +live: t1; + +ph2.constraints: +live: t1; \ No newline at end of file Added: examples/test3c.sp =================================================================== --- examples/test3c.sp (rev 0) +++ examples/test3c.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,113 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\n%s (%s): State 0 (think) u = %d",___INSTANCE,___NAME, u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\n%s (%s): State 1 (requesting right fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\n%s (%s): State 2 (requesting left fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\n%s (%s): State 3 (eat)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t1 t2 t3; + +// --->| t2 +// p | +// t0 |--->O<---| t1 +// | +// --->| t3 + + +(p, t2); (p, t3); (t0, p); (t1, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE r1(p:1); RESOURCE r2(p:1); RESOURCE r3(p:1); RESOURCE r4(p:1); RESOURCE r5(p:1); + +PHIL ph1(p0:1); PHIL ph2(p0:1); PHIL ph3(p0:1); PHIL ph4(p0:1); PHIL ph5(p0:1); + +sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2; + +sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3; + +sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1; + +ph1.constraints: +live: t1; +ph2.constraints: +live: t1; +ph3.constraints: +live: t1; +ph4.constraints: +live: t1; +ph5.constraints: +live: t1; Added: examples/test3d.sp =================================================================== --- examples/test3d.sp (rev 0) +++ examples/test3d.sp 2011-05-13 22:48:19 UTC (rev 248) @@ -0,0 +1,113 @@ +// This is a test file intended to check the code generation module + +process PHIL; + +build: {<thread>}; + +include: { + #include<stdio.h> + static int pr1_state = 0, i, j, u = 0; + + static void delay(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + + +process RESOURCE; + +build: {<supervisor>}; // code is ignored for supervisor components + +include: { + #include<stdio.h> + static int v = 0; + + static void delay2(int n) { + time_t a, b; + for(time(&a), time(&b); a + n > b; time(&b)); + } +}; + + +PHIL.PN: + +places: p0 p1 p2 p3; // think, request right fork, request left fork, eat + +transitions: t0 t1 t2 t3 t4; + +p0.code: { + u++; + fprintf(stderr, "\n%s (%s): State 0 (think) u = %d",___INSTANCE,___NAME, u); + fflush(0); + delay(1); +}; + +p1.code: { + fprintf(stderr, "\n%s (%s): State 1 (requesting right fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p2.code: { + fprintf(stderr, "\n%s (%s): State 2 (requesting left fork)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +p3.code: { + fprintf(stderr, "\n%s (%s): State 3 (eat)",___INSTANCE,___NAME); + fflush(0); + delay(1); +}; + +(p0, t0, p1); (p1, t1, p2); (p2, t2, p3); (p3, t3, p0); + +// t3 +// ------------|<--------------- +// | | +// ->O-->|-->O-->|-->O-->|-->O-- +// p0 t0 p1 t1 p2 t2 p3 + + +RESOURCE.PN: + +places: p; + +transitions: t0 t1 t2 t3; + +// --->| t2 +// p | +// t0 |--->O<---| t1 +// | +// --->| t3 + + +(p, t2); (p, t3); (t0, p); (t1, p); + +p.code: { + fprintf(stderr, "\nResource %s is available", ___NAME); + fflush(0); +}; + +RESOURCE r1(p:1); RESOURCE r2(p:1); RESOURCE r3(p:1); RESOURCE r4(p:1); RESOURCE r5(p:1); + +PHIL ph1(p0:1); PHIL ph2(p0:1); PHIL ph3(p0:1); PHIL ph4(p0:1); PHIL ph5(p0:1); + +sync ph1.t1 r1.t2; sync ph2.t1 r2.t2; sync ph3.t1 r3.t2; sync ph4.t1 r4.t2; sync ph5.t1 r5.t2; + +sync ph1.t2 r5.t3; sync ph2.t2 r1.t3; sync ph3.t2 r2.t3; sync ph4.t2 r3.t3; sync ph5.t2 r4.t3; + +sync ph1.t3 r1.t0 r5.t1; sync ph2.t3 r2.t0 r1.t1; sync ph3.t3 r3.t0 r2.t1; sync ph4.t3 r4.t0 r3.t1; sync ph5.t3 r5.t0 r4.t1; + +ph1.constraints: +live: t1; +ph2.constraints: +live: t1; +ph3.constraints: +live: t1; +ph4.constraints: +live: t1; +ph5.constraints: +live: t1; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-05-11 12:20:46
|
Revision: 247 http://pntool.svn.sourceforge.net/pntool/?rev=247&view=rev Author: miordache Date: 2011-05-11 12:20:38 +0000 (Wed, 11 May 2011) Log Message: ----------- Modified Paths: -------------- newcodegen/ProcessTemplate.c newcodegen/SupervisorTemplate.c newcodegen/plantCompiler.c pnheaders/Makefile pnheaders/main_function.c pnheaders/matrix.c pnheaders/matrix.h pnheaders/pns.c pnheaders/pns.h spnbox/linenf.c spnbox/spnbox.h Modified: newcodegen/ProcessTemplate.c =================================================================== --- newcodegen/ProcessTemplate.c 2011-04-08 22:36:44 UTC (rev 246) +++ newcodegen/ProcessTemplate.c 2011-05-11 12:20:38 UTC (rev 247) @@ -88,6 +88,8 @@ ___send_exit_notification(___pthr); + if(p___) free(p___); + debugInfo("The end of the main function was reached"); return 0; Modified: newcodegen/SupervisorTemplate.c =================================================================== --- newcodegen/SupervisorTemplate.c 2011-04-08 22:36:44 UTC (rev 246) +++ newcodegen/SupervisorTemplate.c 2011-05-11 12:20:38 UTC (rev 247) @@ -314,7 +314,7 @@ for(___ptl = ___pr->tlist, ___i = 0; ___i < ___pr->ntlist; ___i++) if(___t == ___ptl[___i].t) break; - if(___ptl) { // That is, if the transition was found + if(___i < ___pr->ntlist) { // That is, if the transition was found ___pr->fireable = ___t; ___pr->atype |= 2; // set the bit 1 ___qlast->next_in_qelist = ___pr; @@ -1060,14 +1060,21 @@ ___a = IsPermissible(___p); // creates EntryList (qelist) if(___a > 0) { // then the request of ___p can be resolved + // Make sure that ___pn is not in EntryList, since everything in + // EntryList will be removed from the queue + + for(; ___pn; ___pn = ___pn->next_in_queue) + if(!(___pn->atype & 2)) // if not in EntryList + break; + // Grant permission to fire to the processes in EntryList // Remove also from queue and wait list processes in EntryList for(___pa = ___p; ___pa; ___pa = ___pa->next_in_qelist) { // This loop does not affect 'qelist' (EntryList). - // However, it does affect 'queue' and 'wtlist'. - if(___pn == ___pa) // if ___pn will be removed from queued requests - ___pn = ___pn->next_in_queue; // select next queued request + // However, it does affect 'queue' and 'wtlist'. + //if(___pn == ___pa) // if ___pn will be removed from queued requests + // ___pn = ___pn->next_in_queue; // select next queued request ___send_permission_msg(___pa); ___remove_from_queue(___pa); // remove ___pa from queued requests ___remove_from_wtlist(___pa); Modified: newcodegen/plantCompiler.c =================================================================== --- newcodegen/plantCompiler.c 2011-04-08 22:36:44 UTC (rev 246) +++ newcodegen/plantCompiler.c 2011-05-11 12:20:38 UTC (rev 247) @@ -199,6 +199,7 @@ if(procArray[i]->thread) fprintf(plantFile,"\n#define ___THREAD\n"); else fprintf(plantFile,"\n#define ___PROCESS\n"); fprintf(plantFile,"#define ___NAME \"%s\"\n", procArray[i]->name); + fprintf(plantFile,"#define ___INSTANCE \"%s\"\n", procArray[i]->instance); // generate declarations/definitions incl = genDefineBlock(procArray[i], TrInfo[i]); Modified: pnheaders/Makefile =================================================================== --- pnheaders/Makefile 2011-04-08 22:36:44 UTC (rev 246) +++ pnheaders/Makefile 2011-05-11 12:20:38 UTC (rev 247) @@ -1,4 +1,4 @@ -COMPILER=gcc -g +COMPILER=gcc -g -I../spnbox generate: general.o matrix.o pns.o insert.o Modified: pnheaders/main_function.c =================================================================== --- pnheaders/main_function.c 2011-04-08 22:36:44 UTC (rev 246) +++ pnheaders/main_function.c 2011-05-11 12:20:38 UTC (rev 247) @@ -7,6 +7,9 @@ int inline is_verbose() { return verb; } + + + void br_filter(char *p) { // removes beginning and end braces int n; if(!p) @@ -31,16 +34,17 @@ return ! p[i]; } -int th_filter(char** ap) { // filters <thread> commands +int th_filter(char** ap, char* pattern) { // remove pattern from strings char* p = *ap, *p2 = 0; - int i; - if(!p) return 0; + int i, n; + if(!p || !pattern) return 0; + n = strlen(pattern); for(i = 0; p[i]; i++) { if(p[i] == ' ' || p[i] == '\t') continue; - if(!strncmp(p+i, "<thread>", 8)) { - if(!is_empty(p+i+8)) // else p2 remains equal to zero - asprintf(&p2, "%s", p+i+8); + if(!strncmp(p+i, pattern, n)) { + if(!is_empty(p+i+n)) // else p2 remains equal to zero + asprintf(&p2, "%s", p+i+n); free(*ap); *ap = p2; return 1; @@ -66,8 +70,15 @@ continue; br_filter(sp->process_array[i]->build); br_filter(sp->process_array[i]->include); - if(th_filter(&(sp->process_array[i]->build))) - sp->process_array[i]->thread = 1; + //if(th_filter(&(sp->process_array[i]->build))) + //sp->process_array[i]->thread = 1; + + // Is this a thread? + sp->process_array[i]->thread = th_filter(&(sp->process_array[i]->build),\ + "<thread>"); + // Is this a supervisor component? + sp->process_array[i]->supervisor=th_filter(&(sp->process_array[i]->build),\ + "<supervisor>"); pn = sp->process_array[i]->pn; if(pn) { if(pn->segment) @@ -87,23 +98,28 @@ int main(int na, char* argv[]) { - int i, j, l1, l2, UCcnt, UOcnt, *Tuc, *Tuo, *UClst, *UOlst; - int labelcount = 0, finish = 0; + int i, j, l1, l2, UCcnt, UOcnt, LVcnt, *Tuc, *Tuo, *Tlive, *UClst, *UOlst, *LVlst; + int labelcount = 0, finish = 0, plcnum, spcnum; char* input, *build; FILE* f; specs *sp; syncc *snc; - pns pn, *apnsv; + pns pn, pn1, *apnsv; + process **plant_array, **spv_array; matrix L, C, H; int *B; struct myinsert ins; - linenf_r lin_res; + linenf_r lin_res, lin_res2; + dp_p LVparams; + dp_r LVresult; struct synclist *syncl, *syncl2; struct sync_element *syn_el, *syn_el2; struct label_lst* lls; TrData** TInf; + // 1. INITIALIZATION + ins = InitInsert(512); // used to store command line parameters verb = 0; input = 0; @@ -168,11 +184,15 @@ return 0; } - // Call the translator + // 2. TRANSLATE SPECIFICATION sp = ScanInput(input); - if(!sp) // check translator result + + // 2.1. Check translator result + + if(!sp) return 1; + if(sp->process_num <= 0) { fprintf(stderr, "No processes defined! Nothing to do.\n"); dealloc_specs(sp); @@ -180,23 +200,40 @@ return 0; } - sp_filter(sp); // remove extra braces + sp_filter(sp); // detect settings and remove extra braces if(is_verbose() >= 3) { // For debugging for(i = 0; i < sp->process_num; i++) { printf("\n\n======================================================"); - printf("\nPROCESS NAME: %s\n", sp->process_array[i]->name); + if(sp->process_array[i]->supervisor) + printf("\nSUPERVISOR COMPONENT: "); + else if(sp->process_array[i]->thread) + printf("\nTHREAD NAME: "); + else + printf("\nPROCESS NAME: "); + printf("%s (%s)\n", sp->process_array[i]->instance, sp->process_array[i]->name); displaypn(*(sp->process_array[i]->pn), stdout); } } + for(i = 0; i < sp->process_num; i++) + if(!sp->process_array[i]->supervisor) + break; - // Label the PNs + if(i >= sp->process_num) { + fprintf(stderr, "No plant components defined! Nothing to do.\n"); + dealloc_specs(sp); + if(build) free(build); + return 0; + } + + // 2.2 Label the PNs + for(i = 0; i < sp->process_num; i++) updatepn(sp->process_array[i]->pn, "freelabel", &labelcount); - // Deal with synchronization constraints + // 2.2.1 Deal with synchronization constraints for(i = 1; i; ) /* i = 0 indicates when loop may end */ for(i = 0, snc = sp->synclist; snc; snc = snc->next) { @@ -208,7 +245,7 @@ } } - // Obtain SC specification. Currently: + // 2.3 Obtain SC specification. Currently: // extract the L, C, H, and b matrices (more complex specs to be done later) extractLHCB(sp, &pn, &L, &H, &C, &B); @@ -219,18 +256,23 @@ printLHCB(&pn, &L, &H, &C, B, -1, stdout); } - // Perform SC + // 3. SUPERVISORY CONTROL + // 3.1 Enforce SC specs (linear constraints supported currently) + Tuc = tcalloc(pn.tnum, sizeof(*Tuc)); Tuo = tcalloc(pn.tnum, sizeof(*Tuo)); + Tlive = tcalloc(pn.tnum, sizeof(*Tlive)); if(pn.t) for(i = 0; i < pn.tnum; i++) { Tuc[i] = pn.t[i].uncontrollable; Tuo[i] = pn.t[i].unobservable; + Tlive[i] = pn.t[i].live; } UCcnt = findIndices(Tuc, pn.tnum, sizeof(*Tuc), &UClst); UOcnt = findIndices(Tuo, pn.tnum, sizeof(*Tuo), &UOlst); + LVcnt = findIndices(Tlive, pn.tnum, sizeof(*Tlive), &LVlst); lin_res = linenf(&pn.out, &pn.in, &L, B, pn.marking, &H, &C, \ UCcnt, UClst, UOcnt, UOlst); @@ -241,64 +283,178 @@ printLHCB(&pn, &lin_res.Lf, 0, &lin_res.Cf, lin_res.bf, -1, stdout); } - free(Tuc); free(Tuo); free(UClst); free(UOlst); - // Check whether SC was successful if(strcmp(lin_res.how, "OK")) merror(0, "MAIN FUNCTION: SC has failed. Relax the specification\n\ such as by reducing the number of uncontrollable and unobservable transitions"); - // Enforce liveness + // 3.2. Enforce liveness - // no liveness enforcement at this time + // - Liveness enforcement is applied to the closed-loop + // - Check whether the initial marking satisfies the constraints. + // - The result of liveness enforcement is enforced on the closed-loop + // with linenf and no uncontro. and unobs. transitions, since the result + // is guaranteed to be admissible. + // - The supervisor is extracted from the closed-loop reported by linenf via + // getSupervisor - // Extract supervisor as a pn + // For future work: + // - calculate initial marking constraints: check marking constraints satisfied by initial marking of plant. + // - check if responsiveness is guaranteed. + // - To help convergence, invariants from previous constraints should be + // communicated by means of the L, B parameters of the function dp. + + if(LVcnt) { // If T-liveness enforcement has been requested + if(is_verbose() >= 3) { // For debugging + printf("\n\n======================================================"); + printf("\n\nLiveness enforcement has been requested. This may take a while ...\n"); + } + // Initialize parameters + memset(&LVparams, 0, sizeof(LVparams)); + LVparams.Dm = lin_res.Dfm; LVparams.Dp = lin_res.Dfp; + LVparams.Tuc = UClst; LVparams.TucCount = UCcnt; + LVparams.Tuo = UOlst; LVparams.TuoCount = UOcnt; + LVparams.IncludeT = LVlst; LVparams.IncludeCount = LVcnt; + LVparams.option = 12 + (is_verbose() >= 4); + + LVresult = dp(&LVparams); // apply the T-liveness enforcement procedure + if(strcmp(LVresult.how, "OK")) + merror(0, "MAIN FUNCTION: Liveness enforcement has failed. Relax the specification\nsuch as by reducing the number of uncontrollable and unobservable transitions.\nSee also the log file of the liveness enforcement algorithm."); + + // Verify L*m0 >= B + if(!TestLCB(&LVresult.Lf, lin_res.ms0, 0,0, GREATER_OR_EQUAL, LVresult.Bf)) + merror(0, "MAIN FUNCTION: Liveness enforcement has failed due to insufficient initial \nmarking (the initial marking does not satisfy the L*m >= B constraints). \nRelax the specification such as by increasing the initial marking and \nreducing the number of uncontrollable and unobservable transitions. See also \nthe log file of the liveness enforcement algorithm."); + + // Verify L0*m0 >= b0 + if(!TestLCB(&LVresult.L0f, lin_res.ms0,0,0,GREATER_OR_EQUAL, LVresult.B0f)) + merror(0, "MAIN FUNCTION: Liveness enforcement has failed due to insufficient initial \nmarking (the initial marking does not satisfy the L0*m >= B0 constraints). \nRelax the specification such as by increasing the initial marking and \nreducing the number of uncontrollable and unobservable transitions. See also \nthe log file of the liveness enforcement algorithm."); + + // Convert L*m >= B to L*m <= B (the input expected by linenf) + InvertSignOfMatrix(&LVresult.Lf); // L = -L + InvertSignOfVector(LVresult.Bf, NumberOfRows(LVresult.Lf)); // B = -B + + lin_res2 = linenf(&lin_res.Dfm, &lin_res.Dfp, &LVresult.Lf, LVresult.Bf,\ + lin_res.ms0, 0, 0, 0, 0, 0, 0); + // no uncontr. and unobs. transitions have to be passed to linenf + // since constraints are admissible + + DeallocateDp(&LVresult); DeallocateLinenf(&lin_res); + + lin_res = lin_res2; + } + + free(Tuc); free(Tuo); free(Tlive); free(UClst); free(UOlst); free(LVlst); + + // 3.3 Extract supervisor as a pn + apnsv = getSupervisor(&pn, &lin_res.Dfm, &lin_res.Dfp, lin_res.ms0); if(is_verbose() >= 3) { // For debugging printf("\n\n======================================================"); - printf("\nCOMPOSED PN\n"); + printf("\nCOMPOSED PLANT PN PLUS PREDEFINED SUPERVISOR COMPONENTS\n"); displaypn(pn, stdout); printf("\n\n======================================================"); if(apnsv) { - printf("\nSUPERVISOR PN\n"); + printf("\nSC GENERATED SUPERVISOR\n"); displaypn(*apnsv, stdout); } else - printf("\nNO SUPERVISOR PN\n"); + printf("\nNO SC GENERATED SUPERVISOR\n"); } deallocpn(&pn); - // need functions to free linenf_r structures and similar structures - // Generate code + // 4. GENERATE CODE + // 4.1 Separate supervisor components from plant components + spv_array = tcalloc(sp->process_num, sizeof(*spv_array)); + plant_array = tcalloc(sp->process_num, sizeof(*plant_array)); + for(i = 0, plcnum = 0, spcnum = 0; i < sp->process_num; i++) { + if(sp->process_array[i]->supervisor) { + spv_array[spcnum] = sp->process_array[i]; + spcnum++; + } + else { + plant_array[plcnum] = sp->process_array[i]; + plcnum++; + } + } - // Obtain also a synclist structure with the sync data + // 4.2 Compose supervisor components with SC generated supervisor. + + pn = pn_composition(spv_array, spcnum); + pn1 = composepn(apnsv, &pn); + if(apnsv) + free(apnsv); + deallocpn(&pn); // free intermediary result + apnsv = &pn1; + + if(is_verbose() >= 3 && spcnum) { + // If spcnum != 0, then SC supervisor and final supervisor are different. + printf("\n\n======================================================"); + if(apnsv) { + printf("\nFINAL SUPERVISOR\n"); + displaypn(*apnsv, stdout); + } + } + + // 4.3 Obtain a synclist structure with the sync data for plant processes + + /* May be deleted after testing the change lls = get_label_list(sp->process_array, sp->process_num); syncl = get_synclist(lls, sp->process_array); TInf = get_TrData(apnsv, sp->process_array, sp->process_num, lls); + */ - //exit(1); + lls = get_label_list(plant_array, plcnum); + syncl = get_synclist(lls, plant_array); + TInf = get_TrData(apnsv, plant_array, plcnum, lls); - CodeGenerator(apnsv, sp->name, sp->process_array, sp->process_num,\ + // Call the code generation function + + /*CodeGenerator(apnsv, sp->name, sp->process_array, sp->process_num, \ syncl, TInf, build); + */ - // Free memory + CodeGenerator(apnsv, sp->name, plant_array, plcnum, syncl, TInf, build); + + // 5. TERMINATE + if(apnsv) { deallocpn(apnsv); - free(apnsv); + //free(apnsv); } + free(plant_array); + free(spv_array); dealloc_specs(sp); if(build) free(build); free_label_list(lls); free_synclist(syncl); - free_TrData(TInf, sp->process_num); + free_TrData(TInf, plcnum); return 0; } + + +/* Future improvements for deadlock prevention. + + Currently deadlock prevention does not account for determinism. Thus, + some potential deadlocks may remain undetected. + + The following function could be defined in the future to help the deadlock + prevention procedure converge. Additionally, a function for initial + markings could be developed. + +matrix getLB(matrix Lf, matrix Cf, int *Bf, int** B) { + // Outputs a matrix L such that L*m <= B contains the rows of + // Lf*m + Cf*v <= Bf on which Cf is zero. B is also allocated and + // initialized. + +} + +*/ Modified: pnheaders/matrix.c =================================================================== --- pnheaders/matrix.c 2011-04-08 22:36:44 UTC (rev 246) +++ pnheaders/matrix.c 2011-05-11 12:20:38 UTC (rev 247) @@ -452,6 +452,89 @@ +inline int TestCondition(int v, int type, int w) { +/* Checks whether 'v' and 'w' (in this order) are in the relationship + described by 'type', where 'type' may have one of the values in the + range GREATER, ..., LESS. If the relationship is satisfied, the + function returns 1. Else, it returns 0. */ + + int a, b; + + if(type < 0) { + type = -type; + a = v; + b = w; + } + else { + a = w; + b = v; + } + switch(type) { + case GREATER: + if(a >= b) + return 0; + break; + case GREATER_OR_EQUAL: + if(a > b) + return 0; + break; + case EQUAL: + if(a != b) + return 0; + break; + default: + return 0; + } + return 1; +} + +int TestExpression(const int* v, int c, const int* w, int len) { +/* The vectors 'v' and 'w' are compared for the first 'len' elements. + 'c' may have one of the values in the range GREATER, ..., LESS. + The return value is as follows: + * If 'len' <= 0 or v = 0 or w = 0 the function returns a nonzero value; + * Else if 'c' is none of the above, the function returns zero; + * Else if the expression is satisfied for each pair of elements v[i] and + w[i], the function returns a nonzero value; + * Else the function returns zero. */ + + const int *a, *b; + int i; + + if(!v || !w || len <= 0) + return 1; + if(c < 0) { + a = v; + b = w; + c = -c; + } + else { + a = w; + b = v; + } + switch(c) { + case GREATER: + for(i = 0; i < len; i++) + if(a[i] >= b[i]) + return 0; + break; + case GREATER_OR_EQUAL: + for(i = 0; i < len; i++) + if(a[i] > b[i]) + return 0; + break; + case EQUAL: + for(i = 0; i < len; i++) + if(a[i] != b[i]) + return 0; + break; + default: + return 0; + } + return 1; +} + + void free2Darray(int** ar, int nr) { /* Used to deallocate an array created with matrix2array or vector2array; nr is the number of rows */ @@ -501,7 +584,23 @@ memset(m, 0, sizeof(*m)); } +inline void InvertSignOfMatrix(matrix* m) { + int i, j, r, n; + if(!m) return; + r = NumberOfRows(*m); + n = NumberOfColumns(*m); + for(i = 0; i < r; i++) + for(j = 0; j < n; j++) + SetMatrixEl(m, i, j, -GetMatrixEl(m, i, j)); +} +inline void InvertSignOfVector(int* v, int len) { + int i; + if(!v) return; + for(i = 0; i < len; i++) + v[i] = -v[i]; +} + /* To do: - _setmatrel3 does not deallocate elements set to zero - consider better matrix representations. For instance, for type 3 Modified: pnheaders/matrix.h =================================================================== --- pnheaders/matrix.h 2011-04-08 22:36:44 UTC (rev 246) +++ pnheaders/matrix.h 2011-05-11 12:20:38 UTC (rev 247) @@ -127,6 +127,9 @@ int** matrix2array(matrix m); /* Converts a matrix object to an array of integers: result[i][j] = elem(i,j)*/ +void free2Darray(int** ar, int nr); +/* Use to deallocate an array created with matrix2array or vector2array; nr is the number of rows */ + int findIndices(void* vect, int n, int esize, int** answer ); /* Finds the indices of the nonzero elements of 'vect'. Here, 'vect' is a vector of 'n' elements. Each element of 'vect' has the size 'esize'. The @@ -137,7 +140,35 @@ This function is similar to the find function of Matlab. */ -void free2Darray(int** ar, int nr); -/* Use to deallocate an array created with matrix2array or vector2array; nr is the number of rows */ +// Changes in the following can affect TestCondition and TestExpression ! +#define GREATER 2 +#define GREATER_OR_EQUAL 1 +#define EQUAL 0 +#define LESS_OR_EQUAL -1 +#define LESS -2 +inline int TestCondition(int v, int type, int w); +/* Checks whether 'v' and 'w' (in this order) are in the relationship + described by 'type', where 'type' may have one of the values in the + range GREATER, ..., LESS. If the relationship is satisfied, the + function returns 1. Else, it returns 0. */ + +int TestExpression(const int* v, int c, const int* w, int len); +/* The vectors 'v' and 'w' are compared for the first 'len' elements. + 'c' may have one of the values in the range GREATER, ..., LESS above. + The return value is as follows: + * If 'len' <= 0 or v = 0 or w = 0 the function returns a nonzero value; + * Else if 'c' is none of the above, the function returns zero; + * Else if the expression is satisfied for each pair of elements v[i] and + w[i], the function returns a nonzero value; + * Else the function returns zero. */ + +inline void InvertSignOfMatrix(matrix* m); /* m = -m */ + +inline void InvertSignOfVector(int* v, int len); /* v = -v */ + + +// matrixmath.h and extendedmatrix.h of spnbox have additional matrix functions + + #endif Modified: pnheaders/pns.c =================================================================== --- pnheaders/pns.c 2011-04-08 22:36:44 UTC (rev 246) +++ pnheaders/pns.c 2011-05-11 12:20:38 UTC (rev 247) @@ -4,8 +4,8 @@ ****************************************************************************/ #include"pns.h" +#include"matrixmath.h" - void d2dd(const matrix* D, matrix* Dm, matrix* Dp) { int i, j, nr, nc; mtype x; @@ -525,41 +525,18 @@ -pns copypn(pns *src) { - pns dst; +inline pns _copytrans(pns dst, pns *src) { + /* This is a subroutine of copypn and composepn for copying transitions + and arcs from src to dst. */ + + int i; arcs *pa; const arcs *pb; struct placelist *pd; const struct placelist *ps; - int i; - dst = createpn("pnum tnum mDm mDp", src->pnum, src->tnum, src->out, src->in); - if(src->marking) updatepn(&dst, "m0", src->marking); - if(src->C) updatepn(&dst, "C", src->C); - if(src->place_name) - for(i = 0; i < src->pnum; i++) - if(src->place_name[i]) - updatepn(&dst, "place_name", i, src->place_name[i]); - if(src->segment) - for(i = 0; i < src->pnum; i++) - if(src->segment[i]) - updatepn(&dst, "segment", i, src->segment[i]); - if(src->select) - for(i = 0; i < src->pnum; i++) - if(src->select[i]) - updatepn(&dst, "select", i, src->select[i]); - if(src->trans_name) - for(i = 0; i < src->tnum; i++) - if(src->trans_name[i]) - updatepn(&dst, "trans_name", i, src->trans_name[i]); if(src->t) { - dst.t = tcalloc(dst.tnum, sizeof(src->t[0])); - for(i = 0; i < src->tnum; i++) - dst.t[i] = src->t[i]; + dst.t = tcalloc(src->tnum, sizeof(src->t[0])); + memcpy(dst.t, src->t, (src->tnum)*sizeof(src->t[0])); } - if(src->p) { - dst.p = tcalloc(dst.pnum, sizeof(src->p[0])); - for(i = 0; i < src->pnum; i++) - dst.p[i] = src->p[i]; - } if(src->arc_list) { /* copy the list of arcs */ dst.arc_list = tcalloc(dst.tnum, sizeof(*(dst.arc_list))); for(i = 0; i < src->tnum; i++) { @@ -592,7 +569,39 @@ } +pns copypn(pns *src) { + pns dst; + int i; + dst = createpn("pnum tnum mDm mDp", src->pnum, src->tnum, src->out, src->in); + if(src->marking) updatepn(&dst, "m0", src->marking); + if(src->C) updatepn(&dst, "C", src->C); + if(src->place_name) + for(i = 0; i < src->pnum; i++) + if(src->place_name[i]) + updatepn(&dst, "place_name", i, src->place_name[i]); + if(src->segment) + for(i = 0; i < src->pnum; i++) + if(src->segment[i]) + updatepn(&dst, "segment", i, src->segment[i]); + if(src->select) + for(i = 0; i < src->pnum; i++) + if(src->select[i]) + updatepn(&dst, "select", i, src->select[i]); + if(src->trans_name) + for(i = 0; i < src->tnum; i++) + if(src->trans_name[i]) + updatepn(&dst, "trans_name", i, src->trans_name[i]); + if(src->p) { + dst.p = tcalloc(dst.pnum, sizeof(src->p[0])); + for(i = 0; i < src->pnum; i++) + dst.p[i] = src->p[i]; + } + return _copytrans(dst, src); +} + + + void deallocpn(pns *pn) { int i, pnum, tnum; pnum = pn->pnum; @@ -812,17 +821,21 @@ /* Next we deal with the case when pn1 or pn2 does not have transitions */ if(!nt1 || !nt2) { - if(!nt1) { /* if pn1 does not have transitions */ - if(pn2->t) { /* if pn2 has transitions and transition information */ - pn.t = tcalloc(pn.tnum,sizeof(pn.t[0])); - memcpy(pn.t, pn2->t, nt2*sizeof(pn.t[0])); /* copy info */ - } - } + if(!nt1) /* if pn1 does not have transitions */ + pn = _copytrans(pn, pn2); // copies transitions and trans arcs to pn else /* if pn2 does not have transitions */ - if(pn1->t) { /* if pn1 has transitions and transition information */ - pn.t = tcalloc(pn.tnum,sizeof(pn.t[0])); - memcpy(pn.t, pn1->t, nt1*sizeof(pn.t[0])); /* copy info */ + pn = _copytrans(pn, pn1); + // Copy also input/output matrix elements + for(j = 0; j < nt1; j++) + if(np1) { + Copy2ZeroColumn(&(pn1->in),j,&(pn.in),j,0); + Copy2ZeroColumn(&(pn1->out),j,&(pn.out),j,0); } + for(j = 0; j < nt2; j++) + if(np2) { + Copy2ZeroColumn(&(pn2->in),j,&(pn.in),j,np1); + Copy2ZeroColumn(&(pn2->out),j,&(pn.out),j,np1); + } return pn; } @@ -910,6 +923,34 @@ } + +pns pn_composition(process** process_array, int num) { + /* Composes the PNs in the process array and returns the result. */ + pns pn, pn1, *apn; + int i; + + if(num <= 0 || !process_array) + memset(&pn, 0, sizeof(pn)); // return null pn + else if(num == 1) + pn = copypn(process_array[0]->pn); + else { + apn = process_array[0]->pn; + for(i = 1; i < num; i++) { + if(i > 1) { + pn1 = pn; // save intermediary result for subsequent deallocation + apn = &pn1; + } + pn = composepn(apn, process_array[i]->pn); + if(i > 1) + deallocpn(&pn1); // free intermediary result + } + } + + return pn; +} + + + int isfreelabeled(pns *rpn) { int i, j, label; @@ -1175,9 +1216,9 @@ /* This is a temporary implementation; future work should take in account that sp can contain more general specifications */ -/* The implementation assumes that each pn is free labeled and that no disjunctive - constraints are present. */ +/* The implementation assumes that no disjunctive constraints are present. */ + int find_var_index(variable* var, pns* pn, specs* sp) { int i, k; int lab; @@ -1199,7 +1240,7 @@ merror(0, "EXTRACTLHCB: index %d >= tran. number (%d)", var->index, var->pn->tnum); lab = var->pn->t[var->index].l; for(i = 0; i < pn->tnum; i++) - if(pn->t[i].l == lab) + if(pn->t[i].l == lab) // Assumes free-labeled PN return i; merror(0, "EXTRACTLHCB: Variable does not match specified PNs"); } @@ -1215,6 +1256,9 @@ /* Find the composed PN */ + *pn = pn_composition(sp->process_array, sp->process_num); + + /* May be deleted after testing pn_composition above if(sp->process_num == 1) *pn = copypn(sp->process_array[0]->pn); else { @@ -1229,6 +1273,7 @@ deallocpn(&pn1); // dealloc intermediary result } } + */ /* Find cnum, the number of constraints */ for(c = sp->constraint_list, cnum = 0; c; c = c->next, cnum++); @@ -1238,7 +1283,10 @@ AllocateMatrixType(3, L, cnum, pn->pnum); AllocateMatrixType(3, H, cnum, pn->tnum); AllocateMatrixType(3, C, cnum, pn->tnum); - *B = tcalloc(cnum, sizeof(**B)); + if(!cnum) + *B = 0; + else + *B = tcalloc(cnum, sizeof(**B)); /* Initialize L, H, C, B */ @@ -1361,6 +1409,55 @@ } /*************************************************************************** + TestLCB +****************************************************************************/ + +int TestLCB(matrix* L, int* m, matrix* C, int* v, int type, int* B) { + +/* 'type' should be GREATER, LESS, EQUAL, GREATER_OR_EQUAL, or LESS_OR_EQUAL + (which are defined in matrix.h). + + The function calculates L*m + C*v and compares the result to B. + If all elements of the result satisfy the 'type' constraint when compared + to B, then the function returns 1. Otherwise, it returns zero. + + Unused entries may be set to zero. For instance, TestLCB(L,m,0,0,LESS,B,n) + checks whether L*m < B. */ + + int i, a, n; + char zL, zC; + + if(n <= 0) + return 1; + + zL = !L || !m; + zC = !C || !v; + + if(!zL) zL = zL || ! NumberOfRows(*L) || ! NumberOfColumns(*L); + if(!zC) zC = zC || ! NumberOfRows(*C) || ! NumberOfColumns(*C); + + if(!B || (zL && zC)) + return zL && zC && !B; + + if(!zL) + n = NumberOfRows(*L); + else + n = NumberOfRows(*C); + + for(i = 0; i < n; i++) { + a = 0; + if(!zL) + a = MultiplyVector(L, (matrix*) m, i, -1, 0); + if(!zC) + a += MultiplyVector(C, (matrix*) v, i, -1, 0); + if(!TestCondition(a, type, B[i])) + return 0; + } + return 1; +} + + +/*************************************************************************** GETSUPERVISOR ****************************************************************************/ @@ -1370,7 +1467,13 @@ closed-loop input (Dcp) and output (Dcm) matrices and from the initial marking of the closed-loop (ms0). - This function assumes free-labeled PNs. */ + This function assumes that the set of transitions of the closed-loop is + the same as the set of transitions of the plant. Two cases in which + this is true are the following: + - free-labeled closed-loop PN. + - the supervisor implements Lm + Hq + Cv \leq b via SBPI. (Since SBPI does + not add new transitions). +*/ pns *apnsv; int tnum, i, j, k, l, t, pcn, tcn, flag, *labels; @@ -1750,7 +1853,12 @@ } +//========================================================================= + +int TestConstraint(); + + /* Things to do: - composepn ignores the text fields of the pns. - composepn assumes that the places in the two pns are distinct. Modified: pnheaders/pns.h =================================================================== --- pnheaders/pns.h 2011-04-08 22:36:44 UTC (rev 246) +++ pnheaders/pns.h 2011-05-11 12:20:38 UTC (rev 247) @@ -359,6 +359,7 @@ int type:1; /* type = 1 indicates an external process */ int start:1; /* start = 1 if the supervisor should start this process */ char thread:1; /* set to 1 if process should be implemented as a thread */ + char supervisor:1; /* set to 1 if the process is a supervisor component */ } process; @@ -388,14 +389,37 @@ use n < 0. The pn parameter specifies the PN on which the constraints are defined. If one or more of L, H, or C is unavailable, enter 0. */ +int TestLCB(matrix* L, int* m, matrix* C, int* v, int type, int* B); +/* 'type' should be GREATER, LESS, EQUAL, GREATER_OR_EQUAL, or LESS_OR_EQUAL + (which are defined in matrix.h). + + The function calculates L*m + C*v and compares the result to B. + If all elements of the result satisfy the 'type' constraint when compared + to B, then the function returns 1. Otherwise, it returns zero. + + Unused entries may be set to zero. For instance, TestLCB(L,m,0,0,LESS,B,n) + checks whether L*m < B. */ + + +pns pn_composition(process** process_array, int num); +/* Composes the PNs in the process array and returns the result. */ + + pns* getSupervisor(pns* pn, matrix* Dcm, matrix* Dcp, int* ms0); /* Extracts the PN representing the supervisor from the plant PN (pn), the closed-loop input (Dcp) and output (Dcm) matrices and from the initial - marking of the closed-loop (ms0). This function assumes free-labeled PNs. */ + marking of the closed-loop (ms0). + This function assumes that the set of transitions of the closed-loop is + the same as the set of transitions of the plant. Two cases in which + this is true are the following: + - free-labeled closed-loop PN. + - the supervisor implements Lm + Hq + Cv \leq b via SBPI. (Since SBPI does + not add new transitions). */ + void dealloc_specs(specs* sp); void dealloc_process(process* p); Modified: spnbox/linenf.c =================================================================== --- spnbox/linenf.c 2011-04-08 22:36:44 UTC (rev 246) +++ spnbox/linenf.c 2011-05-11 12:20:38 UTC (rev 247) @@ -670,7 +670,7 @@ } } /*If m0 is given, b must be given*/ - if(m0 && ! b) + if(m0 && ! b && Constraints) { merror(0, "LINENF: The constraint vector b must be given if an initial marking m0 is given"); return -1; Modified: spnbox/spnbox.h =================================================================== --- spnbox/spnbox.h 2011-04-08 22:36:44 UTC (rev 246) +++ spnbox/spnbox.h 2011-05-11 12:20:38 UTC (rev 247) @@ -702,7 +702,7 @@ array. -Written for Matlab by Marian V. Iordache, mio...@nd... +Written for Matlab by Marian V. Iordache Original Matlab code extended the Matlab pn2acpn code written on M. Iordache -- Sep. 4, 2000 and revised on Oct. 24, 2001 @@ -1192,7 +1192,7 @@ /* GCDV greatest common divisor of a vector/matrix. Uses GCD. -Written by Marian V. Iordache, mio...@nd... +Written by Marian V. Iordache C Usage: If m is a null pointer, the function returns the gcd of the row and column This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <mio...@us...> - 2011-04-08 22:36:53
|
Revision: 246 http://pntool.svn.sourceforge.net/pntool/?rev=246&view=rev Author: miordache Date: 2011-04-08 22:36:44 +0000 (Fri, 08 Apr 2011) Log Message: ----------- update Modified Paths: -------------- 2009_version/codegen/Makefile Makefile newcodegen/Makefile pnheaders/insert.c Added Paths: ----------- 2009_version/ 2009_version/Makefile09 2009_version/codegen/ 2009_version/pnheaders/ 2009_version/spnbox09/ 2009_version/spnbox09/Makefile 2009_version/spnbox09/MemoryManager.c 2009_version/spnbox09/MemoryManager.h 2009_version/spnbox09/actn.c 2009_version/spnbox09/admcon.c 2009_version/spnbox09/asiph.c 2009_version/spnbox09/avpr.c 2009_version/spnbox09/chkcons.c 2009_version/spnbox09/deallocation.c 2009_version/spnbox09/dp.c 2009_version/spnbox09/dp4.c 2009_version/spnbox09/extendedmatrix.c 2009_version/spnbox09/extendedmatrix.h 2009_version/spnbox09/fvpr.c 2009_version/spnbox09/gcdv.c 2009_version/spnbox09/ilpadm.c 2009_version/spnbox09/invar.c 2009_version/spnbox09/ipslv.c 2009_version/spnbox09/ipsolve.c 2009_version/spnbox09/isadm.c 2009_version/spnbox09/issiph.c 2009_version/spnbox09/linenf.c 2009_version/spnbox09/matrixmath.c 2009_version/spnbox09/matrixmath.h 2009_version/spnbox09/mroadm.c 2009_version/spnbox09/msplit.c 2009_version/spnbox09/nltrans.c 2009_version/spnbox09/pn2acpn.c 2009_version/spnbox09/pn2eacpn.c 2009_version/spnbox09/reduce.c 2009_version/spnbox09/spnbox.h 2009_version/spnbox09/supervis.c 2009_version/spnbox09/tactn.c 2009_version/spnbox09/tests/ 2009_version/spnbox09/tests/Makefile 2009_version/spnbox09/tests/StructuredIO.c 2009_version/spnbox09/tests/StructuredIO.h 2009_version/spnbox09/tests/pnexample.c 2009_version/spnbox09/tests/test-actn.c 2009_version/spnbox09/tests/test-actn.txt 2009_version/spnbox09/tests/test-admcon.c 2009_version/spnbox09/tests/test-asiph.c 2009_version/spnbox09/tests/test-asiph.txt 2009_version/spnbox09/tests/test-avpr.c 2009_version/spnbox09/tests/test-avpr.txt 2009_version/spnbox09/tests/test-dp.c 2009_version/spnbox09/tests/test-dp.txt 2009_version/spnbox09/tests/test-extendedmatrix.c 2009_version/spnbox09/tests/test-extendedmatrix.txt 2009_version/spnbox09/tests/test-fvpr.c 2009_version/spnbox09/tests/test-fvpr.txt 2009_version/spnbox09/tests/test-gcdv.c 2009_version/spnbox09/tests/test-gcdv.txt 2009_version/spnbox09/tests/test-ilpadm.c 2009_version/spnbox09/tests/test-ilpadm.txt 2009_version/spnbox09/tests/test-invar.c 2009_version/spnbox09/tests/test-invar.txt 2009_version/spnbox09/tests/test-ipslv.c 2009_version/spnbox09/tests/test-ipsolve.c 2009_version/spnbox09/tests/test-ipsolve.txt 2009_version/spnbox09/tests/test-isadm.c 2009_version/spnbox09/tests/test-isadm.txt 2009_version/spnbox09/tests/test-issiph.c 2009_version/spnbox09/tests/test-issiph.txt 2009_version/spnbox09/tests/test-linenf.c 2009_version/spnbox09/tests/test-linenf.txt 2009_version/spnbox09/tests/test-matrixmath.c 2009_version/spnbox09/tests/test-matrixmath.txt 2009_version/spnbox09/tests/test-mroadm.c 2009_version/spnbox09/tests/test-mroadm.txt 2009_version/spnbox09/tests/test-msplit.c 2009_version/spnbox09/tests/test-msplit.txt 2009_version/spnbox09/tests/test-nltrans.c 2009_version/spnbox09/tests/test-nltrans.txt 2009_version/spnbox09/tests/test-pn2acpn.c 2009_version/spnbox09/tests/test-pn2acpn.txt 2009_version/spnbox09/tests/test-pn2eacpn.c 2009_version/spnbox09/tests/test-pn2eacpn.txt 2009_version/spnbox09/tests/test-reduce.c 2009_version/spnbox09/tests/test-reduce.txt 2009_version/spnbox09/tests/test-supervis.c 2009_version/spnbox09/tests/test-supervis.txt 2009_version/spnbox09/tests/test-tactn.c 2009_version/spnbox09/tests/test-tactn.txt 2009_version/spnbox09/tests/test.c 2009_version/spnbox09/tests/test.h LICENSE/ LICENSE/ANTLR3_LICENSE.txt LICENSE/LICENSE.txt LICENSE/README.txt README.txt pnheaders/Makefile Removed Paths: ------------- ANTLR3_LICENSE.txt LICENSE.txt Makefile09 codegen/ pnheaders09/ Copied: 2009_version/Makefile09 (from rev 245, Makefile09) =================================================================== --- 2009_version/Makefile09 (rev 0) +++ 2009_version/Makefile09 2011-04-08 22:36:44 UTC (rev 246) @@ -0,0 +1,34 @@ +# This is the make file of the 2009 version of the program. + +COMPILER=gcc -g + +PNHEADERS=pnheaders +SPNBOX=spnbox09 +CODEGEN=codegen +CODEGENOBJS = codegen/src +TRANSLATOR=../translator + +ct09: objectfiles main_function.o + $(COMPILER) -o ct09 $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ + main_function.o $(SPNBOX)/*.a $(TRANSLATOR)/libtranslator.a + +objectfiles: + cd $(PNHEADERS); make + cd $(CODEGEN); make static + cd $(SPNBOX); make + cd $(TRANSLATOR); make + +main_function.o: $(PNHEADERS)/main_function.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/src/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function.c -Ispnbox09 -I$(CODEGEN)/src -I$(PNHEADERS) + +clean: + rm -f main_function.o + cd $(PNHEADERS); make clean + cd codegen; make clean + cd $(TRANSLATOR); make clean + cd $(SPNBOX); make clean + +distclean: clean + cd codegen; make distclean + cd $(TRANSLATOR); make distclean + Modified: 2009_version/codegen/Makefile =================================================================== --- codegen/Makefile 2011-04-02 00:10:24 UTC (rev 245) +++ 2009_version/codegen/Makefile 2011-04-08 22:36:44 UTC (rev 246) @@ -2,7 +2,8 @@ COMPILER=gcc -g -PNHEADERS = ../pnheaders/general.o ../pnheaders/matrix.o ../pnheaders/pns.o +PNHEADERS = ../pnheaders/general.c ../pnheaders/matrix.c ../pnheaders/pns.c +PNOBJS = ../pnheaders/general.o ../pnheaders/matrix.o ../pnheaders/pns.o STANDALONE = src/main.o OBJS = src/codegen.o src/plantCompiler.o src/supervisorCompiler.o src/petriNetSerializer.o src/text.o src/MakeGen.o B = \033[32m @@ -10,21 +11,21 @@ -standalone: pnslib static $(STANDALONE) +standalone: pnslib static $(STANDALONE) $(PNOBJS) echo "$(B)Making standalone files...$(E)" $(COMPILER) -c $(STANDALONE) echo "$(B)Linking it all up...$(E)" - $(COMPILER) -o codegen $(OBJS) $(PNHEADERS) $(STANDALONE) + $(COMPILER) -o codegen $(OBJS) $(PNOBJS) $(STANDALONE) echo "$(B)Done$(E)" -pnslib: $(PNHEADERS) +pnslib: $(PNHEADERS) echo "$(B) Precompiling pnheaders...$(E)" $(COMPILER) -c $(PNHEADERS) echo "$(B)Done$(E)" static: $(OBJS) pnslib echo "$(B) Making pure codegen...$(E)" - $(COMPILER) -c $(OBJS) $(PNHEADERS) -I../pnheaders + #$(COMPILER) -c $(OBJS) -I../pnheaders echo "$(B)Done$(E)" src/%.o : src/%.c $(COMPILER) -I../pnheaders -o src/$*.o -c src/$*.c @@ -41,6 +42,6 @@ echo "$(B)Done$(E)" distclean: clean echo "$(B)Making distclean...$(E)" - rm -f $(PNHEADERS) + rm -f $(PNOBJS) echo "$(B)Done$(E)" Added: 2009_version/spnbox09/Makefile =================================================================== --- 2009_version/spnbox09/Makefile (rev 0) +++ 2009_version/spnbox09/Makefile 2011-04-08 22:36:44 UTC (rev 246) @@ -0,0 +1,108 @@ +#This is the makefile for all spnbox functions. +#It is called by the pntool makefile to create object code for all the functions. + +COMPILER=gcc -g +PNHEADERS=../pnheaders + +all: actn.o admcon.o asiph.o avpr.o chkcons.o deallocation.o dp.o\ + extendedmatrix.o fvpr.o gcdv.o invar.o ilpadm.o ipslv.o ipsolve.o isadm.o\ + issiph.o linenf.o matrixmath.o MemoryManager.o mroadm.o msplit.o nltrans.o\ + pn2acpn.o pn2eacpn.o reduce.o supervis.o tactn.o liblpsolve55.a + +actn.o: actn.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c actn.c + +admcon.o: admcon.c spnbox.h matrixmath.h extendedmatrix.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c admcon.c + +asiph.o: asiph.c spnbox.h extendedmatrix.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c asiph.c + +avpr.o: avpr.c $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c avpr.c + +chkcons.o: chkcons.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h $(PNHEADERS)/pns.h + $(COMPILER) -c chkcons.c + +deallocation.o: deallocation.c spnbox.h $(PNHEADERS)/matrix.h + $(COMPILER) -c deallocation.c + +dp.o: dp.c spnbox.h matrixmath.h extendedmatrix.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h $(PNHEADERS)/pns.h + $(COMPILER) -c dp.c + +dp4.o: dp4.c spnbox.h matrixmath.h extendedmatrix.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h $(PNHEADERS)/pns.h + $(COMPILER) -c dp4.c + +extendedmatrix.o: extendedmatrix.c extendedmatrix.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c extendedmatrix.c + +fvpr.o: fvpr.c $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c fvpr.c + +gcdv.o: gcdv.c $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c gcdv.c + +invar.o: invar.c spnbox.h matrixmath.h MemoryManager.h extendedmatrix.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c invar.c + +ilpadm.o: ilpadm.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h $(PNHEADERS)/pns.h + $(COMPILER) -c ilpadm.c + +ipslv.o: ipslv.c spnbox.h ../../third-party/lp_solve_5.5/lp_lib.h + $(COMPILER) -c ipslv.c + +ipsolve.o: ipsolve.c spnbox.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c ipsolve.c + +isadm.o: isadm.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c isadm.c + +issiph.o: issiph.c spnbox.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c issiph.c + +linenf.o: linenf.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c linenf.c + +matrixmath.o: matrixmath.c matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c matrixmath.c + +MemoryManager.o: MemoryManager.c MemoryManager.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c MemoryManager.c + +mroadm.o: mroadm.c spnbox.h $(PNHEADERS)/matrix.h $(PNHEADERS)/general.h matrixmath.h + $(COMPILER) -c mroadm.c + +msplit.o: msplit.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c msplit.c + +nltrans.o: nltrans.c spnbox.h MemoryManager.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c nltrans.c + +pn2acpn.o: pn2acpn.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c pn2acpn.c + +pn2eacpn.o: pn2eacpn.c spnbox.h MemoryManager.h matrixmath.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h + $(COMPILER) -c pn2eacpn.c + +reduce.o: reduce.c spnbox.h $(PNHEADERS)/general.h $(PNHEADERS)/matrix.h $(PNHEADERS)/pns.h + $(COMPILER) -c reduce.c + +supervis.o: supervis.c spnbox.h matrixmath.h $(PNHEADERS)/matrix.h + $(COMPILER) -c supervis.c + +tactn.o: tactn.c spnbox.h $(PNHEADERS)/matrix.h $(PNHEADERS)/pns.h matrixmath.h MemoryManager.h + $(COMPILER) -c tactn.c + +liblpsolve55.a: ../../third-party/lp_solve_5.5/lpsolve55/liblpsolve55.a + cp ../../third-party/lp_solve_5.5/lpsolve55/liblpsolve55.a liblpsolve55.a + +../../third-party/lp_solve_5.5/lpsolve55/liblpsolve55.a: + cd ../../third-party/lp_solve_5.5; make -f Makefile.Linux lib + +clean: + rm -fv *.o *.a + cd ../../third-party/lp_solve_5.5; make -f Makefile.Linux clean + +clean-partial: + rm -fv *.o + Added: 2009_version/spnbox09/MemoryManager.c =================================================================== --- 2009_version/spnbox09/MemoryManager.c (rev 0) +++ 2009_version/spnbox09/MemoryManager.c 2011-04-08 22:36:44 UTC (rev 246) @@ -0,0 +1,201 @@ +#include "MemoryManager.h" + +inline void ManageMatrix(MemoryManager* mgr, matrix* m) +{ + matrix **matrices; + if(mgr->nextm == mgr->lengthm) + { + if (! (matrices = realloc(mgr->matrices, sizeof(matrix*) * (mgr->lengthm + mgr->addressblockm)))) + { + merror(0, "Out of memory"); + return; + } + mgr->matrices = matrices; + mgr->lengthm += mgr->addressblockm; + } + mgr->matrices[mgr->nextm++] = m; +} + +inline void ManageMemory(MemoryManager* mgr, void* mem) +{ + void** memory; + if (mgr->next == mgr->length) + { + if (! (memory = realloc(mgr->memory, sizeof(void*) * (mgr->length + mgr->addressblock)))) + { + merror(0, "Out of memory"); + return; + } + mgr->memory = memory; + mgr->length += mgr->addressblock; + } + mgr->memory[mgr->next++] = mem; +} + +inline void* mmalloc(MemoryManager* mgr, size_t nbytes) +{ + void **memory; + if(mgr->next == mgr->length) + { + if (! (memory = realloc(mgr->memory, sizeof(void*) * (mgr->length + mgr->addressblock)))) + { + merror(0, "Out of memory"); + return; + } + mgr->memory = memory; + mgr->length += mgr->addressblock; + } + return mgr->memory[mgr->next++] = tmalloc(nbytes); +} + +inline void* mcalloc(MemoryManager* mgr, size_t n, size_t nbytes) +{ + void **memory; + if(mgr->next == mgr->length) + { + if (! (memory = realloc(mgr->memory, sizeof(void*) * (mgr->length + mgr->addressblock)))) + { + merror(0, "Out of memory"); + return; + } + mgr->memory = memory; + mgr->length += mgr->addressblock; + } + return mgr->memory[mgr->next++] = tcalloc(n, nbytes); +} + +inline void MAllocateMatrixType(MemoryManager* mgr, int type, matrix* m, int rows, int cols) +{ + AllocateMatrixType(type, m, rows, cols); + if (rows || cols) + { + ManageMatrix(mgr, m); + } +} + +void FreeMemory(MemoryManager* mgr) +{ + int i; + for (i = 0; i < mgr->nextm; i++) + { + if (mgr->matrices[i]->type) DeallocateMatrix(mgr->matrices[i]); + } + free(mgr->matrices); + mgr->matrices = 0; + for (i = 0; i < mgr->next; i++) + { + free(mgr->memory[i]); + } + free(mgr->memory); + mgr->memory = 0; +} + +MemoryManager CreateMemoryManager(int InitialLength, int InitialMatrices, int AddressBlockSize, int MatrixAddressBlockSize) +{ + MemoryManager mgr; + mgr.next = 0; + mgr.nextm = 0; + if (InitialLength <= 0) InitialLength = 1; + if (InitialMatrices <= 0) InitialMatrices = 1; + if (AddressBlockSize <= 5) AddressBlockSize = 5; + if (MatrixAddressBlockSize <= 5) MatrixAddressBlockSize = 5; + mgr.length = InitialLength; + mgr.lengthm = InitialMatrices; + mgr.memory = tcalloc(InitialLength, sizeof(void*)); + mgr.matrices = tcalloc(InitialMatrices, sizeof(void*)); + mgr.addressblock = AddressBlockSize; + mgr.addressblockm = MatrixAddressBlockSize; + return mgr; +} + +/*CreateMemoryGrower initializes a memory grower structure.*/ +MemoryGrower CreateMemoryGrower(int pointers, int blocksize) +{ + MemoryGrower g; + if (pointers < 1 || blocksize < 1) + { + merror(0, "CREATEMEMORYGROWER: Parameters are non-positive"); + memset(&g, 0, sizeof(MemoryGrower)); + return g; + } + + g.blocksize = blocksize; + g.memories = pointers; + g.memory = tcalloc(pointers, sizeof(void*)); + g.capacity = tcalloc(pointers, sizeof(int)); + g.next = 0; + return g; +} + +void* growMalloc(MemoryGrower* g, void* memory, int size) +{ + /*If the pointer is null, allocate some new memory.*/ + if (! g) + { + merror(0, "MEMORYGROWER: The pointer to the grower is null"); + return 0; + } + if (! memory) + { + if (g->next == g->memories) + { + merror(0, "MEMORYGROWER: Too many pointers registered with the grower"); + return 0; + } + if (size < g->blocksize) size = g->blocksize; + g->memory[g->next] = tmalloc(size); + g->capacity[g->next] = size; + return g->memory[g->next++]; + } + else + { + /*Otherwise, find the index of the memory record.*/ + int i; + for (i = 0; i < g->next; i++) + { + if (memory == g->memory[i]) break; + } + if (i == g->next) + { + merror(0, "MEMORYGROWER: The memory did not originate with the grower"); + return 0; + } + /*If the request size is smaller than the current capacity return without + reallocating.*/ + if (size < g->capacity[i]) + { + return memory; + } + /*Otherwise, allocate as necessary.*/ + { + if (size < g->capacity[i] + g->blocksize) size = g->capacity[i] + g->blocksize; + void* newMem = tmalloc(size); + memcpy(newMem, memory, g->capacity[i]); + g->capacity[i] = size; + g->memory[i] = newMem; + free(memory); + return newMem; + } + } +} + +void* growCalloc(MemoryGrower* g, void* memory, int elementSize, int elements) +{ + return growMalloc(g, memory, elementSize * elements); +} + + +/*FreeMemoryGrower deallocates all the memories pointed to by a memory +grower.*/ +void FreeMemoryGrower(MemoryGrower* g) +{ + if (! g) return; + int i; + for (i = 0; i < g->next; i++) + { + free(g->memory[i]); + } + free(g->memory); + free(g->capacity); + memset(g, 0, sizeof(MemoryGrower)); +} Added: 2009_version/spnbox09/MemoryManager.h =================================================================== --- 2009_version/spnbox09/MemoryManager.h (rev 0) +++ 2009_version/spnbox09/MemoryManager.h 2011-04-08 22:36:44 UTC (rev 246) @@ -0,0 +1,75 @@ +#ifndef MEMORYMANAGER_H +#define MEMORYMANAGER_H + +#include "../pnheaders/general.h" +#include "../pnheaders/matrix.h" + +/*The MemoryManager structure is used to store information about dynamically +allocated memory so that it can be freed when appropriate. It stores lists +of pointers to ordinary memory blocks and pointers to matrices.*/ +typedef struct MemoryManager +{ + void** memory; + int length; + int next; + int addressblock; + + matrix** matrices; + int lengthm; + int nextm; + int addressblockm; +} MemoryManager; + +/*ManageMatrix adds a matrix to the list of matrices to free later.*/ +inline void ManageMatrix(MemoryManager* mgr, matrix* m); + +/*ManageMemory adds a block of memory to the list of blocks to be freed later.*/ +inline void ManageMemory(MemoryManager* mgr, void* mem); + +/*mmalloc allocates a block of memory and adds it to the lists.*/ +inline void* mmalloc(MemoryManager* mgr, size_t nbytes); + +/*mcalloc allocates a block of memory for an array and adds to the lists.*/ +inline void* mcalloc(MemoryManager* mgr, size_t n, size_t nbytes); + +/*MAllocateMatrixType is exactly like AllocateMatrixType except that it adds +the newly-allocated matrix to the list of matrices to be freed later.*/ +inline void MAllocateMatrixType(MemoryManager* mgr, int type, matrix* m, int rows, int cols); + +/*FreeMemory frees the memory blocks and matrices listed by a memory manager.*/ +void FreeMemory(MemoryManager* mgr); + +/*CreateMemoryManager initializes a memory manager structure. InitialLength +and InitialMatrices are the initial sizes of the lists that hold memory block +and matrix addresses, respectively. Both these parameters must be at least 1 and +will be set to 1 automatically if passed as less than that. +AddressBlockSize and MatrixAddressBlockSize are the number of additional +addresses that memory will be allocated for each time the list of memory block +addresses or matrix addresses respectively become full. These must be at least +five and will be set to five automatically if passed as less than that.*/ +MemoryManager CreateMemoryManager(int InitialLength, int InitialMatrices, int AddressBlockSize, int MatrixAddressBlockSize); + +/*The MemoryGrower structure maintains the information needed to have a region +of memory that can be increased in size several times before a time-consuming +reallocation is necessary.*/ +typedef struct MemoryGrower +{ + void** memory; + int * capacity; + int blocksize, memories, next; +} MemoryGrower; + +/*CreateMemoryGrower initializes a memory grower structure.*/ +MemoryGrower CreateMemoryGrower(int pointers, int blocksize); + +/*growMalloc and growCalloc grow the specified piece of memory to the given +capacity. If the pointer to the memory is null, new memory is allocated. If the +pointer points to a piece of memory the memorygrower is not responsible for the +function fails.*/ +void* growMalloc(MemoryGrower* g, void* memory, int size); +void* growCalloc(MemoryGrower* g, void* memory, int elementSize, int elements); + +/*FreeMemoryGrower deallocates all the memories pointed to by a memory +grower.*/ +void FreeMemoryGrower(MemoryGrower* g); +#endif Added: 2009_version/spnbox09/actn.c =================================================================== --- 2009_version/spnbox09/actn.c (rev 0) +++ 2009_version/spnbox09/actn.c 2011-04-08 22:36:44 UTC (rev 246) @@ -0,0 +1,459 @@ +#include <stdlib.h> +#include "../pnheaders/matrix.h" +#include "matrixmath.h" +#include "extendedmatrix.h" +#include "MemoryManager.h" +#include "spnbox.h" + +static int CheckParams(matrix* Dm, matrix* Dp, int** X, int* XCount, matrix *Dcm, matrix *Dcp, int update); + +static int isUnique(matrix* D, int* X, int XCount); + +static actn_r BuildResult(matrix* Dm, matrix* Dp, int* cullPlace, int* cullTrans); + +static int* cullPlaces(matrix* Dp, int* cullTransition); + +static int* updateURT(matrix* Dm, matrix* Dp, matrix* Dcm, matrix* Dcp); + +static int CheckParams(matrix* Dm, matrix* Dp, int** X, int* XCount, matrix *Dcm, matrix *Dcp, int update); + +actn_r actn(matrix* Dm, matrix* Dp, int* X, int XCount, matrix *Dcm, matrix *Dcp, int update, int checkUnique) +{ + actn_r result; + nltrans_r nltransResult; + MemoryManager memory; + matrix D; /*The incidence matrix*/ + int *cullTransition; /*An array of flags, one for each transition, set if it + should be culled (is unraisable)*/ + int *cullPlace; /*An array of flags, one for each place, set if the place + should be culled.*/ + + /*Initialize the error return value*/ + memset(&result, 0, sizeof(actn_r)); + + /*Initialize the memory manager*/ + memory = CreateMemoryManager(5, 5, 0, 0); + + /*Check the parameters.*/ + if (! CheckParams(Dm, Dp, &X, &XCount, Dcm, Dcp, update)) return result; + + /*Get the incidence matrix - we'll need it later.*/ + D = SubtractMatrix(Dp, Dm, (matrix*) 2); + ManageMatrix(&memory, &D); + + if (update) + { + /*If we are in update mode, use the updateURT function to get the + unraisable transitions.*/ + cullTransition = updateURT(Dm, Dp, Dcm, Dcp); + } + else + { + /*Otherwise, use nltrans to get the list of unraisable transitions.*/ + nltransResult = nltrans(&D, X, XCount); + if (! (nltransResult.dtrCount)) + { + /*If the call failed, fail.*/ + FreeMemory(&memory); + merror(0, "ACTN: nltrans call failed"); + return result; + } + else + { + cullTransition = nltransResult.dtr; + } + } + ManageMemory(&memory, cullTransition); + + /*Build the cullPlace flags, which will be cleared only for places that + have nonzero input arcs from transitions that are not being culled.*/ + cullPlace = cullPlaces(Dp, cullTransition); + ManageMemory(&memory, cullPlace); + + /*Build the final output.*/ + result = BuildResult(Dm, Dp, cullPlace, cullTransition); + + /*Do an isUnique test only if the checkUnique flag is set, since the test + does several linear programming problems and is thus rather slow.*/ + if (checkUnique) + { + result.unique = isUnique(&D, X, XCount); + } + + /*Clean up.*/ + FreeMemory(&memory); + + return result; +} + +/******************************************************************************* +isUnique examines the petri net and the given set of unraisable transitions to +determine if the live subnet that will be returned is unique. It is only called +when the actn caller requests it.*/ +int isUnique(matrix* D, int* X, int XCount) +{ + /*We will be doing a linear programming problem for each raisable transition. + The constraint matrix will be the subset of D having only the columns + corresponding to transitions not in X, with a row of 1s concatenated onto the + bottom, and the column corresponding to whichever transition is currently + being tested removed (or in this case, zeroed).*/ + matrix Dx, dx; + int i, j, Transitions = 0; + int* UnraisableT; + double* B; + short int *IntList; + ipsolve_r result; + + //If no transitions are being evaluated, return true. + if ((Transitions = NumberOfColumns(*D) - XCount) <= 0) return 1; + /*Build a flag array of the columns whose indices are in X.*/ + UnraisableT = tcalloc(NumberOfColumns(*D), sizeof(int)); + for (i = 0; i < XCount; i++) + { + UnraisableT[X[i]] = 1; + } + /*Build Dx. It should include only columns of D whose indices are not in X. + It should be optimized for column ops.*/ + AllocateMatrixType(2, &Dx, Transitions, NumberOfRows(*D) + 1); + TransposeMatrix(&Dx); + j = 0; + for (i = 0; i < NumberOfColumns(*D); i++) + { + if (! UnraisableT[i]) + { + /*Fill in the last row.*/ + SetMatrixEl(&Dx, NumberOfRows(*D), j, 1); + /*Fill in the other rows*/ + CopyBlock(NumberOfRows(*D), 1, D, 0, i, &Dx, 0, j++); + } + } + //We are done with the flag array. Free memory. + free(UnraisableT); + + /*Allocate space to record the values of the current column while it is + zeroed. Make it a type-2 transpose to optimize the column-swap operation.*/ + AllocateMatrixType(1, &dx, 1, NumberOfRows(*D) + 1); + TransposeMatrix(&dx); + + /*Build B. It is all zeroes except for a 1 in the last element.*/ + B = tcalloc(NumberOfRows(*D) + 1, sizeof(double)); + B[NumberOfRows(*D)] = 1; + + /*IntList needs to be all zeroes to override the default of all 1s.*/ + IntList = tcalloc(Transitions, sizeof(short int)); + + /*Iterate through each transition*/ + for (i = 0; i < Transitions; i++) + { + /*If there is a previous transition to restore, restore it.*/ + if (i) SwapColumns(&Dx, &dx, i - 1, 0); + /*Swap out the current transition. Because dx is a column of zeros this + will effectively zero the current transition and save a copy in dx for later + restoration.*/ + SwapColumns(&Dx, &dx, i, 0); + + //ipsolve_r ipsolve(matrix* L, double* B, double* f, short int *IntList, double *ub, double *lb, short int *ctype); + result = ipsolve(&Dx, B, 0, IntList, 0, 0, 0); + if (result.res) free(result.res); + + /*If we get a valid solution, then free memory and return false.*/ + if (! strcmp(result.mhow, HOW_OK)) + { + free(IntList); + free(B); + DeallocateMatrix(&Dx); + DeallocateMatrix(&dx); + return 0; + } + } + //If we get through all transition without returning false, return true. + free(IntList); + free(B); + DeallocateMatrix(&Dx); + DeallocateMatrix(&dx); + return 1; +} + +/******************************************************************************* +BuildResult takes the list of places and transitions to cull from the total net +and builds the active subnet. It returns the result structure that will be +returned by actn. +*/ +actn_r BuildResult(matrix* Dm, matrix* Dp, int* cullPlace, int* cullTrans) +{ + int Places = 0, Transitions = 0, i, j, k, l; + actn_r result; + + /*All matrices are zeroed initially.*/ + memset(&result, 0, sizeof(actn_r)); + + /*Count the number of places and transitions that are going to be left after + culling.*/ + for (i = 0; i < NumberOfRows(*Dm); i++) + { + if (! cullPlace[i]) Places++; + } + for (i = 0; i < NumberOfColumns(*Dm); i++) + { + if (! cullTrans[i]) Transitions++; + } + + /*Allocate space. Dma/Dmp are the same size as the original matrices but + contain only elements in non-culled rows and columns. Dmra/Dpra contain only + non-culled rows and columns. TA holds the indices of kept transitions.*/ + if (Places && Transitions) + { + AllocateMatrixType(2, &result.Dmra, Places, Transitions); + AllocateMatrixType(2, &result.Dpra, Places, Transitions); + } + AllocateMatrixType(2, &result.Dma, NumberOfRows(*Dm), NumberOfColumns(*Dm)); + AllocateMatrixType(2, &result.Dpa, NumberOfRows(*Dm), NumberOfColumns(*Dm)); + result.TA = tcalloc(Transitions, sizeof(int)); + result.TACount = Transitions; + /*Do the copy. k and l indicate the row and column numbers in the Dmra/Dpra + matrices. Fill in TA while we're at it.*/ + l = 0; + for (j = 0; j < NumberOfColumns(*Dm); j++) + { + if (cullTrans[j]) continue; + k = 0; + for (i = 0; i < NumberOfRows(*Dm); i++) + { + if (cullPlace[i]) continue; + SetMatrixEl(&result.Dma, i, j, GetMatrixEl(Dm, i, j)); + SetMatrixEl(&result.Dpa, i, j, GetMatrixEl(Dp, i, j)); + SetMatrixEl(&result.Dmra, k, l, GetMatrixEl(Dm, i, j)); + SetMatrixEl(&result.Dpra, k, l, GetMatrixEl(Dp, i, j)); + k++; + } + result.TA[l] = j; + l++; + } + return result; +} +/******************************************************************************* +cullPlaces examines the Petri net and the list of transitions to cull and +returns an array of integer flags, one for each place, indicating whether that +place should be culled. +*/ +int* cullPlaces(matrix* Dp, int* cullTransition) +{ + int i, j; + int *cull; + /*Allocate and initialize the return value cull. It will be clear only for + places that have nonzero output arcs to transitions that are not being + culled.*/ + cull = tcalloc(NumberOfRows(*Dp), sizeof(int)); + for (i = 0; i < NumberOfRows(*Dp); i++) + { + /*Look to see if the current place has any nonzero output arcs to + transitions not being culled.*/ + for (j = 0; j < NumberOfColumns(*Dp); j++) + { + if (GetMatrixEl(Dp, i, j) && (! cullTransition[j])) + { + break; + } + } + /*If there were no nonzero output arcs set the place flag.*/ + if (j == NumberOfColumns(*Dp)) + { + cull[i] = 1; + } + } + return cull; +} + +/******************************************************************************* +updateURT examines the Petri net and the predefined active subnet if given and +returns an array of transitions that are unraisable given the active subnet. +This is used to determine transitions to cull if in update mode. +*/ +int* updateURT(matrix* Dm, matrix* Dp, matrix* Dcm, matrix* Dcp) +{ + /*This function builds a list of unraisable transitions in Dm/Dp by examining + Dcm/Dcp.*/ + int Places, Transitions, SubPlaces, SubTransitions, i, j, keepGoing; + /*These are each flag arrays set to indicate live places or transitions at + various times throughout the algorithm.*/ + int *URT, *Trans = 0, *Place = 0; + + Places = NumberOfRows(*Dm); + Transitions = NumberOfColumns(*Dm); + SubPlaces = NumberOfRows(*Dcm); + SubTransitions = NumberOfColumns(*Dcm); + + /*URT is the return value. It has a flag for each transition.*/ + URT = tcalloc(Transitions, sizeof(int)); + /*Trans and Place both have flags only for each of the possible new + transitions or places that can be added.*/ + if (Places - SubPlaces) + { + Place = tcalloc(Places - SubPlaces, sizeof(int)); + } + if (Transitions - SubTransitions) + { + Trans = tcalloc(Transitions - SubTransitions, sizeof(int)); + } + + /*URT is a flag vector with an element for each transition. It is initially + cleared only for non-null columns of Dcm/Dcp, where column numbers in Dcm/Dcp + map to the same column numbers in Dm/Dp.*/ + for (i = 0; i < SubTransitions; i++) + { + /*See if the current column of Dcm/Dcp is non-null.*/ + for (j = 0; j < SubPlaces; j++) + { + if (GetMatrixEl(Dcm, j, i) || GetMatrixEl(Dcp, j, i)) + { + break; + } + } + /*If it was null, set the URT flag.*/ + if (j == SubPlaces) + { + URT[i] = 1; + } + } + /*Fill the additional elements of URT, the ones not taken care of above.*/ + for (i = SubTransitions; i < Transitions; i++) + { + URT[i] = 1; + } + + /*Now, we loop. For the first iteration we have to do something special. Use + keepGoing = -1 to indicate first loop iteration.*/ + keepGoing = -1; + do + { + /*The place flag should be set for any place (in Dm/Dp beyond those mapped + to by Dcm/Dcp) such that the place has at least one nonzero output arc to + a transition that is flagged in the current transition list. It should + be cleared for every other place. On the first loop iteration, rather + than using the current transition list (which maps to the columns in the + right of Dm/Dp that have no corresponding columns in Dcm/Dcp), we use logic + inverse of URT, which maps to all columns in Dm/Dp. The keepGoing flag will + be set to -1 on the first iteration.*/ + memset(Place, 0, sizeof(int) * (Places - SubPlaces)); + if (keepGoing > 0) + { + for (i = SubPlaces; i < Places; i++) + { + /*Check to see if the current place has at least one nonzero output arc + to a transition flagged in the current transition list.*/ + for (j = SubTransitions; j < Transitions; j++) + { + if (Trans[j - SubTransitions] && GetMatrixEl(Dm, i, j)) + { + /*If it does, set the flag and break out of the test loop.*/ + Place[i - SubPlaces] = 1; + break; + } + } + } + } + else + { + for (i = SubPlaces; i < Places; i++) + { + /*Check to see if the current place has at least one nonzero output arc + to a transition not flagged in URT.*/ + for (j = 0; j < SubTransitions; j++) + { + if ((! URT[j]) && GetMatrixEl(Dm, i, j)) + { + /*If it does, set the flag and break out of the test loop.*/ + Place[i - SubPlaces] = 1; + break; + } + } + } + } + /*Similarly, the transition flag should be set for any transition in Dm/Dp + beyond those mapped to by Dcm/Dcp such that the transition has at least one + nonzero input arc to a place that is flagged in the current place list. + Additionally, we clear every flag of URT that corresponds to a + transition whose flag is set in Trans. Finally, the overall loop will + continue only until Trans is entirely empty. Set the keepGoing flag + if any element of Trans is set.*/ + keepGoing = 0; + memset(Trans, 0, sizeof(int) * (Transitions - SubTransitions)); + for (j = SubTransitions; j < Transitions; j++) + { + for (i = SubPlaces; i < Places; i++) + { + if (Place[i - SubPlaces] && GetMatrixEl(Dp, i, j)) + { + Trans[j - SubTransitions] = 1; + /*Clear the appropriate URT flag.*/ + URT[j] = 0; + /*Set the keepGoing flag.*/ + keepGoing = 1; + break; + } + } + } + } while (keepGoing); + /*Free memory*/ + if (Place) free(Place); + if (Trans) free(Trans); + /*Return*/ + return URT; +} + +/******************************************************************************* +CheckParams checks the parameters to make sure required parameters are present, +checks some basic validity, and makes sure that all array pointers are null if +their counts are zero and vice-versa.*/ +int CheckParams(matrix* Dm, matrix* Dp, int** X, int* XCount, matrix *Dcm, matrix *Dcp, int update) +{ + int Rows0, Cols0, Rows1, Cols1; + /*Dm and Dp are required and must be the same size.*/ + if (! (Dm && Dp)) + { + merror(0, "ACTN: Dm or Dp was not given"); + return 0; + } + Rows0 = NumberOfRows(*Dm); + Cols0 = NumberOfColumns(*Dm); + if (Rows0 != NumberOfRows(*Dp) || Cols0 != NumberOfColumns(*Dp)) + { + merror(0, "ACTN: The dimensions of Dm and Dp do not match"); + return 0; + } + + /*X is not required. Make sure that XCount is zero if X is null and vice- + versa.*/ + if (! *X) + { + *XCount = 0; + } + else if (! *XCount) + { + *X = 0; + } + + /*If update is nonzero, Dcm and Dcp are required. They cannot be larger than + Dm/Dp in either dimension and they must be the same size.*/ + if (update) + { + if (! (Dcm && Dcp)) + { + merror(0, "ACTN: Dcm or Dcp was not given while update was nonzero"); + return 0; + } + Rows1 = NumberOfRows(*Dcm); + Cols1 = NumberOfColumns(*Dcm); + if (NumberOfRows(*Dcp) != Rows1 || NumberOfColumns(*Dcp) != Cols1) + { + merror(0, "ACTN: Dcm and Dcp are not the same size"); + return 0; + } + if (Rows1 > Rows0 || Cols1 > Cols0) + { + merror(0, "ACTN: Dcm and Dcp are larger than Dm and Dp"); + return 0; + } + } + return 1; +} Added: 2009_version/spnbox09/admcon.c =================================================================== --- 2009_version/spnbox09/admcon.c (rev 0) +++ 2009_version/spnbox09/admcon.c 2011-04-08 22:36:44 UTC (rev 246) @@ -0,0 +1,613 @@ +#include <stdlib.h> +#include "../pnheaders/general.h" +#include "../pnheaders/matrix.h" +#include "MemoryManager.h" +#include "matrixmath.h" +#include "extendedmatrix.h" +#include "spnbox.h" + +static int CheckParams(admcon_p *params); +static int GetRowCount(admcon_p *params); +static matrix BuildZ(admcon_p *params); +static matrix BuildDX(admcon_p *p, matrix *Z); +static int *nlplace(admcon_p *p, matrix *DX, int *pCount); +static ipsolve_r RawSolution(admcon_p *param, matrix *DX, int* p, int pCount); +static admcon_r BuildResult(ipsolve_r *lpresult, int *p, int pCount, int rowCount); + +admcon_r admcon(admcon_p *params) +{ + /*Initialize to an error value.*/ + admcon_r result; + memset(&result, 0, sizeof(result)); + + /*Check parameters.*/ + if (! CheckParams(params)) + { + return result; + } + + /*Initialize the result to a default value.*/ + result.how = 1; + + /*Get the row count and the intermediate matrix Z.*/ + int rowCount = GetRowCount(params); + matrix Z = BuildZ(params); + /*Get the intermediate linear programming matrix DX. Z will be deallocated + by the function call. If DX returns an empty matrix, it means that the + default solution, a copy of the siphon, is feasible. Return immediately.*/ + matrix DX = BuildDX(params, &Z); + if (! DX.type) + { + /*Build the result and return. l should be a copy of the siphon vector.*/ + result.l = tcalloc(NumberOfRows(params->Dm), sizeof(int)); + result.lCount = NumberOfRows(params->Dm); + memcpy(result.l, params->siphon, sizeof(int) * NumberOfRows(params->Dm)); + return result; + } + + /*Get p, a list of places. This function is an aggregate of the nlplace function + present in the Matlab version of this function, and several lines of code + immediately after it. If nlplace returns a null pointer, it means that no + feasible solution exists.*/ + int pCount; + int *p; + if (! (p = nlplace(params, &DX, &pCount))) + { + result.how = 0; + DeallocateMatrix(&DX); + return result; + } + + /*Otherwise, proceed to build and solve another linear programming problem + using p. This problem deallocates DX.*/ + ipsolve_r lpresult = RawSolution(params, &DX, p, pCount); + + /*Get the new solution.*/ + return BuildResult(&lpresult, p, pCount, rowCount); +} + +/******************************************************************************* +This function processes the solution returned by RawSolution to build the new +solution. It also deallocates everything that still needs to be deallocated.*/ +admcon_r BuildResult(ipsolve_r *lpresult, int *p, int pCount, int rowCount) +{ + int i; + admcon_r result; + + /*If the lp solution is valid, copy the appropriate values to the result. + Otherwise leave it blank.*/ + if (! strcmp(lpresult->mhow, HOW_OK)) + { + result.l = tcalloc(rowCount, sizeof(int)); + result.lCount = rowCount; + for (i = 0; i < pCount; i++) + { + result.l[p[i]] = (int) lpresult->res[p[i]]; + } + result.how = 1; + } + else + { + memset(&result, 0, sizeof(admcon_r)); + } + + /*Deallocate p and the lpresult.*/ + free(p); + DeallocateIpsolve(lpresult); + return result; +} + +/******************************************************************************* +This function builds and solves a linear programming problem to get the modified +solution vector l. It returns the raw ipsolve results - not the processed +version that is the final solution. It also deallocates DX, which is not used +after this point.*/ +ipsolve_r RawSolution(admcon_p *param, matrix *DX, int* p, int pCount) +{ + MemoryManager mem; + mem = CreateMemoryManager(3, 1, 0, 0); + /*The constraint matrix is an identity followed below by those columns + of DX which have indices present in p. We will do this by adding rows directly + to DX (it has been optimized for row ops), nulling out the columns we are not + interested in, and putting in 1s for the identity where we are interested.*/ + InsertNullRows(DX, 0, pCount, -1); + ManageMatrix(&mem, DX); + + /*Insert the 1s we are interested in. While doing it, build a flag array that + is set at each index present in p.*/ + int *pFlag = mcalloc(&mem, NumberOfColumns(*DX), sizeof(int)); + int i, j; + for (i = 0; i < pCount; i++) + { + pFlag[p[i]] = 1; + SetMatrixEl(DX, i, p[i], 1); + } + /*Now go back and zero all the columns not flagged in pFlag.*/ + for (i = 0; i < NumberOfColumns(*DX); i++) + { + if (! pFlag[i]) MakeZeroColumn(DX, i); + } + + /*The constraint vector should be 1s for each row that was added by the + identity and zeros for all elements thereafter except the last.*/ + double *B = mcalloc(&mem, NumberOfRows(*DX), sizeof(double)); + for (i = 0; i < pCount; i++) + { + B[i] = 1; + } + B[NumberOfRows(*DX) - 1] = 1; + + /*Cost should have, for each place indexed in p, an element that is the sum + of all elements of Dm for that place that correspond to elements of the + incidence matrix D that are negative.*/ + double *F = mcalloc(&mem, NumberOfColumns(*DX), sizeof(double)); + for (i = 0; i < pCount; i++) + { + for (j = 0; j < NumberOfColumns(param->Dm); j++) + { + int dm = GetMatrixEl(¶m->Dm, p[i], j); + int dp = GetMatrixEl(¶m->Dp, p[i], j); + if (dp - dm < 0) F[p[i]] += (double) dm; + } + } + + /*Solve the problem.*/ + ipsolve_r result = ipsolve(DX, B, F, 0, 0, 0, 0); + + /*Free memory and return the solution.*/ + FreeMemory(&mem); + return result; +} + +/******************************************************************************* +Get the list of places p that are live. Return the list length in the integer +pointed to by parameter pCount.*/ +int *nlplace(admcon_p *p, matrix *DX, int *pCount) +{ + MemoryManager mem; + mem = CreateMemoryManager(4, 1, 0, 0); + + /*We need to build a linear programming problem. We will iterate through each + column, adjust the problem slightly, and resolve it.*/ + + /*We need to know how many places are flagged in the siphon flag array.*/ + int placeCount = 0, i, j, k; + for (i = 0; i < NumberOfRows(p->Dm); i++) + { + if (p->siphon[i]) placeCount++; + } + + /*The constraint matrix is the columns (?) of DX for which flags are set in the + siphon listing, followed to the right by a negative identity, then below by a + vector which will change from iteration to iteration.*/ + matrix L; + MAllocateMatrixType(&mem, 2, &L, NumberOfRows(*DX) + 1, placeCount + NumberOfRows(*DX)); + j = 0; + /*Copy the appropriate columns of DX.*/ + for (i = 0; i < NumberOfRows(p->Dm); i++) + { + if (p->siphon[i]) + { + CopyBlock(NumberOfRows(*DX), 1, DX, 0, i, &L, 0, j++); + } + } + /*Fill in the negative identity.*/ + for (i = 0; i < NumberOfRows(*DX); i++) + { + SetMatrixEl(&L, i, i + placeCount, -1); + } + + /*The constraint vector should be all zeros except the last element, which + should be 1.*/ + double *B = mcalloc(&mem, NumberOfRows(L), sizeof(double)); + B[NumberOfRows(L) - 1] = 1; + + /*Cost vector should be all ones.*/ + double *F = mcalloc(&mem, NumberOfColumns(L), sizeof(double)); + for (i = 0; i < NumberOfColumns(L); i++) + { + F[i] = 1; + } + + /*Constraint type should be all equalities (0) except that of the last column, + which should be a greater-than (1).*/ + short *ctype = mcalloc(&mem, NumberOfRows(L), sizeof(short)); + ctype[NumberOfRows(L) - 1] = 1; + + /*IntList should be all zeroes.*/ + short *intList = mcalloc(&mem, NumberOfColumns(L), sizeof(short)); + + /*During our iterations we will modify a flag array, cov, with an element for + each of the columns that came from DX. Allocate space.*/ + int *cov = mcalloc(&mem, placeCount, sizeof(int)); + + /*Start the iterations. Store in j the index of the last column of L such that + its element in the last row was set to 1 within the loop. -1 means no column + set yet.*/ + j = -1; + for (i = 0; i < placeCount; i++) + { + /*Process only columns which are not flagged yet in cov.*/ + if (cov[i]) continue; + + /*The last row of the constraint matrix should be all zeros except for the + element corresponding to the current column, which should be 1.*/ + if (j >= 0) SetMatrixEl(&L, NumberOfRows(L) - 1, j, 0); + j = i; + SetMatrixEl(&L, NumberOfRows(L) - 1, i, 1); + + /*Solve the linear programming problem. Let the bounds default to 0 and inf.*/ + ipsolve_r lpresult = ipsolve(&L, B, F, intList, 0, 0, ctype); + + /*If the solution is valid, set any elements of cov for which there is a + nonzero (and not very small) value in the solution vector.*/ + if (! strcmp(lpresult.mhow, HOW_OK)) + { + for (k = 0; k < placeCount; k++) + { + if (lpresult.res[k] > HOW_MAX_ERROR || lpresult.res[k] < -HOW_MAX_ERROR) + { + cov[k] = 1; + } + } + } + /*Deallocate any memory used by the solution.*/ + DeallocateIpsolve(&lpresult); + } + + /*Build the result. It is a list of the indices of elements of the siphon list + (places) that correspond to nonzero elements in cov. Start by counting them.*/ + *pCount = 0; + for (i = 0; i < placeCount; i++) + { + if (cov[i]) (*pCount)++; + } + /*Allocate space and do the building. Each index should be not the index + within cov, but, for the ith element of cov, the index of the ith nonzero + element in siphon. Use j to count indices in siphon.*/ + int *result = tcalloc(*pCount, sizeof(int)); + j = -1; + k = 0; + for (i = 0; i < placeCount; i++) + { + /*Find the ith nonzero place in siphon.*/ + j++; + while (! p->siphon[j]) j++; + /*If the current nonzero place is flagged in cov, copy the index.*/ + if (cov[i]) result[k++] = j; + } + /*Free up memory.*/ + FreeMemory(&mem); + + /*Make sure that there are at least two places with indices in p that are + also present in the active place list. Count places like that in k.*/ + k = 0; + for (i = 0; i < *pCount; i++) + { + for (j = 0; j < p->apCount; j++) + { + if (result[i] == p->apl[j]) + { + if (++k == 2) break; + } + } + } + /*If not, no feasible solution to the admcon problem exists. Return a null + pointer to indicate this.*/ + if (k < 2) + { + free(result); + *pCount = 0; + return 0; + } + return result; +} + +/******************************************************************************* +This function builds the intermediate linear programming description matrix DX. +It runs a test on DX, and if the value of l (the solution vector) is already +correct it returns an empty matrix to signify that admcon should return +immediately. This function also deallocates the Z matrix, which, is not used +again.*/ +matrix BuildDX(admcon_p *p, matrix *Z) +{ + /*DX is a matrix composed of a right-to-left concatentation of submatrices, all transposed: + DX = [Auc, Auo, -Auo, -Ds, d]' + For: + Auc = Z * DI(:,Tuc) + Auo = Z * DI(:,Tuo) + Ds = (Dp - Dm)(:,ntr) %that is, the part of the incidence matrix corresponding + %to transitions that came from transition split. + d = a flag array, one for each place, set to 1 for active places. + */ + /*Allocate DX.*/ + matrix DX; + AllocateMatrixType(2, &DX, p->TucCount + p->TuoCount + p->TuoCount + p->ntCount + 1, NumberOfRows(*Z)); + + int i, j, k; + for (i = 0; i < NumberOfColumns(DX); i++) + { + /*Fill in Auc.*/ + for (j = 0; j < p->TucCount; j++) + { + SetMatrixEl(&DX, j, i, MultiplyVector(Z, &p->DI, i, p->Tuc[j], 0)); + } + /*Fill in Auo and -Auo.*/ + for (j = 0; j < p->TuoCount; j++) + { + k = MultiplyVector(Z, &p->DI, i, p->Tuo[j], 0); + SetMatrixEl(&DX, j + p->TucCount, i, k); + SetMatrixEl(&DX, j + p->TucCount + p->TuoCount, i, -k); + } + /*Fill in -Ds.*/ + for (j = 0; j < p->ntCount; j++) + { + k = GetMatrixEl(&p->Dm, i, p->ntr[j]) - GetMatrixEl(&p->Dp, i, p->ntr[j]); + SetMatrixEl(&DX, j + p->TucCount + (2 * p->TuoCount), i, k); + } + } + /*Fill in d.*/ + for (i = 0; i < p->apCount; i++) + { + SetMatrixEl(&DX, NumberOfRows(DX) - 1, p->apl[i], 1); + } + /*Deallocate Z. It will not be needed anymore.*/ + DeallocateMatrix(Z); + + /*Run a test. If DX * siphon (the default solution vector is simply the siphon) + >= b, the default solution vector is good. b should be a vector of all zeros + except for the last element, which should be 1. We can skip the building of b + and simply put the test in a loop.*/ + if (p->siphon) + { + for (i = 0; i < NumberOfRows(DX); i++) + { + k = MultiplyVector(&DX, (matrix*) p->siphon, i, MULTIPLYVECTOR_ARRAY, 0); + if (k < (i < NumberOfRows(DX) - 1 ? 0 : 1)) + { + break; + } + } + /*If we made it through the loop without breaking out early, it means that the + default solution vector is valid. Deallocate and zero DX and return to + indicate this. Otherwise just return DX as-is for the next stage in + processing.*/ + if (i == NumberOfRows(DX)) + { + DeallocateMatrix(&DX); + } + } + return DX; +} + +/******************************************************************************* +This function builds the matrix Z, an intermediate matrix of the admcon +algorithm.*/ +matrix BuildZ(admcon_p *p) +{ + /*Build the independent place flag array. This is an array of flags, one for + each element of the independent place list. The flag should be set of the + place indexed by the corresponding ind. place list element is also present in + the original place list.*/ + int *ipFlag = 0; + int ipFlagged = 0, i, j, k; + if (p->ipl) + { + ipFlag = tcalloc(p->ipCount, sizeof(int)); + for (i = 0; i < p->ipCount; i++) + { + for (j = 0; j < p->opCount; j++) + { + if (p->ipl[i] == p->opl[j]) + { + ipFlag[i] = 1; + ipFlagged++; + break; + } + } + } + } + + /*Initialize the result to an empty matrix.*/ + matrix result; + memset(&result, 0, sizeof(matrix)); + + if (ipFlagged) + { + /*Allocate space for Z.*/ + AllocateMatrixType(2, &result, p->ipCount + p->dpCount, ipFlagged); + j = 0; + /*Build Z. We'll need to examine each independent place.*/ + for (i = 0; i < p->ipCount; i++) + { + if (ipFlag[i]) + { + /*Build the part of Z based on independent places. We are inserting an + identity, except that some columns (those not flagged in ipFlagged) must + be removed premptively. Thus, on the ith independent place, count how + many places up to that point have been flagged. Use j. Set the jth + column of Z (at the appropriate row) to a 1.*/ + SetMatrixEl(&result, p->ipl[i], j, 1); + + /*Build the part of Z based on dependent places. We are copying rows + from M to their corresponding rows in Z (dep. place rows) except that + the columns not flagged in ipFlag will not be copied.*/ + if (p->M.type) + { + for (k = 0; k < p->dpCount; k++) + { + SetMatrixEl(&result, p->dpl[k], j, GetMatrixEl(&p->M, k, i)); + } + } + + j++; + } + } + } + /*Free the flag array.*/ + if (ipFlag) free(ipFlag); + return result; +} + +/******************************************************************************* +This function gets the row count.*/ +int GetRowCount(admcon_p *params) +{ + int max = 0, i; + for (i = 0; i < params->ipCount; i++) + { + if (params->ipl[i] > max) max = params->ipl[i]; + } + for (i = 0; i < params->dpCount; i++) + { + if (params->dpl[i] > max) max = params->dpl[i]; + } + for (i = 0; i < params->opCount; i++) + { + if (params->opl[i] > max) max = params->opl[i]; + } + return max + 1; +} + +/******************************************************************************* +This function checks the parameters to make sure they are valid.*/ +int CheckParams(admcon_p *params) +{ + /*If the skipParamCheck flag is set, skip the checks. Return 1 immediately.*/ + if (params->skipParamCheck) return 1; + + int i, j; + if (! params) + { + merror(0, "ADMCON: No parameters provided"); + return 0; + } + /*Dm and Dp must be present.*/ + if (! (params->Dm.type && params->Dp.type)) + { + merror(0, "ADMCON: Dm and Dp were not initialized"); + return 0; + } + /*Dm and Dp must be the same size.*/ + if (NumberOfRows(params->Dm) != NumberOfRows(params->Dp) || NumberOfColumns(params->Dm) != NumberOfColumns(params->Dp)) + { + merror(0, "ADMCON: Dm and Dp are not the same size"); + return 0; + } + /*DI must be present.*/ + if (! params->DI.type) + { + merror(0, "ADMCON: DI has not been initialized"); + return 0; + } + /*Make sure that array pointers are null if their counts are null.*/ + if (! params->ipCount) params->ipl = 0; + else if (! params->ipl) params->ipCount = 0; + if (! params->dpCount) params->dpl = 0; + else if (! params->dpl) params->dpCount = 0; + if (! params->opCount) params->opl = 0; + else if (! params->opl) params->opCount = 0; + if (! params->apCount) params->apl = 0; + else if (! params->apl) params->apCount = 0; + if (! params->ntCount) params->ntr = 0; + else if (! params->ntr) params->ntCount = 0; + if (! params->TucCount) params->Tuc = 0; + else if (! params->Tuc) params->TucCount = 0; + if (! params->TuoCount) params->Tuo = 0; + else if (! params->Tuo) params->TuoCount = 0; + + /*If the dependent/independent place lists are provided, run some tests.*/ + if (params->ipl || params->dpl) + { + /*Their total count must be that of the total number of places.*/ + if (params->ipCount + params->dpCount != NumberOfRows(params->Dm)) + { + merror(0, "ADMCON: The number of dependent and independent places does not match the total number of places"); + return 0; + } + /*They cannot include any of the same places or include any out-of-range + indices.*/ + for (i = 0; i < params->ipCount; i++) + { + if (params->ipl[i] < 0 || params->ipl[i] > NumberOfRows(params->Dm)) + { + merror(0, "ADMCON: The independent place list has an out-of-range index"); + return 0; + } + } + for (i = 0; i < params->dpCount; i++) + { + if (params->dpl[i] < 0 || params->dpl[i] > NumberOfRows(params->Dm)) + { + merror(0, "ADMCON: The dependent place list has an out-of-range index"); + return 0; + } + } + for (i = 0; i < params->ipCount; i++) + { + for (j = 0; j < params->dpCount; j++) + { + if (params->ipl[i] == params->dpl[j]) + { + merror(0, "ADMCON: The independent and dependent place lists contain common elements"); + return 0; + } + } + } + } + /*If the list of transitions that resulted from the transition split is present, + make sure there are no duplicate or out-of-range elements.*/ + if (params->ntr) + { + for (i = 0; i < params->ntCount; i++) + { + if (params->ntr[i] < 0 || params->ntr[i] > NumberOfColumns(params->Dm)) + { + merror(0, "ADMCON: The new transition list contains an out-of-range index"); + return 0; + } + for (j = i + 1; j < params->ntCount; j++) + { + if (params->ntr[i] == params->ntr[j]) + { + merror(0, "ADMCON: The new transition list containts duplicate entries"); + } + } + } + } + /*If M is present (nonzero) it must have the same number of columns as there + are independent places and the same number of rows as there are independent + places.*/ + if (params->M.type && (params->ipl && params->dpl)) + { + if (NumberOfColumns(params->M) != params->ipCount || NumberOfRows(params->M) != params->dpCount) + { + merror(0, "The dependent-to-independent marking transformation matrix is not the right size"); + return 0; + } + } + /*At least one of Tuc or Tuo must be provided.*/ + if (! (params->Tuc || params->Tuo)) + { + merror(0, "ADMCON: No unobservable or uncontrollable transitions were given"); + return 0; + } + /*Neither Tuc nor Tuo should contain duplicate or out-of-range indices.*/ + for (i = 0; i < params->TucCount; i++) + { + if (params->Tuc[i] < 0 || params->Tuc[i] >= NumberOfColumns(params->DI)) + { + merror(0, "ADMCON: Tuc contains an out-of-range index"); + return 0; + } + } + for (i = 0; i < params->TuoCount; i++) + { + if (params->Tuo[i] < 0 || params->Tuo[i] >= NumberOfColumns(params->DI)) + { + merror(0, "ADMCON: Tuo contains an out-of-range index"); + return 0; + } + } + return 1; +} Added: 2009_version/spnbox09/asiph.c =================================================================== --- 2009_version/spnbox09/asiph.c (rev 0) +++ 2009_version/spnbox09/asiph.c 2011-04-08 22:36:44 UTC (rev 246) @@ -0,0 +1,901 @@ +#include <stdio.h> +#include "../pnheaders/general.h" +#include "../pnheaders/matrix.h" +#include "spnbox.h" +#include "MemoryManager.h" +#include "extendedmatrix.h" + +typedef struct asiph_data +{ + int *numInputPlaces; + int *curTrans; + int *counters; + matrix M; + matrix N; + matrix MT; + matrix NT; + matrix newRow; + matrix newPlace; + matrix MNS; + matrix NS; +} asiph_data; + +static int CheckParams(matrix *Dm, matrix *Dp, int **list, int *listCount, matrix *PS, matrix **Dma, matrix **Dpa, MemoryManager *mem); +static matrix SXInit(matrix *Dm, matrix *Dp, matrix *Dma, matrix* Dpa, matrix *PS, int **list, int* listCount, asiph_data* data); +static int* insert(asiph_data* data, matrix* vector, int* index); +static int *DataInit(matrix *Dm, matrix *Dp, matrix *PS, matrix *sx, asiph_data* data); +static int GetNewTrans(matrix *Dm, matrix *Dp, matrix *Places, int *Flags); +static void OuterLoopInit(asiph_data* data, matrix *Dm, matrix *Dp, MemoryManager *mem); +static void MiddleLoopInit(asiph_data* data, asiph_r* result, int siphon); +static void InnerLoopInit(asiph_data* data, matrix *Dm, matrix *Dp); +static int Check1(matrix *MNS, matrix *newRow); +static int Check2(matrix* M, matrix* newRow); +static int* DoInnerLoop(asiph_data* data, matrix* Dm, matrix *Dp, int* index); +static void PrintPercent(int num, int denom); +static asiph_r BuildResult(matrix *Dm, matrix *Dp, asiph_data* data, int *index); + +asiph_r asiph(matrix *Dm, matrix *Dp, int* list, int listCount, matrix *PS, matrix *Dma, matrix *Dpa) +{ + MemoryManager mem; + mem = CreateMemoryManager(10, 10, 0, 0); + asiph_r result; + memset(&result, 0, sizeof(asiph_r)); + /*Check parameters.*/ + if (! CheckParams(Dm, Dp, &list, &listCount, PS, &Dma, &Dpa, &mem)) + { + return result; + } + asiph_data data; + memset(&data, 0, sizeof(asiph_data)); + + /*Initialize sx (and a few other things)*/ + matrix sx = SXInit(Dm, Dp, Dma, Dpa, PS, &list, &listCount, &data); + ManageMatrix(&mem, &sx); + /*Initialize some other parts of the loop data. Build the newIndex array.*/ + int *newIndex = DataInit(Dm, Dp, PS, &sx, &data); + + /*Allocate and initialize various quantities that do not change or the space + for which does not change over the iterations of the outer loop.*/ + OuterLoopInit(&data, Dm, Dp, &mem); + + /*Iterate through each of the rows of NS. Each row corresponds to a siphon + that needs to be processed. If verbosity is high enough we'll be printing a + progress report as we go. Prepare.*/ + int siphon, originalSiphons; + originalSiphons = NumberOfRows(data.NS); + if (is_verbose() >= VRB_ASIPH) + { + printf("ASIPH: Primary Processing Loop Progress: "); + PrintPercent(0, 1); + } + for (siphon = 0; siphon < originalSiphons; siphon++) + { + /*Initialize the stuff that doesn't change within the middle loop.*/ + MiddleLoopInit(&data, &result, siphon); + /*The middle loop runs until we have removed all rows from M/N*/ + while (NumberOfRows(data.M)) + { + /*Initialize the stuff for the innermost loop run.*/ + InnerLoopInit(&data, Dm, Dp); + /*Run the inner loop. This has been moved to its own function.*/ + newIndex = DoInnerLoop(&data, Dm, Dp, newIndex); + /*Now concatenate MT onto M and NT onto N.*/ + if (NumberOfRows(data.MT)) InsertRows(&data.M, &data.MT, -1, -1); + if (NumberOfRows(data.NT)) InsertRows(&data.N, &data.NT, -1, -1); + /*Remove the first row of M and N.*/ + RemoveRows(&data.M, 0, 1, -1); + RemoveRows(&data.N, 0, 1, -1); + } + /*Deallocate whatever still needs to be deallocated - M and N.*/ + DeallocateMatrix(&data.M); + DeallocateMatrix(&data.N); + /*If verbosity is high enough, print a progress percentage.*/ + if (is_verbose() >= VRB_ASIPH) + { + PrintPercent(siphon + 1, originalSiphons); + } + } + if (is_verbose() >= VRB_ASIPH) + { + PrintPercent(1, 1); + printf("\n"); + } + /*If MNS is empty, build it based on if there are any source transitions.*/ + result = BuildResult(Dm, Dp, &data, newIndex); + FreeMemory(&mem); + return result; +} + +/******************************************************************************* +This function builds the result structure.*/ +asiph_r BuildResult(matrix *Dm, matrix *Dp, asiph_data* data, int *index) +{ + int i, j, oFlag, iFlag, flag = 0; + int *sourceF; + sourceF = tcalloc(NumberOfColumns(*Dm), sizeof(int)); + + /*Build a set of source transition flags.*/ + + /*If MNS is empty, build a new MNS algo... [truncated message content] |
From: <mio...@us...> - 2011-04-02 00:10:32
|
Revision: 245 http://pntool.svn.sourceforge.net/pntool/?rev=245&view=rev Author: miordache Date: 2011-04-02 00:10:24 +0000 (Sat, 02 Apr 2011) Log Message: ----------- 2011 update--second part Added Paths: ----------- pnheaders/ pnheaders/general.c pnheaders/general.h pnheaders/insert.c pnheaders/insert.h pnheaders/main_function.c pnheaders/matrix.c pnheaders/matrix.h pnheaders/pnexample.c pnheaders/pns.c pnheaders/pns.h Added: pnheaders/general.c =================================================================== --- pnheaders/general.c (rev 0) +++ pnheaders/general.c 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,145 @@ +/**************************************************************************** +GENERAL.C -- general purpose functions +Written in 2008-2009 by M. V. Iordache. +****************************************************************************/ + +#include "general.h" +#include<signal.h> + +void merror(int errorlevel, char* str, ...) { + va_list param; + + fprintf(stderr, "\nERROR!\n"); + va_start(param, str); + vfprintf(stderr, str, param); + va_end(param); + fprintf(stderr, "\n"); + + if(!errorlevel) + raise(SIGINT); /* terminate the entire program */ +} + + +inline void* tmalloc(size_t NBYTES) { + void* p; + p = malloc(NBYTES); + if(p == NULL) + merror(0, "Out of memory"); + return p; +} + + +inline void* tcalloc(size_t N, size_t S) { + void* p; + p = calloc(N, S); + if(p == NULL) + merror(0, "Out of memory"); + return p; +} + + +/* void makezero(void* x, size_t n) { // USE memset instead + int i; + char* p; + for( i = 0, p = (char*)x; i <= n-sizeof(char); i++) + *(p+i) = 0; + } */ + + +/*************************************************************************** + MEMORY MANAGEMENT VIA struct alloc +****************************************************************************/ + +void initalloc(struct alloc* x, size_t N) { + x->N = N; x->mem = tcalloc(N, 1); x->i = N; + x->data = tcalloc(1, sizeof(*(x->data))); + x->data->mem = x->mem; x->pos = x->data; +} + + +inline void* smalloc(struct alloc* x, size_t nbytes) { + /* In this algorithm the memory blocks have at least N bytes and when used + as intended approximately N bytes. */ + + if(!x->N) merror(0, "Uninitialized allocation structure!"); + x->i -= nbytes; + if(x->i >= 0) + return (x->mem) + (x->i); + x->pos->next = tcalloc(1, sizeof(*(x->data))); + x->pos = x->pos->next; + x->mem = tmalloc(x->N + nbytes); x->pos->mem = x->mem; x->i = x->N; + return (x->mem) + (x->i); +} + + +void sfree(struct alloc *x) { + struct _alist *p, *q; + for(p = x->data; p; ) { + free(p->mem); + q = p; + p = p->next; + free(q); + } + x->data = 0; /* no segmentation fault if sfree called twice */ +} + + +/*************************************************************************** + QUEUE ALLOCATION AND MANAGEMENT +****************************************************************************/ + +inline struct _qlist *alloc_qpage(size_t n) { + struct _qlist *p; + p = tmalloc(n + sizeof(*p)); + p->mem = &p[1]; + p->next = 0; + return p; +} + +void qfree(struct qalloc *x) { /* Assumes pages allocated with alloc_qpage! */ + struct _qlist *p; + for(p = x->rrpage; p; p = p->next) + free(p); + x->rrpage = 0; /* no segmentation fault if qfree called twice */ + x->frpage = 0; +} + +void initqalloc(struct qalloc* x, size_t n, size_t sz) { + x->N = n*sz; x->sz = sz; + x->front = (x->N); x->rear = (x->N); + x->frpage = alloc_qpage(x->N); + x->rrpage = x->frpage; x->last = x->frpage; + x->nitems = 0; +} + +inline void* place_in_line(struct qalloc* x) { + (x->nitems)++; + x->front -= x->sz; + if( x->front < 0) { + x->front = x->N - x->sz; + if(x->frpage->next) /* use the next page */ + x->frpage = x->frpage->next; + else { /* allocate a new page if none is available */ + x->frpage->next = alloc_qpage(x->N); + x->frpage = x->frpage->next; + x->last = x->frpage; + } + } + return x->frpage->mem + x->front; +} + +inline void* next_in_line(struct qalloc* x) { + if(x->nitems) { + (x->nitems)--; + x->rear -= x->sz; + if( x->rear < 0 ) { + x->rear = x->N - x->sz; + x->last->next = x->rrpage; /* recycle current page */ + x->last = x->last->next; + x->rrpage = x->rrpage->next; + x->last->next = 0; + } + return x->rrpage->mem + x->rear; + } + return 0; +} Added: pnheaders/general.h =================================================================== --- pnheaders/general.h (rev 0) +++ pnheaders/general.h 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,98 @@ + +#ifndef GENERAL_H +#define GENERAL_H + +#include<stdio.h> +#include<stdlib.h> +#include<stdarg.h> +#include<string.h> + +void merror(int errorlevel, char* str, ...); +/* Prints error message. str and the following parameters should be formatted + the same way as for printf. + If errorlevel = 0, the SIGINT signal is sent to terminate the program. */ + +inline void* tmalloc(size_t NBYTES); +inline void* tcalloc(size_t N, size_t S); +/* These functions call malloc and calloc, respectively. In addition, they + terminate the program via merror(...) when memory cannot be allocated. */ + +/**************************************************************************/ +/* Memory management for structures that allocate small amounts of memory + at a time */ + +struct _alist { + void* mem; /* pointer to allocated memory */ + struct _alist *next; +}; + + +struct alloc { + size_t N; /* the min size of the blocks of memory will be N + 1 */ + void* mem; /* pointer to current block of allocated memory */ + size_t i; /* indicates number of available bytes in mem */ + struct _alist *data, *pos; /* pos points to the current alist element */ +}; + + +void initalloc(struct alloc* x, size_t N); +/* Must be called before using the allocation object! + N determines the number of bytes of the memory blocks that are allocated. +*/ + +inline void* smalloc(struct alloc* x, size_t nbytes); +/* Use it in the place of malloc. The function is optimized for speed, not for + memory usage. Memory is best used if nbytes is small. The fraction of unused + allocated memory is in the worst case (max(nbytes)-1)/(x->N + 1), where + max(nbytes) is the maximum value given by the program to nbytes. */ + +void sfree(struct alloc *x); +/* Deallocates the memory blocks addressed by the object. */ + +/**************************************************************************/ +/* Memory management for queues */ + +struct _qlist { + void* mem; /* pointer to allocated memory */ + struct _qlist *next; +}; + + +/* The structures is organized in blocks of memory called here pages. Each + page can store N bytes. A page stores elements of size sz bytes. */ +struct qalloc { + size_t N, sz; /* N: bytes per page, sz: bytes per element */ + size_t front, rear; /* front: position of last element; + rear: position of first element; */ + size_t nitems; /* number of items in the queue */ + struct _qlist *frpage, *rrpage; /*the pages of front and rear, respectively*/ + struct _qlist *last; /* pointer to the last element of the chain of pages */ + + /* Note that rrpage always points to the first page of the chain. Once all + elements on a page have been removed, the empty page is placed at the end + of the chain and rrpage points to the new first page of the chain. + + Each time a new element is added to the queue, front -= sz, until front + becomes negative. Then, frpage is set to the next page. If there is no + next page, a new page is allocated. + */ +}; + +void initqalloc(struct qalloc* x, size_t n, size_t sz); +/* Must be called before using the allocation object! + n: number of elements of (max) size sz per block of memory. +*/ + +inline void* place_in_line(struct qalloc* x); +/* Places a new element in line and returns a pointer to it. */ + +inline void* next_in_line(struct qalloc* x); +/* Removes from queue the element returned in the previous call (the + first element in line) and returns the next element in line. The return + value is in the form of a pointer to the element. The pointer is null if + no element remains in line. */ + +void qfree(struct qalloc *x); +/* Deallocates the memory blocks addressed by the object. */ + +#endif Added: pnheaders/insert.c =================================================================== --- pnheaders/insert.c (rev 0) +++ pnheaders/insert.c 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,291 @@ +/* INSERT.C: Only one task may use these function at a time. Variables + must be reinitialized each time a new task begins to use it. */ + +#include"insert.h" +#include<stdlib.h> +#include<string.h> + +/* defined in insert.h + struct myinsert { + long INCR; + long strg_size, strg_len; + char* strg, *tmp, stmp[10], *IndString; + }; */ + +struct myinsert InitInsert(int i) { + struct myinsert ret; + memset(&ret, 0, sizeof(ret)); + if (i < 2) + ret.INCR = BUFINC; + else + ret.INCR = i; + ret.strg_size = 0; + ret.strg_len = 0; + ret.strg = 0; + return ret; +} + +char* GetInsertBuf(struct myinsert* s) { + return s->strg; +} + + +void Empty(struct myinsert* s) { + if(s) { + if(s->strg) + if(s->strg_size) { + s->strg_len = 0; + s->strg[0] = 0; + } + if(s->IndString) + free(s->IndString); + s->IndString = 0; + } +} + + +void FreeIns(struct myinsert* s) { // does not free the main buffer + long x; + + if(s) { + x = s->INCR; + if(s->IndString) + free(s->IndString); + memset(s, 0, sizeof(*s)); + s->INCR = x; + } +} + + +struct myinsert AddToIndent(struct myinsert ins, int n) { + int k; + char *sa; + + if(!ins.IndString && n <= 0) + return ins; + if(!ins.IndString) { // here n > 0 + ins.IndString = calloc(n+1, sizeof(char)); // initializes data to zero + memset(ins.IndString, ' ', n); + return ins; + } + k = strlen(ins.IndString); + if(k + n <= 0) { + free(ins.IndString); + ins.IndString = 0; + return ins; + } + + if(n > 0) { + sa = calloc(k+n+1, sizeof(char)); + strcpy(sa, ins.IndString); + memset(sa+k, ' ', n); + free(ins.IndString); + ins.IndString = sa; + } + + ins.IndString[k+n] = 0; // all that is needed when n < 0 + + return ins; +} + + +struct myinsert FSInsert(struct myinsert ins, const char *str, ...) { + char* p; + va_list param; + + if(str) + if(strlen(str)) { + va_start(param, str); + vasprintf(&p, str, param); + va_end(param); + + ins = SInsert(p, ins); + + free(p); + } + return ins; +} + + + +struct myinsert SInsert_sub(char* s, size_t k, struct myinsert ins) { + // k is the length of s (without the final 0 element) + + long i, j; + + if(!s) + return ins; + i = ins.strg_len; + if(k <= 0) + return ins; + ins.strg_len += k; + if(ins.strg_size <= ins.strg_len + 1) { + for(; ins.strg_size <= ins.strg_len + 1; ins.strg_size += ins.INCR); + if(!ins.strg) { + ins.strg = calloc(ins.strg_size, sizeof(*ins.strg)); + if(!ins.strg) { + printf("Sinsert: unable to allocate %ld bytes\n", ins.strg_size); + exit(EXIT_FAILURE); + } + strcpy(ins.strg, s); + return ins; + } + else { /* if more memory is needed */ + ins.tmp = calloc(ins.strg_size, sizeof(*ins.strg)); + if(!ins.tmp) { + printf("Sinsert: unable to allocate %ld bytes\n", ins.strg_size); + exit(EXIT_FAILURE); + } + strcpy(ins.tmp, ins.strg); + free(ins.strg); + ins.strg = ins.tmp; + } + } + for(j = 0; i + j < ins.strg_len; j++) /* concatenate the strings */ + ins.strg[i+j] = s[j]; + ins.strg[i+j] = 0; + + return ins; +} + + + +struct myinsert CInsert(char c, struct myinsert ins) { + if(c == 0) + return ins; + if(ins.strg_size <= ins.strg_len + 1) { + ins.strg_size += ins.INCR; + if(!ins.strg) { + ins.strg = calloc(ins.strg_size, sizeof(*ins.strg)); + if(!ins.strg) { + printf("Cinsert: unable to allocate %ld bytes\n", ins.strg_size); + exit(EXIT_FAILURE); + } + } + else { + ins.tmp = calloc(ins.strg_size, sizeof(*ins.tmp)); + if(!ins.tmp) { + printf("Cinsert: unable to allocate %ld bytes\n", ins.strg_size); + exit(EXIT_FAILURE); + } + strcpy(ins.tmp, ins.strg); + free(ins.strg); + ins.strg = ins.tmp; + } + } + ins.strg[ins.strg_len++] = c; /* update ins.strg and ins.strg_len */ + ins.strg[ins.strg_len] = 0; + + if(c == '\n' && ins.IndString) + ins = SInsert_sub(ins.IndString, strlen(ins.IndString), ins); + + return ins; +} + + + +struct myinsert SInsert(char* s, struct myinsert ins) { + long i, j; + size_t k; + char c; + + if(!s) + return ins; + k = strlen(s); + if(!k) + return ins; + if(!ins.IndString) { + ins = SInsert_sub(s, k, ins); + } + else { + for(i = 0, j = 0; i < k; i++) { + if(s[i] == '\n') { + ins = SInsert_sub(s+j, i-j+1, ins); // insert s[j] ... s[i] + j = i+1; + ins = SInsert_sub(ins.IndString, strlen(ins.IndString), ins); + } + } + if(j < i) // insert remaining part of string, if any is left + ins = SInsert_sub(s+j, k-j, ins); // insert s[j] ... s[k-1] + } + return ins; +} + + + long INCR = BUFINC; + long strg_size = 0, strg_len = 0; + char* strg = 0, *tmp, stmp[10]; + + +void init_insert() { + strg_size = 0; strg_len = 0; strg = 0; +} + +char* get_insert_buf() { + return strg; +} + +void cinsert(char c) { + if(c == 0) + return; + if(strg_size <= strg_len + 1) { + strg_size += INCR; + if(!strg) { + strg = calloc(strg_size, sizeof(*strg)); + if(!strg) { + printf("Cinsert: unable to allocate %ld bytes\n", strg_size); + exit(EXIT_FAILURE); + } + } + else { + tmp = calloc(strg_size, sizeof(*tmp)); + if(!tmp) { + printf("Cinsert: unable to allocate %ld bytes\n", strg_size); + exit(EXIT_FAILURE); + } + strcpy(tmp, strg); + free(strg); + strg = tmp; + } + } + strg[strg_len++] = c; /* update strg and strg_len */ + strg[strg_len] = 0; +} + + +void sinsert(char* s) { + long i, j; + size_t k; + if(!s) + return; + i = strg_len; + k = strlen(s); + if(!k) + return; + strg_len += k; + if(strg_size <= strg_len + 1) { + for(; strg_size <= strg_len + 1; strg_size += INCR); + if(!strg) { + strg = calloc(strg_size, sizeof(*strg)); + if(!strg) { + printf("Sinsert: unable to allocate %ld bytes\n", strg_size); + exit(EXIT_FAILURE); + } + strcpy(strg, s); + return; + } + else { /* if more memory is needed */ + tmp = calloc(strg_size, sizeof(*strg)); + if(!tmp) { + printf("Sinsert: unable to allocate %ld bytes\n", strg_size); + exit(EXIT_FAILURE); + } + strcpy(tmp, strg); + free(strg); + strg = tmp; + } + } + for(j = 0; i + j < strg_len; j++) /* concatenate the strings */ + strg[i+j] = s[j]; + strg[i+j] = 0; +} Added: pnheaders/insert.h =================================================================== --- pnheaders/insert.h (rev 0) +++ pnheaders/insert.h 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,49 @@ +#ifndef INSERT_H +#define INSERT_H + +#include<stdarg.h> + +#define BUFINC 10024 + +struct myinsert { + long INCR; + long strg_size, strg_len; + char* strg, *tmp, stmp[10], *IndString; +}; + +/* These insert functions work with any number of buffers at the same time */ + +struct myinsert InitInsert(int i); +/* i: size increment of allocation buffer; use i = 0 for the default value */ + +struct myinsert AddToIndent(struct myinsert ins, int n); +/* Adds n blank spaces to default indentation; n may be negative. */ + +struct myinsert CInsert(char c, struct myinsert ins); + +struct myinsert SInsert(char* s, struct myinsert ins); + +struct myinsert FSInsert(struct myinsert ins, const char *str, ...); +/* Same as SInsert except it can use a printf formatted string */ + +char* GetInsertBuf(struct myinsert* s); +/*gets the result; this should be deallocated with free() if no longer needed*/ + +void Empty(struct myinsert* s); +/* Use this function if buffer should be reused. It empties the buffer without + deallocating it. Resets also indentation. */ + +void FreeIns(struct myinsert* s); +/* Does not deallocate the buffer, which is the responsibility of the user. */ + +/* These insert functions work with ONE buffer ONLY at a time */ + +void init_insert(); + +void cinsert(char c); + +void sinsert(char* s); + +char* get_insert_buf(); + +#endif Added: pnheaders/main_function.c =================================================================== --- pnheaders/main_function.c (rev 0) +++ pnheaders/main_function.c 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,304 @@ +#include "pns.h" +#include "spnbox.h" +#include "codegen.h" +#include"insert.h" + +int verb; + +int inline is_verbose() { return verb; } + +void br_filter(char *p) { // removes beginning and end braces + int n; + if(!p) + return; + n = strlen(p); + if(!n) + return; + n--; + if(p[0] == '{' && p[n] == '}') { + p[0] = ' '; + p[n] = ' '; + } +} + + +int is_empty(char *p) { // returns 1 if p has only space and tab characters + int i; + if(!p) return 1; + for(i = 0; p[i]; i++) + if(p[i] != ' ' && p[i] != '\t') + break; + return ! p[i]; +} + +int th_filter(char** ap) { // filters <thread> commands + char* p = *ap, *p2 = 0; + int i; + if(!p) return 0; + for(i = 0; p[i]; i++) { + if(p[i] == ' ' || p[i] == '\t') + continue; + if(!strncmp(p+i, "<thread>", 8)) { + if(!is_empty(p+i+8)) // else p2 remains equal to zero + asprintf(&p2, "%s", p+i+8); + free(*ap); + *ap = p2; + return 1; + } + break; + } + return 0; +} + + +void sp_filter(specs *sp) { + // Removes beginning and end braces. + // Processes <thread> instructions. + int i, j; + pns *pn; + arcs *pa; + if(!sp) + return; + if(!sp->process_array) + return; + for(i = 0; i < sp->process_num; i++) { + if(!sp->process_array[i]) + continue; + br_filter(sp->process_array[i]->build); + br_filter(sp->process_array[i]->include); + if(th_filter(&(sp->process_array[i]->build))) + sp->process_array[i]->thread = 1; + pn = sp->process_array[i]->pn; + if(pn) { + if(pn->segment) + for(j = 0; j < pn->pnum; j++) + br_filter(pn->segment[j]); + if(pn->select) + for(j = 0; j < pn->pnum; j++) + br_filter(pn->select[j]); + if(pn->arc_list) + for(j = 0; j < pn->tnum; j++) + for(pa = pn->arc_list[j]; pa; pa = pa->next) + br_filter(pa->condition); + } + } +} + + +int main(int na, char* argv[]) { + + int i, j, l1, l2, UCcnt, UOcnt, *Tuc, *Tuo, *UClst, *UOlst; + int labelcount = 0, finish = 0; + char* input, *build; + FILE* f; + specs *sp; + syncc *snc; + pns pn, *apnsv; + matrix L, C, H; + int *B; + struct myinsert ins; + linenf_r lin_res; + struct synclist *syncl, *syncl2; + struct sync_element *syn_el, *syn_el2; + struct label_lst* lls; + TrData** TInf; + + + ins = InitInsert(512); // used to store command line parameters + verb = 0; + input = 0; + + if(na <= 1 || na > 3) { + printf("\nACTS--A Concurrency Tool Suite for concurrent programming and concurrent \nsystem design. This software is part of ongoing research to apply supervisory\ncontrol and related approaches to concurrency problems. While various \nsupervisory control tools should be implemented in the future, currently only\nmethods of the supervision based on place invariants are implemented. For \nmore information please refer to the documentation.\n\ +\nUsage: ct [-dnum] file [-b ...]\ +\nOptions:\ +\n -b ... List of files and compiler options that should be copied to\ +\n the command line that builds the main program.\ +\n -d<num> Comment on execution progress. More information displayed for\ +\n high values of <num>.\ +\n\ +\nExamples: ct manf.sp\ +\n ct -d3 input.sp\n"); + + finish = 1; + } + + for(i = 1; i < na && !finish; i++) { + if(argv[i][0] == '-') { + switch(argv[i][1]) { + case 'd': verb = atoi(argv[i]+2); + break; + case 'b': if(argv[i][2]) + ins = FSInsert(ins, " %s", argv[i]+2); + for(i = i + 1; i < na; i++) + ins = FSInsert(ins, " %s", argv[i]); + break; + default: fprintf(stderr, "Unknown option %s.\n", argv[i]); + } + } + else { + if(input) + fprintf(stderr, "Unexpected parameter %s.\n", argv[i]); + else + input = argv[i]; + } + } + + if(!input) { + fprintf(stderr, "No input file specified."); + finish = 1; + } + else { + f = fopen(input,"r"); + if(!f) { + fprintf(stderr, "The file %s cannot be opened.\n", input); + finish = 1; + } + else { + if(verb && !finish) + fprintf(stderr, "Using the input file %s ...\n", input); + fclose(f); + } + } + + build = GetInsertBuf(&ins); + + if(finish) { // Terminate if errors were encountered + if(build) free(build); + return 0; + } + + // Call the translator + + sp = ScanInput(input); + if(!sp) // check translator result + return 1; + if(sp->process_num <= 0) { + fprintf(stderr, "No processes defined! Nothing to do.\n"); + dealloc_specs(sp); + if(build) free(build); + return 0; + } + + sp_filter(sp); // remove extra braces + + if(is_verbose() >= 3) { // For debugging + for(i = 0; i < sp->process_num; i++) { + printf("\n\n======================================================"); + printf("\nPROCESS NAME: %s\n", sp->process_array[i]->name); + displaypn(*(sp->process_array[i]->pn), stdout); + } + } + + + // Label the PNs + + for(i = 0; i < sp->process_num; i++) + updatepn(sp->process_array[i]->pn, "freelabel", &labelcount); + + // Deal with synchronization constraints + + for(i = 1; i; ) /* i = 0 indicates when loop may end */ + for(i = 0, snc = sp->synclist; snc; snc = snc->next) { + l1 = snc->pn1->t[snc->t1].l; l2 = snc->pn2->t[snc->t2].l; + if(l1 != l2) { + i = 1; + j = (l1 > l2)?l1:l2; + snc->pn1->t[snc->t1].l = j; snc->pn2->t[snc->t2].l = j; + } + } + + // Obtain SC specification. Currently: + // extract the L, C, H, and b matrices (more complex specs to be done later) + + extractLHCB(sp, &pn, &L, &H, &C, &B); + + if(is_verbose() >= 3) { // For debugging + printf("\n\n======================================================"); + printf("\nCONSTRAINTS:\n"); + printLHCB(&pn, &L, &H, &C, B, -1, stdout); + } + + // Perform SC + + Tuc = tcalloc(pn.tnum, sizeof(*Tuc)); + Tuo = tcalloc(pn.tnum, sizeof(*Tuo)); + if(pn.t) + for(i = 0; i < pn.tnum; i++) { + Tuc[i] = pn.t[i].uncontrollable; + Tuo[i] = pn.t[i].unobservable; + } + + UCcnt = findIndices(Tuc, pn.tnum, sizeof(*Tuc), &UClst); + UOcnt = findIndices(Tuo, pn.tnum, sizeof(*Tuo), &UOlst); + + lin_res = linenf(&pn.out, &pn.in, &L, B, pn.marking, &H, &C, \ + UCcnt, UClst, UOcnt, UOlst); + + if(is_verbose() >= 3) { // For debugging + printf("\n\n======================================================"); + printf("\nADMISSIBLE CONSTRAINTS (H entries omitted): \n"); + printLHCB(&pn, &lin_res.Lf, 0, &lin_res.Cf, lin_res.bf, -1, stdout); + } + + free(Tuc); free(Tuo); free(UClst); free(UOlst); + + // Check whether SC was successful + + if(strcmp(lin_res.how, "OK")) + merror(0, "MAIN FUNCTION: SC has failed. Relax the specification\n\ + such as by reducing the number of uncontrollable and unobservable transitions"); + + // Enforce liveness + + // no liveness enforcement at this time + + // Extract supervisor as a pn + + apnsv = getSupervisor(&pn, &lin_res.Dfm, &lin_res.Dfp, lin_res.ms0); + + if(is_verbose() >= 3) { // For debugging + printf("\n\n======================================================"); + printf("\nCOMPOSED PN\n"); + displaypn(pn, stdout); + printf("\n\n======================================================"); + if(apnsv) { + printf("\nSUPERVISOR PN\n"); + displaypn(*apnsv, stdout); + } + else + printf("\nNO SUPERVISOR PN\n"); + } + deallocpn(&pn); + + // need functions to free linenf_r structures and similar structures + + // Generate code + + + + // Obtain also a synclist structure with the sync data + lls = get_label_list(sp->process_array, sp->process_num); + syncl = get_synclist(lls, sp->process_array); + TInf = get_TrData(apnsv, sp->process_array, sp->process_num, lls); + + //exit(1); + + CodeGenerator(apnsv, sp->name, sp->process_array, sp->process_num,\ + syncl, TInf, build); + + // Free memory + + if(apnsv) { + deallocpn(apnsv); + free(apnsv); + } + dealloc_specs(sp); + if(build) free(build); + free_label_list(lls); + free_synclist(syncl); + free_TrData(TInf, sp->process_num); + + return 0; +} + Added: pnheaders/matrix.c =================================================================== --- pnheaders/matrix.c (rev 0) +++ pnheaders/matrix.c 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,512 @@ +/**************************************************************************** +MATRIX.C +Written in 2008-2009 by M. V. Iordache. +****************************************************************************/ + +#include "pns.h" + +MatrElem* FindEl(const matrix* m, int i, int j, MatrElem** next, int dir) { + /* THE FUNCTION TAKES IN ACCOUNT THE trans FIELD OF m! + It finds a pointer to the element (i,j) if it has a MatrElem object in the + matrix. Otherwise it returns zero. The search is done in the direction + indicated by 'dir', which can be one of mDOWN, mUP, mRIGHT, or mLEFT. + The function writes to '*next' the element next to the (i,j) position in + the direction indicated by 'dir'. If no other element is present, *next + is made zero. + */ + + int ii, jj, k = -1; /* k must be initialized to a value less than 0 */ + MatrElem* p; + + if(m->type != 3 || m->nc <= 0 || m->nr <= 0) { + merror(0, "FindEl: The operation is not implemented."); + return 0; + } + + dir = dir^m->trans; /* xor with m->trans to correct direction */ + + if(m->trans) { + ii = j; jj = i; + } + else { + ii = i; jj = j; + } + + if(!(dir&1)) {/* that is, if(dir == mRIGHT || dir == mLEFT) */ + p = m->row[ii]; + if(p) { + for( ; (k < p->column) && (jj > p->column); p = p->next[mRIGHT]) + k = p->column; + + if(p->column == jj) { + *next = p->next[dir]; + return p; + } + if(dir == mLEFT) { /* else *next will be set to p in a subsequent line */ + *next = p->next[mLEFT]; + return 0; + } + } + } + else {/* that is, if(dir == mDOWN || dir == mUP) */ + p = m->column[jj]; + if(p) { + for( ; (k < p->row) && (ii > p->row); p = p->next[mDOWN]) + k = p->row; + + if(p->row == ii) { + *next = p->next[dir]; + return p; + } + if(dir == mUP) { /* else *next will be set to p in a subsequent line */ + *next = p->next[mUP]; + return 0; + } + } + } + *next = p; + return 0; +} + +inline mtype _matrel3(const matrix* m, int i, int j) { + MatrElem *p, *next; + + p = FindEl(m, i, j, &next, mRIGHT); + if(!p) + return 0; + return p->value; +} + +mtype GetMatrixEl(const matrix* m, int i, int j) { + switch(m->type) { + case 1: + return m->trans?m->elem[j*m->nc+i]:m->elem[i*m->nc+j]; + case 2: + return m->trans?m->ar[j][i]:m->ar[i][j]; + case 3: + return _matrel3(m, i, j); + default: + merror(0, "MATRIX: The operation is not implemented."); + } + return 0; +} + + + +inline void _setmatrel3(const matrix* m, int i, int j, mtype x) { + int ii, jj; + int dir; + MatrElem *p, *next, *next2; + + /* If an already allocated element is set to zero it is not deleted + (deallocated) in this version of the function. */ + + p = FindEl(m, i, j, &next, mRIGHT); /* signals error if m->nr or m->nc = 0 */ + if(p) { /* if the element has been already allocated */ + p->value = x; + return; + } + + /* The following lines executed if element (i,j) not allocated in matrix. */ + + if(!x) /* nothing to do if the element is not allocated and x = 0 */ + return; + + /* Create and initialize new element of the matrix */ + + p = tmalloc(sizeof(*p)); + p->value = x; + if(m->trans) {/*ii and jj: row and column number in internal representation*/ + ii = j; jj = i; + } + else { + ii = i; jj = j; + } + p->column = jj; + p->row = ii; + + /* Place element in matrix */ + + if(!next) { + if(m->trans){/*if transposed, search to mRIGHT in FindEl is to mDOWN in m*/ + m->column[jj] = p; + p->next[mDOWN] = p; + p->next[mUP] = p; + } + else { + m->row[ii] = p; + p->next[mRIGHT] = p; + p->next[mLEFT] = p; + } + } + else { + dir = mRIGHT^(m->trans);/*next obtained by a search in the mRIGHT direction*/ + p->next[dir] = next; /*dir = mDOWN or mRIGHT depending on trans = 1 or 0 */ + p->next[dir^2] = next->next[dir^2]; /* dir^2 = mUP or mLEFT */ + next->next[dir^2]->next[dir] = p; + next->next[dir^2] = p; + } + + FindEl(m, i, j, &next2, mDOWN); + if(!next2) { + if(m->trans){/*if transposed, search to mDOWN in FindEl is to mRIGHT in m*/ + m->row[ii] = p; + p->next[mRIGHT] = p; + p->next[mLEFT] = p; + } + else { + m->column[jj] = p; + p->next[mDOWN] = p; + p->next[mUP] = p; + } + } + else { + dir = mDOWN^(m->trans);/*next2 obtained by a search in the DOWN direction*/ + p->next[dir] = next2; /*dir = mDOWN or mRIGHT depending on trans = 1 or 0*/ + p->next[dir^2] = next2->next[dir^2]; /* dir^2 = mUP or mLEFT */ + next2->next[dir^2]->next[dir] = p; + next2->next[dir^2] = p; + } + + /* update row and column to point to the first element in chain */ + if(m->row[ii]->column > p->column) + m->row[ii] = p; + if(m->column[jj]->row > p->row) + m->column[jj] = p; +} + +void SetMatrixEl(matrix* m, int i, int j, mtype x) { + switch(m->type) { + case 1: + if(m->trans) + m->elem[j*m->nc+i] = x; + else + m->elem[i*m->nc+j] = x; + break; + case 2: + if(m->trans) + m->ar[j][i] = x; + else + m->ar[i][j] = x; + break; + case 3: + _setmatrel3(m, i, j, x); + break; + default: + merror(0, "MATRIX: The operation is not implemented."); + } +} + + +inline MatrElem* NextEl(const matrix* m, int dir, int pos, MatrElem* current) { + /* Finds the next element on the row or column 'pos' (depending on 'dir'). + Returns 0 if no other element is in the specified direction. */ + /* This function is for type 3 matrices in which not all elements are + allocated in memory. Thus, the function returns the next allocated + allocated element. */ + /* If called within a loop, the function will give the right result if + the matrix chains are not modified between calls. */ + /* It does not verify that pos and current->row/column are consistent! */ + /* 'dir' is one of mRIGHT, mLEFT, mUP, mDOWN; the next element is searched + on the row 'pos' if 'dir' is mRIGHT or mLEFT and else on the column 'pos'. + */ + /* Here is an example on how this function could be used in a loop: + p = 0; + for(p = NextEl(&(pn1.in),mUP,i,p); p; p = NextEl(&(pn1.in),mUP,i,p)) { + if(pn1.in.trans) // pn1 is transposed! + SetMatrixEl(&(pn.in), p->column, i, p->value); + else + SetMatrixEl(&(pn.in), p->row, i, p->value); + } + */ + MatrElem *p, *pt, **pbase; + + if(m->type != 3) { + merror(0, "NextEl: The operation is not implemented."); + return 0; + } + dir = dir^m->trans; /* xor with m->trans to correct direction */ + + if(!(dir&1)) /* that is, if(dir == mRIGHT || dir == mLEFT) */ + pbase = m->row; + else /* that is, if(dir == mUP || dir == mDOWN) */ + pbase = m->column; + + p = pbase[pos]; + if(!current) + return p; + if(!p) + return 0; /* no (allocated) elements on the row, so return 0. */ + pt = current->next[dir]; + if(p == pt) + return 0; /* all elements of the chain have been visited, so return 0 */ + return pt; +} + + +void AllocateMatrix(matrix* m, int nr, int nc) { + if(nr*nc <= 100) + AllocateMatrixType(1, m, nr, nc); + else + AllocateMatrixType(2, m, nr, nc); +} + + +void AllocateMatrixType(int type, matrix* m, int nr, int nc) { + int i; + + memset(m, 0, sizeof(matrix)); /* Initializes to zero the structure */ + m->nr = nr; + m->nc = nc; + m->type = type; + + if(!nr || !nc) + return; + + switch(type) { + case 1: + m->elem = tcalloc(nc*nr, sizeof(mtype)); + return; + case 2: + m->ar = tcalloc(nr, sizeof(mtype*)); + for(i = 0; i < nr; i++) + m->ar[i] = tcalloc(nc, sizeof(mtype)); + return; + case 3: + m->row = tcalloc(nr, sizeof(*(m->row))); + m->column = tcalloc(nc, sizeof(*(m->column))); + return; + default: + merror(0, "MATRIX: The operation is not implemented."); + } +} + + + +void Copy2ZeroColumn(const matrix* src, int i, matrix* dst, int k, int offset){ + /* Copies the allocated elements of column i of src to the column k of dst. + Namely, it does dst[offset + j][k] = src[j][i] for all j such that + src[j][i] is allocated. Now, IF the column k of dst is zero, this means + that we copy the column i of src to the column k of dst. This function + is intended for type 3 matrices. + + Example: When a Petri net object pn1 is copied to a new Petri net object + pn, we could copy the column i of the input matrix of pn1 as follows: + Copy2ZeroColumn(&(pn1.in),i,&(pn.in),i,0); + */ + + MatrElem* p = 0; /* it is essential that p is initialized to zero */ + int j; + + if(src->type == 3) { + for(p = NextEl(src,mUP,i,p); p; p = NextEl(src,mUP,i,p)) { + if(src->trans) /* */ + SetMatrixEl(dst, offset + (p->column), k, p->value); + else + SetMatrixEl(dst, offset + (p->row), k, p->value); + } + } + else + for(j = 0; j < NumberOfRows(*src); j++) + SetMatrixEl(dst, offset + j, k, GetMatrixEl(src,j,i)); +} + + +void MakeZeroColumn(matrix* dst, int col) { + /* Makes zero the column col of dst. The implementation could be optimized if + needed. */ + + int i, n; + n = NumberOfRows(*dst); + for(i = 0; i < n; i++) + SetMatrixEl(dst, i, col, 0); +} + +void MakeZeroRow(matrix* dst, int num) { + /* Makes zero the row num of dst. The implementation could be optimized if + needed. */ + + int i, n; + n = NumberOfColumns(*dst); + for(i = 0; i < n; i++) + SetMatrixEl(dst, num, i, 0); +} + + +void CopyBlock(int nx, int ny, const matrix* src, int xs, int ys,\ + matrix* dst, int xd, int yd) { + /* Copies a block of nx by ny elements of src to dst. Specifically, it + copies the elements (xs+i, ys+j) of src to (xd+i, yd+j) of dst for all + i = 0...nx-1 and j = 0...ny-1. */ + int i, j; + + /* This is a plain implementation; it could be optimized in the future */ + + switch(src->type) { + case 3: + /* if(dst->type != 3) { + for(i = 0; i < nx; i++) { + p = NextEl(src, mRIGHT, i+xs, 0); + if(!p) { // all elements are zero + for(j = 0; j < ny; j++) + SetMatrixEl(dst, i+xd, j+yd, 0); + } + ... + for(j = 0; j < ny; j++) { + if(src->trans) { // rows actually columns + if(j <= (p->row - yd)) + } + } + } + } */ + default: + for(i = 0; i < nx; i++) + for(j = 0; j < ny; j++) + SetMatrixEl(dst, i+xd, j+yd, GetMatrixEl(src, i+xs, j+ys)); + } +} + + +void CopyMatrix(const matrix* src, matrix* dst) { + CopyBlock(NumberOfRows(*src), NumberOfColumns(*src), src, 0, 0, dst, 0, 0); +} + + +int** matrix2array(matrix mat) { +/* Converts a matrix object to an array of integers: result[i][j] = elem(i,j)*/ + int** res, i, j; + res = tmalloc(sizeof(int*)*mat.nr); + for(i = 0; i < mat.nr; i++) { + res[i] = tmalloc(sizeof(int)*mat.nc); + for (j = 0; j < mat.nc; j++) + res[i][j] = GetMatrixEl(&mat, i, j); + } + return res; +} + + +int** vector2array(int* v, int nr, int nc) { + int** res, i, j; + res = tmalloc(sizeof(int*)*nr); + for(i = 0; i < nr; i++) { + res[i] = tmalloc(sizeof(int)*nc); + for (j = 0; j < nc; j++) + res[i][j] = v[i*nc + j]; + } + return res; +} + + +matrix array2matrix(int** ar, int nr, int nc) { + matrix m; + int i, j, k; + + AllocateMatrix(&m, nr, nc); + for(i = 0; i < nr; i++) + for(j = 0; j < nc; j++) + SetMatrixEl(&m, i, j, ar[i][j]); + + return m; +} + +matrix vector2matrix(int* v, int nr, int nc) { + matrix m; + int i, j, k; + + AllocateMatrix(&m, nr, nc); + for(i = 0, k = 0; i < nr; i++) + for(j = 0; j < nc; j++, k++) + SetMatrixEl(&m, i, j, v[k]); + + return m; +} + + + +int findIndices(void* vect, int n, int esize, int** answer ) { +/* Finds the indices of the nonzero elements of 'vect'. Here, 'vect' is a + vector of 'n' elements. Each element of 'vect' has the size 'esize'. The + return value is the number of nonzero indices. Further, the indices are + stored in 'answer'. Note that *answer is a pointer to memory allocated + in this function. Memory is always allocated, even if there are no indices. + + This function is similar to the find function of Matlab. */ + + int count, i, j; + void* p; + + *answer = tcalloc(n, sizeof(int)); + + if(sizeof(char) != 1) + merror(0, "findIndices has to be rewritten!"); + + for(count = 0, i = 0, p = vect; i < n; i++, p+= esize) + for(j = 0; j < esize; j++) + if( *(char*)( p + j ) ) { + (*answer)[count++] = i; + break; + } + + return count; +} + + + +void free2Darray(int** ar, int nr) { +/* Used to deallocate an array created with matrix2array or vector2array; nr is the number of rows */ + + int i; + for(i = 0; i < nr; i++) + free(ar[i]); + free(ar); +} + + +void inline _delmatr3(matrix* m) { + int i; + MatrElem* p, *pt; + for (i = 0; i < (m->nr); i++) { + p = m->row[i]; + if(p) { + p->next[mLEFT]->next[mRIGHT] = 0; + while(p) { + pt = p->next[mRIGHT]; + free(p); + p = pt; + } + } + } + free(m->row); + free(m->column); +} + +void DeallocateMatrix(matrix* m) { + switch(m->type) { + case 1: + if(m->nr && m->nc && m->elem) + free(m->elem); + break; + case 2: + if(m->nr && m->nc) + free2Darray((int**) (m->ar), (int) m->nr); + break; + case 3: + if(m->nr && m->nc) { + _delmatr3(m); + } + break; + default: + merror(0, "MATRIX: The operation is not implemented."); + } + memset(m, 0, sizeof(*m)); +} + + +/* To do: + - _setmatrel3 does not deallocate elements set to zero + - consider better matrix representations. For instance, for type 3 + matrices, consider better representations of row and column than + int*. The improvements are to be intended for a more effient + representation of very large matrices. + - CopyBlock could be optimized for type 3 matrices. +*/ Added: pnheaders/matrix.h =================================================================== --- pnheaders/matrix.h (rev 0) +++ pnheaders/matrix.h 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,143 @@ +#ifndef _MATRIX_H +#define _MATRIX_H + +#include "general.h" + +typedef short int mtype; + +/* The following structure useful for matrices in which most elements are 0. */ +typedef struct MatrElem { + mtype value; /* the value of a (nonzero) element */ + int row, column; /* position of element in the matrix */ + struct MatrElem *next[4]; + /* these are pointers to the next (nonzero) elements of the matrix in + the four directions: down, up, right, left */ +} MatrElem; + +/* the following values must not be changed unless the functions performing + the basic operations on MatrElem are also updated */ +#define mDOWN 1 +#define mUP 3 +#define mRIGHT 0 +#define mLEFT 2 + +typedef struct matrix { + int nc; /* number of columns */ + int nr; /* number of rows */ + unsigned int type:3; /* indicates the type of matrix representation */ + unsigned int trans:1; /* indicates whether the matrix is transposed */ + /* when the matrix is transposed, the element (i,j) of the matrix is + interpreted as the element (j,i). */ + union { + mtype *elem; /* matrix representation for type = 1 */ + /* nr*nc elements in this order: row 1, row 2, row 3, ... */ + /* If trans = 0, it is not transposed: elem(i,j) = elem[i*nc + j]. + Otherwise, it is transposed: elem(i,j) = elem[j*nc + i]. */ + + mtype **ar; /* matrix representation for type = 2 */ + + struct { /* matrix representation for type = 3 */ + MatrElem** row; + MatrElem** column; + /* rows and columns organized as chains; for instance, row[i] contains + the address of the first element of the chain on row i. */ + }; + }; +} matrix; + +/* Avoid modifying directly a matrix object. + Use instead the following functions: + - AllocateMatrix (for memory allocation and initialization). + - GetMatrixEl (to obtain the value of the element (i,j) of the matrix). + - SetMatrixEl (to write a number to the element (i,j) of the matrix). + - DeallocateMatrix (to deallocate the memory used by the matrix). +*/ + +void AllocateMatrix(matrix* m, int nr, int nc); +/* This is the first step when defining a matrix. Specify the number of + rows (nr) and the number of columns (nc). Then, the function will allocate + memory to represent the matrix. Moreover, the data will be initialized with + zero (by means of calloc). + + The function selects automatically the matrix type and then calls + AllocateMatrixType */ + +mtype GetMatrixEl(const matrix* m, int i, int j); +/* Returns the element (i,j) of the matrix */ + +void SetMatrixEl(matrix* m, int i, int j, mtype x); +/* Writes x to the element (i,j) of the matrix */ + +#define NumberOfRows(m) ((m).trans?(m).nc:(m).nr) + +#define NumberOfColumns(m) ((m).trans?(m).nr:(m).nc) + +#define MatrixLength(m) ((m).nr*(m).nc) + +void DeallocateMatrix(matrix* m); + +void CopyMatrix(const matrix* src, matrix* dst); +/* The function assumes that dst has been already allocated ! */ + +void CopyBlock(int nx, int ny, const matrix* src, int xs, int ys,\ + matrix* dst, int xd, int yd); +/* Copies a block of nx by ny elements of src to dst. Specifically, it + copies the elements (xs+i, ys+j) of src to (xd+i, yd+j) of dst for all + i = 0...nx-1 and j = 0...ny-1. */ + +void Copy2ZeroColumn(const matrix* src, int i, matrix* dst, int k, int offset); + /* This function is for type 3 matrices. + Copies the allocated elements of column i of src to the column k of dst. + Namely, it does dst[offset + j][k] = src[j][i] for all j such that + src[j][i] is allocated. Now, IF the column k of dst is zero, this means + that we copy the column i of src to the column k of dst. + + Example: When a Petri net object pn1 is copied to a new Petri net object + pn, we could copy the column i of the input matrix of pn1 as follows: + Copy2ZeroColumn(&(pn1.in),i,&(pn.in),i,0); + */ + +void MakeZeroColumn(matrix* dst, int i); +/* Makes zero the column i of dst. */ + +void MakeZeroRow(matrix* dst, int i); +/* Makes zero the row i of dst. */ + +void AllocateMatrixType(int type, matrix* m, int nr, int nc); +/* Allocates the memory required for an nr by nc matrix. Does not deallocate + memory if already allocated. */ + +MatrElem* NextEl(const matrix* m, int dir, int pos, MatrElem* current); +/* Determines the next allocated element in the direction 'dir' at the row or + column number 'pos'. The starting point is the element 'current'. */ +/* If called within a loop, the function will give the right result if + the matrix chains are not modified between calls. */ +/* 'dir' is one of mRIGHT, mLEFT, mUP, mDOWN; pos is the row or column number*/ + + +matrix array2matrix(int** ar, int nr, int nc); +/* Converts array to matrix */ + +matrix vector2matrix(int* v, int nr, int nc); +/* Converts vector to matrix */ + +int** vector2array(int* v, int nr, int nc); +/* Converts vector to array */ + +int** matrix2array(matrix m); +/* Converts a matrix object to an array of integers: result[i][j] = elem(i,j)*/ + +int findIndices(void* vect, int n, int esize, int** answer ); +/* Finds the indices of the nonzero elements of 'vect'. Here, 'vect' is a + vector of 'n' elements. Each element of 'vect' has the size 'esize'. The + return value is the number of nonzero indices. Further, the indices are + stored in 'answer'. Note that *answer is a pointer to memory allocated + in this function. Memory is always allocated, even if there are no indices. + + This function is similar to the find function of Matlab. */ + + +void free2Darray(int** ar, int nr); +/* Use to deallocate an array created with matrix2array or vector2array; nr is the number of rows */ + +#endif Added: pnheaders/pnexample.c =================================================================== --- pnheaders/pnexample.c (rev 0) +++ pnheaders/pnexample.c 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,148 @@ +#include"pns.h" + +int main() { + int i; + + /* Declaring pn objects */ + + pns pn_p, pn_s, pn_s2, pn, pn2; + + /* Petri nets can be initialized using the incidence matrix */ + + /* This will be used for the incidence matrix of one pn */ + + int Dp[] = { 1, 1, -1, 1, 0, 0,\ + 0, 0, 1, 0, -1, 0,\ + 0, -1, 1, 0, 0, -1,\ + -1, 0, 0, 0, 1, 0,\ + 0, 0, 0, -1, 0, 1}; + + int mp[] = { 1, 1, 1, 1, 1}; /* The initial marking */ + + /* These will be used for the input and output matrices of another pn */ + + int Is[] = { 0, 1, 0, 0,\ + 0, 0, 1, 0,\ + 0, 0, 0, 1,\ + 1, 0, 0, 0}; + + int Os[] = { 0, 0, 1, 0,\ + 0, 0, 0, 1,\ + 1, 0, 0, 0,\ + 0, 1, 0, 0}; + + int ms[] = {0, 0, 1, 1}; /* The initial marking */ + + struct placelist *plist; + arcs* alist; + char *str; + + /* Here is how the pn objects are created */ + + /* The following creates a pn of 5 places, 6 transitions, incidence + matrix Dp, and initial marking mp */ + pn_p = createpn("pnum tnum D m0", 5, 6, Dp, mp); + + /* Here the input and output matrices are used to initialize the pn */ + pn_s = createpn("pnum tnum I O m0", 4, 4, Is, Os, ms); + + /* This creates a pn object without transition arcs */ + pn = createpn("pnum tnum", 3, 5); + + /* GetMatrixEl and SetMatrixEl can be used to read or write the elements + of a matrix. */ + + /* For instance, arcs could be added by changing the value of the input + and output matrices of the pn */ + + SetMatrixEl(&pn.out, 0, 2, 1); /* add arc from p0 to t2 of weight 1 */ + SetMatrixEl(&pn.out, 0, 4, 1); /* add arc from p0 to t4 of weight 1 */ + SetMatrixEl(&pn.out, 2, 4, 1); /* add arc from p2 to t4 of weight 1 */ + SetMatrixEl(&pn.in, 1, 3, 1); /* add arc from t3 to p1 of weight 1 */ + SetMatrixEl(&pn.in, 1, 0, 2); /* add arc from t0 to p1 of weight 2 */ + + /* For instance, to check whether there is an arc from t1 to p2: */ + i = GetMatrixEl(&pn.in, 2, 1); + if(i) + fprintf(stderr, "\nThe arc (t1, p2) has the weight %d.\n", i); + else + fprintf(stderr, "\nThere is no arc from t1 to p2.\n"); + + /* To display in text format a Petri net object use displaypn */ + + fprintf(stderr, "\n** PN_P *************************************\n"); + displaypn(pn_p, stderr); /* displays pn_p */ + fprintf(stderr, "\n** PN_S *************************************\n"); + displaypn(pn_s, stderr); /* displays pn_s */ + fprintf(stderr, "\n** PN *************************************\n"); + displaypn(pn, stderr); /* displays pn */ + + /* Properties of the pn objects can be set or changed with updatepn */ + + updatepn(&pn, "place_name", 0, "start_p"); + /* The line above associates the name "start_p" with the place 0 */ + + updatepn(&pn, "trans_name", 0, "tr0"); + /* The line above associates the name "tr0" with the transition 0 */ + + updatepn(&pn, "select", 1, "f1"); /*select function 'f1' for place 1*/ + + updatepn(&pn, "segment", 0, "i++;");/*code segment 'i++' for place 0*/ + + /* Text transmitted by means of createpn/updatepn is copied to the + corresponding items of the pns object; thus it should be + deallocated, when applicable. For instance: */ + + str = tcalloc(strlen("f1(i, j);")+1, sizeof(char)); + strcpy(str, "f1(i, j);"); + updatepn(&pn, "segment", 1, str); + /* Now, str may be freed, since its content has been copied */ + free(str); + + /* Flags are set as follows. */ + + updatepn(&pn, "unobservable nondeterministic", 0, 1); + /* marks transition 0 unobservable and place 1 as nondeterministic */ + + updatepn(&pn, "live uncontrollable uncontrollable", 0, 0, 2); + /* The line above sets the "live" and "uncontrollable" flags of + transition 0 and the uncontrollable flag of transition 2 */ + + /* Arcs are added similarly (using createpn or updatepn). Here is + an example. */ + + plist = tmalloc(sizeof(struct placelist)); + plist->place = 1; + plist->next = tmalloc(sizeof(*plist)); + plist->next->place = 2; + plist->next->next = 0; + + alist = tmalloc(sizeof(arcs)); + alist->in_place = 0; + alist->out_places = plist; + alist->condition = tcalloc(strlen("j == i || z == 0.1")+1, sizeof(char)); + strcpy(alist->condition, "j == i || z == 0.1"); + alist->next = 0; + + updatepn(&pn, "arcs", 0, alist); /* arc list associated with transition 0 */ + + /* The line above updates the arc_list item of the pns object as well as the + input & output matrices. */ + + /* Note the absence of the lines of code deallocating alist. The object alist is + placed in the pns object, it is not copied. Thus, alist is deallocated when + the pns object is deallocated with the function deallocpn. */ + + /* To create a copy */ + + pn2 = copypn(&pn); + + /* To deallocate a pn object use deallocpn */ + + deallocpn(&pn_p); + deallocpn(&pn_s); + deallocpn(&pn); + deallocpn(&pn2); + + return 0; +} Added: pnheaders/pns.c =================================================================== --- pnheaders/pns.c (rev 0) +++ pnheaders/pns.c 2011-04-02 00:10:24 UTC (rev 245) @@ -0,0 +1,1760 @@ +/**************************************************************************** +PNS.C +Written in 2008-2010 by M. V. Iordache. +****************************************************************************/ + +#include"pns.h" + + +void d2dd(const matrix* D, matrix* Dm, matrix* Dp) { + int i, j, nr, nc; + mtype x; + + nr = NumberOfRows(*D); + nc = NumberOfColumns(*D); + + if(!D || !Dm || !Dp) { + merror(0, "D2DD: one of the parameters has zero address."); + return; + } + + if(nc <= 0 || nr <= 0) { + merror(0, "D2DD: Wrong dimensions of D: %d x %d", D->nr, D->nc); + return; + } + + if((nr != NumberOfRows(*Dm)) || (nc != NumberOfColumns(*Dm)) || \ + (nr != NumberOfRows(*Dp)) || (nc != NumberOfColumns(*Dp))) { + merror(0, "D2DD: One or more parameters have wrong dimensions"); + return; + } + for(i = 0; i < nr; i++) + for(j = 0; j < nc; j++) { + x = GetMatrixEl(D, i, j); + if(x < 0) + SetMatrixEl(Dm, i, j, -x); + else if(x > 0) + SetMatrixEl(Dp, i, j, x); + } +} + + +pns getpn(matrix* Dm, matrix* Dp, int* Tuc, int* Tuo, int* m0, int* C) { + + matrix mDm, mDp; + pns pn; + + if(!Dm && !Dp) { + merror(0, "GETPN: Both Dm and Dn are zero."); return pn; + } + + if(!Dp) { /* In SPNBOX it is possible to call getpn(D) */ + d2dd(Dm, &mDm, &mDp); + pn = createpn("mDm mDp Tuc Tuo m0 C", mDm, mDp, Tuc, Tuo, m0, C); + DeallocateMatrix(&mDm); + DeallocateMatrix(&mDp); + } + else + return createpn("mDm mDp Tuc Tuo m0 C", Dm, Dp, Tuc, Tuo, m0, C); + + return pn; +} + +void _updatepn(pns* pn, const char *str, va_list param); + + +pns createpn(const char *str, ...) { + pns pn; + va_list param; + char* s; + char opt[] = "zero "; /* to set first the pn to zero */ + + s = tmalloc((1+strlen(str)+strlen(opt))*sizeof(char)); + strcpy(s, opt); + strcat(s, str); + + /* Do the initializations */ + + va_start(param, str); + _updatepn(&pn, s, param); + va_end(param); + + free(s); + + return pn; +} + + +void updatepn(pns* pn, const char *str, ...) { + va_list param; + + va_start(param, str); + _updatepn(pn, str, param); + va_end(param); +} + + +/* Subroutines of _updatepn */ + +void inline allocate_matrices(pns* pn) { + if(!(pn->pnum) || !(pn->tnum)) + return; + if(pn->in.nr !=pn->pnum || pn->in.nc !=pn->tnum)/*if not already allocated*/ + AllocateMatrixType(3, &(pn->in), pn->pnum, pn->tnum); + if(pn->out.nr != pn->pnum || pn->out.nc != pn->tnum) + AllocateMatrixType(3, &(pn->out), pn->pnum, pn->tnum); +} + +void ptNumCheck(pns *pn, int m, int n) { + if(m < 0) + merror(0, "_UPDATEPN: Request for %d places!", m); + if(n < 0) + merror(0, "_UPDATEPN: Request for %d places!", n); + if(!pn->pnum && !pn->tnum) { /* If the pn has not been yet initialized */ + pn->pnum = m; + pn->tnum = n; + allocate_matrices(pn); + } + else { + if (pn->pnum != m) + merror(0, "_UPDATEPN: Request to change from %d to %d the number of places", pn->pnum, m); + if (pn->tnum != n) + merror(0, "_UPDATEPN: Request to change from %d to %d the number of transitions", pn->tnum, n); + } +} + + +void pCheck(pns *pn, char* s) { + int i,j; + char *p; + if(!pn->pnum) { + merror(0,"SETPN: Parameter '%s' requires at least one place",s); + return; + } + if(!pn->p) { /* Allocate t if not already allocated */ + pn->p = tmalloc(sizeof(PlaceInfo)*pn->pnum); + for(i = 0; i < pn->pnum; i++) { + p = (char*)&(pn->p[i]); + for(j = 0; j <= sizeof(PlaceInfo)-sizeof(char); j++) + *(p+j) = 0; + } + } +} + + +void tCheck(pns *pn, char* s) { + int i,j; + char *p; + if(!pn->tnum) { + merror(0,"SETPN: Parameter '%s' requires at least one transition",s); + return; + } + if(!pn->t) { /* Allocate t if not already allocated */ + pn->t = tmalloc(sizeof(TransInfo)*pn->tnum); + for(i = 0; i < pn->tnum; i++) { + p = (char*)&(pn->t[i]); + for(j = 0; j <= sizeof(TransInfo)-sizeof(char); j++) + *(p+j) = 0; + } + } +} + +void dealloc_arcs(arcs *pa) { + arcs *p, *p2; + struct placelist *pl, *pl2; + + if(!pa) + return; + for(p = pa; p; ) { + if(p->condition) + free(p->condition); + for(pl = p->out_places; pl; ) { + pl2 = pl; + pl = pl->next; + free(pl2); + } + p2 = p; + p = p->next; + free(p2); + } +} + +void inclArcs(pns* pn, int t, arcs* p_arc) { + arcs* pa, *p, *padst; + struct placelist* pl; + int i; + + if(!p_arc) { /* Remove all transition arcs of t */ + if(pn->arc_list) + if(pn->arc_list[t]) { + dealloc_arcs(pn->arc_list[t]); + pn->arc_list[t] = 0; + } + MakeZeroColumn(&(pn->out), t); + MakeZeroColumn(&(pn->in), t); + return; + } + if(!pn->arc_list) + pn->arc_list = tcalloc(pn->tnum, sizeof(pn->arc_list[0])); + + /* Next, place arcs in arc_list and update the input & output matrices. */ + + /* The following loop places the arcs in increasing order of the in_place field. */ + + for(pa = p_arc; pa; ) { + if(!pn->arc_list[t]) { + pn->arc_list[t] = pa; + pa = pa->next; + pn->arc_list[t]->next = 0; + continue; + } + if(pa->in_place <= pn->arc_list[t]->in_place) { /* insert at the beginning */ + p = pn->arc_list[t]; + pn->arc_list[t] = pa; + pa = pa->next; + pn->arc_list[t]->next = p; + continue; + } + for(padst = pn->arc_list[t]; padst; padst = padst->next) { + if(padst->next) + if(pa->in_place > padst->next->in_place) + continue; + p = padst->next; /* the line is reached if padst->next == 0 or + pa->in_place <= padst->next->in_place */ + padst->next = pa; + pa = pa->next; + padst->next->next = p; + break; + } + } + + /* Update the input and output matrices */ + + MakeZeroColumn(&(pn->out), t); + MakeZeroColumn(&(pn->in), t); + for(pa = pn->arc_list[t]; pa; pa = pa->next) { + if(pa->in_place >= 0) { /* write to the output matrix */ + i = 1 + GetMatrixEl(&(pn->out), pa->in_place, t); + SetMatrixEl(&(pn->out), pa->in_place, t, i); + } + for(pl = pa->out_places; pl; pl = pl->next) { /* write to the input matrix */ + i = 1 + GetMatrixEl(&(pn->in), pl->place, t); + SetMatrixEl(&(pn->in), pl->place, t, i); + } + } +} + + +void inclString(char*** pstr, int index, char* p, int num) { + if(!num || index >= num || index < 0) + merror(0, "SETPN: Attempt to describe undefined places or transitions"); + if(!*pstr) + *pstr = tcalloc(num, sizeof(**pstr)); + if((*pstr)[index]) { + free((*pstr)[index]); + (*pstr)[index] = 0; + } + if(!p) + p = ""; + if(!strlen(p)) + return; + (*pstr)[index] = tcalloc(strlen(p)+1, sizeof(*p)); + strcpy((*pstr)[index], p); +} + + +void _updatepn(pns* pn, const char *str, va_list param) { + arcs* p_arc; + char *sdest, *p; + int i, count, m, n, **ar, *ip, m0, n0; + matrix d, dm, dp; + + m0 = pn->pnum; + n0 = pn->tnum; + + if(!pn || !str) { + merror(0, "SETPN: First two parameters must be nonzero."); + return; + } + + sdest = tmalloc(sizeof(char)*(strlen(str)+1)); + + for(count = 0; str[count]; count++) { + if(str[count] == ' ' || str[count] == '\t') + continue; + + if(sscanf(str+count, "%s", sdest) < 0) { + merror(0, "SETPN could not scan this input: \"%s\".", str); return; } + + /* Advance count to the next field */ + count++; + for(; str[count] != ' ' && str[count] != '\t' && str[count]; count++); + count--; + + if(!strcmp(sdest,"arcs") || !strcmp(sdest,"arc")) { + i = va_arg(param, int); + p_arc = va_arg(param, arcs*); + inclArcs(pn, i, p_arc); + } + else if(!strcmp(sdest,"D") || !strcmp(sdest,"pD")) { + if(!pn->pnum || !pn->tnum) { + merror(0,"SETPN: The D parameter applies to PNs with at least one place and one transition!"); return; + } + if(!strcmp(sdest,"pD")) { + ar = va_arg(param, int**); + if(!ar) { + merror(0,"SETPN: The option pD = 0 is not implemented"); return; + } + d = array2matrix(ar, pn->pnum, pn->tnum); + } + else { /* the case "D" */ + ip = va_arg(param, int*); + if(!ip) { + merror(0,"SETPN: The option D = 0 is not implemented"); return; + } + d = vector2matrix(ip, pn->pnum, pn->tnum); + } + d2dd(&d, &(pn->out), &(pn->in)); + DeallocateMatrix(&d); + } + else if(!strcmp(sdest,"Dm")|| !strcmp(sdest,"O")|| !strcmp(sdest,"pDm")) { + if(!pn->pnum || !pn->tnum) { + merror(0,"SETPN: The Dm parameter applies to PNs with at least one place and one transition!"); return; + } + if(!strcmp(sdest,"pDm")) { + ar = va_arg(param, int**); + if(!ar) { + merror(0,"SETPN: The option pDm = 0 is not implemented"); return; + } + dm = array2matrix(ar, pn->pnum, pn->tnum); + } + else { + ip = va_arg(param, int*); + if(!ip) { + merror(0,"SETPN: The option Dm = 0 is not implemented"); return; + } + dm = vector2matrix(ip, pn->pnum, pn->tnum); + } + CopyMatrix(&dm, &(pn->out)); + DeallocateMatrix(&dm); + } + else if(!strcmp(sdest,"Dp")|| !strcmp(sdest,"I")|| !strcmp(sdest,"pDp")) { + if(!pn->pnum || !pn->tnum) { + merror(0,"SETPN: The Dp parameter applies to PNs with at least one place and one transition!"); return; + } + if(!strcmp(sdest,"pDp")) { + ar = va_arg(param, int**); + if(!ar) { + merror(0,"SETPN: The option pDp = 0 is not implemented"); return; + } + dp = array2matrix(ar, pn->pnum, pn->tnum); + } + else { + ip = va_arg(param, int*); + if(!ip) { + merror(0,"SETPN: The option Dp = 0 is not implemented"); return; + } + dp = vector2matrix(ip, pn->pnum, pn->tnum); + } + CopyMatrix(&dp, &(pn->in)); + DeallocateMatrix(&dp); + } + else if(!strcmp(sdest,"mD")) { + d = va_arg(param, matrix); + m = NumberOfRows(d); + n = NumberOfColumns(d); + ptNumCheck(pn, m, n); /*If uninitialized, pnum and tnum become m and n.*/ + /* If m and n are nonzero, pn->in,out are allocated if necessary.*/ + d2dd(&d, &(pn->out), &(pn->in)); + } + else if(!strcmp(sdest,"mDm")) { + d = va_arg(param, matrix); + m = NumberOfRows(d); + n = NumberOfColumns(d); + ptNumCheck(pn, m, n); /*If uninitialized, pnum and tnum become m and n*/ + ... [truncated message content] |
From: <mio...@us...> - 2011-04-02 00:08:41
|
Revision: 244 http://pntool.svn.sourceforge.net/pntool/?rev=244&view=rev Author: miordache Date: 2011-04-02 00:08:32 +0000 (Sat, 02 Apr 2011) Log Message: ----------- 2011 update--first part Modified Paths: -------------- Makefile spnbox/spnbox.h spnbox/tests/Makefile spnbox/tests/StructuredIO.c translator/pngenerator.c translator/pngenerator.g Added Paths: ----------- Makefile09 newcodegen/ newcodegen/Makefile newcodegen/ProcessTemplate.c newcodegen/SupervisorTemplate.c newcodegen/codegen.h newcodegen/compexample.c newcodegen/filltmpl.lex newcodegen/plantCompiler.c newcodegen/plantCompiler.h newcodegen/spcommon.h newcodegen/supervisorCompiler.c pnheaders09/ spnbox/disj2normal.c spnbox/disj2pn.c spnbox/disq2disj.c spnbox/tests/test-lindisj.c spnbox/tests/test-lindisj.txt spnbox/tests/test-lindisq.c spnbox/tests/test-lindisq.txt spnbox/tests/test-lintree.c spnbox/tests/test-lintree.txt spnbox/tests/test-superdis.c spnbox/tree2spec.c Removed Paths: ------------- README.txt pnheaders/ Modified: Makefile =================================================================== --- Makefile 2009-08-23 07:45:43 UTC (rev 243) +++ Makefile 2011-04-02 00:08:32 UTC (rev 244) @@ -7,7 +7,6 @@ # the object code. # # 2) Place all relevant object files and libraries in the same directory. -# Codegen note: makefile is in codegen/, however .o files are codegen/src/*.o # 3) Place no other object files in that directory (or else please make # appropriate changes below). # @@ -23,30 +22,33 @@ PNHEADERS=pnheaders SPNBOX=spnbox -CODEGEN=codegen -CODEGENOBJS = codegen/src +CODEGEN=newcodegen +CODEGENOBJS = $(CODEGEN)/obj TRANSLATOR=translator ct: objectfiles main_function.o $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ main_function.o $(SPNBOX)/*.a $(TRANSLATOR)/libtranslator.a + cp ct.exe .. + objectfiles: cd $(PNHEADERS); make cd $(CODEGEN); make static cd $(SPNBOX); make cd $(TRANSLATOR); make -main_function.o: $(PNHEADERS)/main_function.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/src/codegen.h +main_function.o: $(PNHEADERS)/main_function.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/codegen.h $(COMPILER) -c $(PNHEADERS)/main_function.c -Ispnbox -I$(CODEGEN)/src -I$(PNHEADERS) clean: rm -f main_function.o rm -f ct cd $(PNHEADERS); make clean - cd codegen; make clean + cd $(CODEGEN); make clean cd $(TRANSLATOR); make clean cd $(SPNBOX); make clean distclean: clean - cd codegen; make distclean - cd $(TRANSLATOR); make distclean \ No newline at end of file + cd $(CODEGEN); make distclean + cd $(TRANSLATOR); make distclean + Added: Makefile09 =================================================================== --- Makefile09 (rev 0) +++ Makefile09 2011-04-02 00:08:32 UTC (rev 244) @@ -0,0 +1,54 @@ +# This is the make file of the 2009 version of the program. +# +# Modify it so that the files you contribute are properly included. +# I propose the following format (but you may change it if necessary). +# +# 1) Create a local make file in your directory. It should generate +# the object code. +# +# 2) Place all relevant object files and libraries in the same directory. +# Codegen note: makefile is in codegen/, however .o files are codegen/src/*.o +# 3) Place no other object files in that directory (or else please make +# appropriate changes below). +# +# Please make sure all commands can be run in Linux! +# +# Changelog: +# 6/26/09 SC: Changed ct instruction to include static library files +#(.a) from the spnbox directories. This is necessary to link the lpsolve library. +# +# If you make changes to this format, please document them above. + +COMPILER=gcc -g + +PNHEADERS=pnheaders09 +SPNBOX=spnbox +CODEGEN=codegen +CODEGENOBJS = codegen/src +TRANSLATOR=translator + +ct: objectfiles main_function.o + $(COMPILER) -o ct $(PNHEADERS)/*.o $(CODEGENOBJS)/*.o $(SPNBOX)/*.o \ + main_function.o $(SPNBOX)/*.a $(TRANSLATOR)/libtranslator.a + cp ct.exe .. + +objectfiles: + cd $(PNHEADERS); make + cd $(CODEGEN); make static + cd $(SPNBOX); make + cd $(TRANSLATOR); make + +main_function.o: $(PNHEADERS)/main_function.c $(PNHEADERS)/pns.h $(SPNBOX)/spnbox.h $(CODEGEN)/src/codegen.h + $(COMPILER) -c $(PNHEADERS)/main_function.c -Ispnbox -I$(CODEGEN)/src -I$(PNHEADERS) + +clean: + rm -f main_function.o + rm -f ct + cd $(PNHEADERS); make clean + cd codegen; make clean + cd $(TRANSLATOR); make clean + cd $(SPNBOX); make clean + +distclean: clean + cd codegen; make distclean + cd $(TRANSLATOR); make distclean Deleted: README.txt =================================================================== --- README.txt 2009-08-23 07:45:43 UTC (rev 243) +++ README.txt 2011-04-02 00:08:32 UTC (rev 244) @@ -1,20 +0,0 @@ -You're looking at the SOURCE CODE REPOSITORY for pntool - -Drew Crawford administrates this repo. If you need help, send me an e-mail: dr...@se... - -Here's the directory structure: - -codegen - these files are maintained by Drew Crawford and Kris Eggert. - This will become the code generating portion of the petri net. - -pnheaders - these files are maintained by Dr. Iordache. They provide functions - for the manipulation of PN objects. - -spnbox - this code performs the supervisory control. Maintained by - Stephen Camp. Uses LPSOLVE as the MILP solver. LPSOLVE is - distributed under the LGPL licence. - -translator - this code takes a high-level-language spec and turns it into a pns datastructure. Maintained by Bion Oren. Uses ANTLR - (third-party/ANTLR3_ctarget_x_x_x/). ANTLR is distributed under the BSD license. - -Feel free to add more directories! Track your code in here! Added: newcodegen/Makefile =================================================================== --- newcodegen/Makefile (rev 0) +++ newcodegen/Makefile 2011-04-02 00:08:32 UTC (rev 244) @@ -0,0 +1,25 @@ +COMPILER=gcc -g +PNDIR=../pnheaders/ + +comp: plantCompiler.o compexample.o filltmpl.fl.o supervisorCompiler.o + make -f pnexample.mak -C$(PNDIR) + $(COMPILER) -o compexample plantCompiler.o compexample.o filltmpl.fl.o $(PNDIR)matrix.o $(PNDIR)general.o $(PNDIR)pns.o $(PNDIR)insert.o supervisorCompiler.o + +static: plantCompiler.o filltmpl.fl.o supervisorCompiler.o + cp plantCompiler.o filltmpl.fl.o supervisorCompiler.o obj/ + +compexample.o: compexample.c *.h $(PNDIR)*.h + $(COMPILER) -c -I$(PNDIR) compexample.c + +plantCompiler.o: plantCompiler.c *.h $(PNDIR)*.h + $(COMPILER) -c -I$(PNDIR) plantCompiler.c + +supervisorCompiler.o: supervisorCompiler.c *.h $(PNDIR)*.h + $(COMPILER) -c -I$(PNDIR) supervisorCompiler.c + +filltmpl.fl.o: filltmpl.lex + flex -Pfl -ofilltmpl.fl.c filltmpl.lex + $(COMPILER) -c filltmpl.fl.c + +clean: + rm *.o obj/*.o || true \ No newline at end of file Added: newcodegen/ProcessTemplate.c =================================================================== --- newcodegen/ProcessTemplate.c (rev 0) +++ newcodegen/ProcessTemplate.c 2011-04-02 00:08:32 UTC (rev 244) @@ -0,0 +1,212 @@ + +#include<stdarg.h> +#include<stdio.h> +#include<stdlib.h> +#include<time.h> +#include<string.h> +#include<pthread.h> +#include<limits.h> +#include<sys/types.h> + +#ifdef ___PROCESS +int ___debug = 0; // value determined by parameters of main function +#else +extern int ___debug; // corresponds to variable of supervisor +#endif + +#include"spcommon.h" + +static void* ___main_function(void* ___v); + +// +++++++ OTHER DECLARATIONS (GENERATED CODE HERE) + + +#ifndef ___NTR + +// Here are some default definitions allowing to compile the file without +// automatically generated code. This is for debugging purposes. + +#define ___NTR 1 // ___NTR defined in the automatically generated code +// TR represents a list of transitions and NTR its max size. +static const char ___TRinfo[10]; + +#endif + +static void* ___main_function(void* ___v) { + int ___i, ___j, ___flag, ___ntran; + time_t ___ctime; + char* ___str; + struct ___thread_data *___pthr = ___v; + struct ___trans ___TR[___NTR]; + + void *p___ = 0; // Reserved for user code. Useful when there are + // several thread copies running in parallel. + // Each thread can allocate memory and associate p___ to the + // address, if needed. + // At the end of the program p___ should be deallocated if nonzero!!! + + int ___place; // denotes the value of the current place + int ___finish; // the program terminates when its value is nonzero + + ___finish = 0; + ___flag = 0; + ___place = ___pthr->state; + + // !!! To define communication parameters ... + + time(&___ctime);//___ctime used to initialize the random number generator + // Next, ___ctime is modified so that different processes started at the + // same time do not have the same ___ctime. + // The random number generator of the threads is initialized by supervisor. +#ifndef ___THREAD + ___ctime += (int) getpid(); +#else + ___ctime += (int) getpid() + (int)___pthr->id; +#endif + srand(___ctime%64000); + + while(!___finish) { + switch(___place) { + + // +++++++ case list (GENERATED CODE HERE) + + default: + // display error message for undefined place + debugInfo("Internal ERROR: the place %d is undefined", ___place); + ___finish = 1; + } // ends main switch block + + if(___finish) + break; // exit main while loop + + //debugInfo("Calling ___NextState"); + ___place = ___NextState(___TR, ___TRinfo, ___place, ___i, &___finish, ___pthr, debugInfo); + // at this point ___i = no of elements of ___TR + //debugInfo("Going to place %d", ___place); // place = -1 when terminating + + } // ends main while loop + + ___send_exit_notification(___pthr); + + debugInfo("The end of the main function was reached"); + + return 0; +} + + +#ifndef ___THREAD + + +void ___print_args(int argc, char* argv[], struct ___thread_data *___pthr, struct ___thread_comm *___pc) { + int ___i, ___j; + char *___str, *___s1 = 0, *___s2 = 0, *___s3 = 0, *___s4 = 0; + + if(___debug) { + if(argc <= 1) + asprintf(&___s1, "The main function was entered. The main function has no parameters."); // This line should not be reached! + else { + for(___i = 0, ___j = 0; ___i < argc; ___i++) + ___j += strlen(argv[___i]); + ___j += argc + 1; + ___str = malloc(___j*sizeof(char)); + for(___i = 0, ___j = 0; ___i < argc - 1; ___i++) { + sprintf(___str + ___j, "%s ", argv[___i]); + ___j += strlen(argv[___i]) + 1; + } + sprintf(___str + ___j, "%s", argv[___i]); + asprintf(&___s1, "The process was started with the following command line\n\t%s", ___str); + free(___str); + } + if(___pthr || ___pc) { + asprintf(&___s2, "\nThe following parameters were received:\n"); + if(___pthr) + asprintf(&___s3, "id = %d debug = %d initial state = %d", (int)___pthr->id, (int)___pthr->debug, (int)___pthr->state); + if(___pc) + asprintf(&___s4, " write end = %d", (int)___pc->pwrite); + } + if(!___s2) asprintf(&___s2, " "); + if(!___s3) asprintf(&___s3, " "); + if(!___s4) asprintf(&___s4, " "); + } + debugInfo("%s%s%s%s", ___s1, ___s2, ___s3, ___s4); + free(___s1); free(___s2); free(___s3); free(___s4); +} + + +#define ___RETURN_IF_ERROR_1(___f, ___string) \ + if(!___f) { \ + ___print_args(argc, argv, ___pthr, ___pc);\ + debugInfo(___string); \ + free(___pthr); free(___pc); \ + return 1; \ + } + +#define ___RETURN_IF_ERROR_2(___f, ___string) \ + if(!___f) { \ + ___print_args(argc, argv, ___pthr, ___pc);\ + debugInfo(___string); \ + close(___pc->pread); close(___pc->pwrite); \ + ___send_exit_notification(___pthr); \ + free(___pthr); free(___pc); \ + return 1; \ + } + + +int main(int argc, char* argv[]) { + + // Update to read from pipe parameters! See ___upd_comm_param + + int ___i, ___j, ___flag = 0, ___vplace; + char* ___str; + struct ___thread_data *___pthr = 0; + struct ___thread_comm *___pc = 0; + + ___debug = 1; // allow messages if errors occur at the beginning + + ___pthr = calloc(1, sizeof(*___pthr)); + if(!___pthr) { + debugInfo("Could not allocate 'struct ___thread_data' object"); + return 1; + } + ___pc = calloc(1, sizeof(*___pc)); + if(!___pc) { + free(___pthr); + debugInfo("Could not allocate 'struct ___thread_comm' object"); + return 1; + } + + ___flag = (argc > 1); + if(___flag) + ___pc->pread = atoi(argv[1]); + // Command line parameter from get_process_comm_data in SupervisorTemplate + + ___RETURN_IF_ERROR_1(___flag, "The process exits since no command line parameter is given.\n"); + + // READ PARAMETERS FROM PIPE + + ___j = ___get_msg(___pc->pread, &___pc->pwrite, sizeof(___pc->pwrite), debugInfo); + ___RETURN_IF_ERROR_1(___j, "The process exits since 'pwrite' cannot be read from pipe.\n"); + ___j = ___get_msg(___pc->pread, &___pthr->id, sizeof(___pthr->id), debugInfo); + ___RETURN_IF_ERROR_1(___j, "The process exits since process id cannot be read from pipe.\n"); + ___j = ___get_msg(___pc->pread, &___pthr->debug, sizeof(___pthr->debug), debugInfo); + ___RETURN_IF_ERROR_2(___j, "The process exits since 'debug' cannot be read from pipe.\n"); + ___j = ___get_msg(___pc->pread, &___pthr->state, sizeof(___pthr->state), debugInfo); + ___RETURN_IF_ERROR_2(___j, "The process exits since the initial state cannot be read from pipe.\n"); + + ___pthr->comm = ___pc; + ___debug = ___pthr->debug; + + + ___print_args(argc, argv, ___pthr, ___pc); + + ___main_function(___pthr); + + debugInfo("The process is terminating.\n"); + + free(___pthr); + free(___pc); + + return 0; +} + +#endif Added: newcodegen/SupervisorTemplate.c =================================================================== --- newcodegen/SupervisorTemplate.c (rev 0) +++ newcodegen/SupervisorTemplate.c 2011-04-02 00:08:32 UTC (rev 244) @@ -0,0 +1,1096 @@ +// TO DO: check pipe size and adjust it if necessary or terminate if impossible +// enable SIGPIPE for sread pipe of supervisor. +// use fcntl for both +// The plant must use fcntl so that its write is not blocked! +// Plant: Blocking read, nonblocking write! +// +// Note: read() from pipe with O_NOBLOCK set returns 0 if the sender has closed +// its end of the pipe or -1 and errno = EAGAIN if the pipe is empty. +// +// check_for_msg()/get_msg() accounts for the possibility that read() may return less bytes +// than expected. However, some testing might be needed to ensure that the way +// check_for_msg()/get_msg() deals with this error is adequate. +// If this is not the case, some functions could be created to read and write +// bytes one by one. Then, struct proc would have two additional items: one buffer +// to hold the bytes of a message that is being received, which is filled with bytes +// of data as they arrive, and one integer indicating how many bytes are in the +// buffer. +// +// The plant should send a notification message to the supervisor when terminating. +// +// The debugInfo of the supervisor should use a lock. + +#define ___SUPERVISOR + +#include<stdarg.h> +#include<stdio.h> +#include<stdlib.h> +#include<time.h> +#include<string.h> +#include<pthread.h> +#include<unistd.h> +#include<fcntl.h> +#include<signal.h> + +#define MSG_READ_LIMIT 10 +// max number of messages read from a single process during an iteration + +char ___debug; // value determined by parameters of main function +int ___finish; // the program terminates when its value is nonzero +pid_t ___pid; +pthread_t ___tid; +FILE* ___f; +char* ___name; + +#include"spcommon.h" + +// The following is used for unnamed pipe communication between plant +// and supervisor. + +struct ___comm { + int sread, swrite; + int pread, pwrite; + char pclosed; // nonzero if pread and pwrite pipes have been closed +}; + +// The following is used in the command line when a process is started. +// The size should be updated if the communication approach is changed. +// A size of (4*sizeof(int)+1) is sufficient to represent one signed +// int-type number in text form. + +char ___com[4*sizeof(int)+1]; + +// The following is used to store transition lists in "struct proc" + +struct trlist { + int t; // transition number + int a; // action label of plant transition + //char type; // 0: if input transition, 1: if output transition +}; + +// When a plant process is created, an object of type "struct proc" +// is created. The address of this object is transmitted to the process and +// this address is included in all messages from the process to the supervisor. +// These objects are placed in three lists, as follows: +// - prlist is the list of all processes started by the supervisor. +// - wtlist[i] is a list of processes of the type i that wait for the supervisor. +// - queue is a queue list of all processes that wait for the supervisor. + +struct proc { + int type; // identifies the type of the process + int request; // id of last request (not notification!) made by the proc to the supervisor + int solved; // id of last resolved request (so solved == request when all + // requests of the process have been answered). + char atype; // the action type (permission request or firing notification) + // bit 0: 0 -- permission, 1 -- notification + // bit 1: 1 -- if part of qelist (QueueEntryList of IsPermissible) + int fireable; // the plant transition selected by the supervisor algorithms + int ntlist; // number of elements of the list below + struct trlist *tlist; // list of firable plant transitions + // All entries below must be ZERO when not used + struct proc *next_in_queue; // next element of lower priority + struct proc *prev_in_queue; // next element of higher priority + struct proc *next_in_prlist; // next element in the list of processes + struct proc *prev_in_prlist; // previous element + struct proc *next_in_wtlist; // next element in the list of processes of the + // same type that wait for a supervisor action + struct proc *prev_in_wtlist; + struct proc *next_in_qelist; + + pthread_t thread_id; // id of thread + pid_t pid; // id of forked process + + void* comm; // pointer to an unspecified communication structure, such as + // struct ___comm. +}; + +struct proc *___prlist; // pointer to the first element of the list +// wtlist is defined automatically as "struct proc *___wtlist[n];" +// wtlistLast[n] (pointer to last element of wtlist[n]) is defined the same way. + +struct proc *___first, *___last; // Queue pointers + +// When a process sends a message requesting action i, the supervisor +// examines the data associated with the action i. This data consists of +// process types that are involved in firing the transition and of supervisor +// transitions that are involved. This data is stored in 'struct ___action' +// objects (the structure is defined below). Note that a transition is fired +// if all process type requirements are met and one of the supervisor +// transitions in the list is enabled. + +// Conditions are expressed by process type lists and transition lists. +// There are npr process types: type[i] denotes the type of process i and +// weight[i] denotes the weight of the transition of process i that is part +// of the synchronization. +// There are ntr supevisor transitions having the same label as the plant +// transitions participating in the synchronization. Their indices are +// in the array t. + +// The structure allows expressing constraints in which a synchronization may +// involve either t (non-source) or t' (source tran), where t and t' belong to +// the same process. This situation may arise when t and t' have the same label. +// This is done by means of the 'disj' field. If disj[i] != 0, then one of +// the transitions itr[i] should be chosen OR one of the transitions corresp to +// oplace[disj[i]-1]. + +struct ___action { + const int ni; + const int *itype; // input proc. type, array of size ni + const int *nit; // array of size ni + const int *disj; // array of size ni; see the disj field of struct sync_element + const int **itr; // array of size ni x nit[i] for transitions + const int **iweight; // array of size ni x nit[i] + + const int no; + const int *otype; // output proc. type, array of size no + const int *not; // array of size no + const int **oweight; // array of size no x not[i] + const int **oplace; // array of size no x not[i] + // (place in which proc is started) + const int ntr; + const int *t; // array of size ntr +}; + + +// The PN structure of the supervisor is represented using the following +// structure. Each transition 0, 1, ..., n has an object of this type. + +struct ___PN { + const int nipl; // number of input places + const int *iplace; // vector of nipl elements + const int *iweight; // vector of nipl elements + + const int nopl; // number of output places + const int *oplace; // vector of nopl elements + const int *oweight; // vector of nopl elements +}; + + +// +++++++ OTHER DECLARATIONS (GENERATED CODE HERE) + +// default values included below for debugging puroposes +#ifndef n___prtypes +#define n___prtypes 1 +#endif + +struct proc *___prtype[n___prtypes]; + +int ___marking[___pnum]; // supervisor marking + + + +inline int ___is_enabled(int ___t) { // checks whether ___t is enabled + int ___i, ___nipl; + const int *___iplace, *___iweight; + const struct ___PN *___p; + + ___p = ___trans + ___t; + ___nipl = ___p->nipl; + ___iplace = ___p->iplace; + ___iweight = ___p->iweight; + + for(___i = 0; ___i < ___nipl; ___i++) + if(___marking[___iplace[___i]] < ___iweight[___i]) + break; + return (___i == ___nipl); +} + + +inline void ___fire(int ___t) { + // Fires __t without checking if it is enabled + + int ___i; + struct ___PN ___d = ___trans[___t]; + + for(___i = 0; ___i < ___d.nipl; ___i++) + ___marking[___d.iplace[___i]] -= ___d.iweight[___i]; + for(___i = 0; ___i < ___d.nopl; ___i++) + ___marking[___d.oplace[___i]] += ___d.oweight[___i]; +} + + +inline void ___fire_zltrans() { + // check 0 label transitions and fire them if enabled + + #ifdef ZERO_LABEL_TRANS + + for(___flag = 1; ___flag; ) { + ___flag = 0; + for(___i = 0; ___i < ZERO_LABEL_TRANS; ___i++) { + ___tr = ___zltrans[___i]; + if(___is_enabled(___tr)) { + ___fire(___tr); + ___flag = 1; + } + } + } + #endif +} + + +inline void ___fire_all(int ___t) { + // Fires __t without checking if it is enabled; fires also all zero label + // transitions that are enabled until none remains enabled. + + int ___i, ___flag, ___tr; + + ___fire(___t); + ___fire_zltrans(); +} + + +void ___UpdateSupervisorMarking(int ___a) { // ___a is the action number + + #ifdef ___ACTIONS + + const int *___ip = ___act[___a].t, ___n = ___act[___a].ntr; + int ___i; + + for(___i = 0; ___i < ___n; ___i++) + if(___is_enabled(___ip[___i])) { + ___fire_all(___ip[___i]); + break; + } + #endif +} + + +/* + +int find_weight(int ___prtype, int ___a, int ___t) { + // Returns zero if ___t has no input place. Otherwise, it + // returns the weight of the input arc of ___t. + + int ___i, ___j, ___w = 0; + struct ___action ___at = ___act[___a]; + + if(___at.ni) { + for(___i = 0; ___i < ___at.ni; ___i++) + if(___at.itype[___i] == ___prtype) + break; + if(___i < ___at.ni) { // that is, if ___prtype was found + for(___j = 0; ___j < ___at.nit[___i]; ___j++) + if(___t == ___at.itr[___i][___j]) { + ___w = ___at.iweight[___i][___j]; + break; + } + } + } + return ___w; +} + +*/ + + +void inline clear_qel_entries(struct proc* ___qel_last) { + // Clears from QueueEntryList all elements that follow ___qel_last + struct proc* ___pr, *___pr2; + for(___pr = ___qel_last->next_in_qelist; ___pr; ___pr = ___pr2) { + ___pr->atype -= (___pr->atype & 2); // clear bit 1 + ___pr2 = ___pr->next_in_qelist; + ___pr->next_in_qelist = 0; + } + ___qel_last->next_in_qelist = 0; +} + +struct proc* SearchQueue(int ___prtype, int ___t, int ___w, int ___cnt,\ + struct proc* ___qel_last) { + // The search is done for transitions 't' with *t!=0 corresponding to + // an action 'a' and to processes of type 'prtype'. 'w' is the weight + // of 't'. 'qel_last' denotes the last element of QueueEntryList. The + // function returns zero if nothing is found. Otherwise, it adds the + // appropriate processes to the QueueEntryList and returns the new + // last element of QueueEntryList. + + struct proc *___pr, *___qlast; + struct trlist* ___ptl; + int ___i, ___c = ___cnt; + + ___qlast = ___qel_last; + for(___pr = ___wtlist[___prtype]; ___pr; ___pr = ___pr->next_in_wtlist) { + if(___pr->atype & 2) // if entry in QueueEntryList + continue; + // Check if t is in the transition list + for(___ptl = ___pr->tlist, ___i = 0; ___i < ___pr->ntlist; ___i++) + if(___t == ___ptl[___i].t) + break; + if(___ptl) { // That is, if the transition was found + ___pr->fireable = ___t; + ___pr->atype |= 2; // set the bit 1 + ___qlast->next_in_qelist = ___pr; + ___qlast = ___pr; + ___c++; + if(___c >= ___w) + return ___qlast; + } + } + clear_qel_entries(___qel_last); // clear qel entries added by SearchQueue + return 0; +} + + +#ifdef ___MASK +inline void ___reset_mask(int ___n) { + int ___i; + for(___i = 0; ___i < ___n; ___i++) + ___mask[___i] = 0; +} +#endif + + +#ifdef ___ACTIONS // The following function called in the context of actions + +int IsPermissible(struct proc* ___q) { + // Checks whether the entry ___q of the queue has some transition that + // may be fired. It returns a nonzero number (action number + 1) if this + // is the case. + + int ___i, ___j, ___k, ___a, ___t, ___w; + int ___count, ___permissible, ___ptype, ___type; + char ___first; + struct ___action *___pa; + struct proc *___qel_last, *___q2; + + ___q->atype |= 2; // the instruction places {q} in QueueEntryList + ___ptype = ___q->type; + for(___i = 0; ___i < ___q->ntlist; ___i++) { + ___a = ___q->tlist[___i].a; + ___pa = ___act + ___a; // pa: pointer to the action element + + // Check whether any of the supervisor transitions associated with the + // action ___a is enabled. To execute ___a, at least one should be enabled. + + if(___pa->ntr) { // if there are sup. trans. associated with ___a + for(___j = 0; ___j < ___pa->ntr; ___j++) + if(___is_enabled(___pa->t[___j])) + break; // found one enabled supervisor transition + if(___j >= ___pa->ntr) + continue; // line reached if there are supervisor transitions + // associated with the action and none is enabled. + } + + // Note: For any correct supervisor, if the supervisor enables t + // it enables also all transitions with the same label as t. Thus, + // it is not necessary to check whether any other transition synchronized + // with t is supervisor enabled, since they have the same label. + + ___t = ___q->tlist[___i].t; + ___q->fireable = ___t; + ___qel_last = ___q; + ___permissible = 1; + #ifdef ___MASK + ___reset_mask(___pa->no); + #endif + for(___j = 0, ___first = 1; ___j < ___pa->ni; ___j++) { + // Note: pa->ni cannot be zero, because ___t cannot be a source + // transition (a plant will not request permission to fire one of its + // source transitions). Thus, ___t must be part of the input transition + // list of *___pa, so ni >= 1. + + ___type = ___pa->itype[___j]; + + // (a) Check first whether entry j of pa corresponds to t + // If yes, it is necessary to check the weight of t and whether enough + // many processes enable t. + + if(___first && ___ptype == ___type) { + for(___k = 0; ___k < ___pa->nit[___j]; ___k++) + if(___t == ___pa->itr[___j][___k]) + break; + if(___k < ___pa->nit[___j]) { // if the transition t was found + ___first = 0; + // If a non-source transition is chosen and source transitions are an + // alternative, an alternative source transition should not be fired + #ifdef ___MASK + ___w = ___pa->disj[___j]; + if(___w) // if source tran alternatives are present + ___mask[___w-1] = 1; // then mask (inhibit) them + #endif + ___w = ___pa->iweight[___j][___k]; + if(___w == 1) + continue; // continues with the next ___j + ___q2 = SearchQueue(___type, ___t, ___w, 1, ___qel_last); + if(___q2) { + ___qel_last = ___q2; + continue; // continues with the next ___j + } + ___permissible = 0; // line reached if t is unfirable + clear_qel_entries(___q); // clear QueueEntryList + break; // Go to next i, since t is unfirable + } // endif ___k < ... + } // endif ___first && ... + + // (b) Check whether some transition of entry j of pa is firable + + for(___k = 0; ___k < ___pa->nit[___j]; ___k++) { + ___w = ___pa->iweight[___j][___k]; + ___q2 = SearchQueue(___type, ___pa->itr[___j][___k], ___w, 0, ___qel_last); + if(___q2) { // if a firable entry was found + ___qel_last = ___q2; + // If a non-source transition is chosen and source transitions are an + // alternative, an alternative source transition should not be fired + #ifdef ___MASK + ___w = ___pa->disj[___j]; + if(___w) // if source tran alternatives are present + ___mask[___w-1] = 1; // then mask (inhibit) them + #endif + break; // Go to the next ___j + } + } // end for(___k ... + if(___k >= ___pa->nit[___j]) { // if no firable transition was found + if(___pa->disj[___j]) // if there are alternative source transitions + continue; // continue with the next ___j + clear_qel_entries(___q); //clear QueueEntryList; line reached if no sol found + ___permissible = 0; + break; // Go to next i, since t is unfirable + } + + } // end for(___j ... + if(___permissible) + return ___a + 1; // the transition may be fired! + } // end for(___i ... + ___q->atype -= ___q->atype & 2; // reset bit 1 of atype + return 0; // no transition of ___q may be fired! +} // ends IsPermissible + +#endif // ends ifdef ACTIONS + + +struct ___comm* ___new_comm_struct() { + int ___ip[2]; + struct ___comm* ___p; + + ___p = malloc(sizeof(*___p)); + if(! ___p) { + debugInfo("Could not allocate memory for 'struct ___comm' object"); + return 0; + } + + if (pipe(___ip) == -1) { + debugInfo("Could not open unnamed pipes"); + free(___p); + return 0; + } + + ___p->sread = ___ip[0]; + ___p->pwrite = ___ip[1]; + + if (pipe(___ip) == -1) { + debugInfo("Could not open unnamed pipes"); + close(___p->sread); + close(___p->pwrite); + free(___p); + return 0; + } + + ___p->swrite = ___ip[1]; + ___p->pread = ___ip[0]; + + fcntl( ___p->sread, F_SETFL, O_NONBLOCK); + fcntl( ___p->swrite, F_SETFL, O_NONBLOCK); + fcntl( ___p->pwrite, F_SETFL, O_NONBLOCK); + + return ___p; +} + + +struct proc* ___NewProcess(int ___type) { + // Creates new process structure. Places it at the beginning in prlist. + + struct proc *___p; + + ___p = calloc(1, sizeof(*___p)); // initializes everything to zero + if(!___p) { + debugInfo("Could not allocate memory for 'struct proc' object"); + return 0; + } + + ___p->comm = ___new_comm_struct(); + if(!___p->comm) { + free(___p); + return 0; + } + + ___p->tlist = calloc(___maxOutpTranNum[___type], sizeof(*(___p->tlist))); + if( ! ___p->tlist) { + debugInfo("Could not allocate memory for 'tlist' field of 'struct proc'"); + free(___p->comm); + free(___p); + return 0; + } + + ___p->ntlist = ___maxOutpTranNum[___type]; + ___p->type = ___type; + + // insert element in ___prlist + + if( ! ___prlist) + ___prlist = ___p; + else { + ___prlist->prev_in_prlist = ___p; + ___p->next_in_prlist = ___prlist; + ___prlist = ___p; + } + + return ___p; +} + + +void ___free_comm(struct ___comm *___pc) { + if(___pc) { + close(___pc->sread); close(___pc->swrite); + if( ! ___pc->pclosed ) { + close(___pc->pread); close(___pc->pwrite); + } + free(___pc); + } +} + + +void inline ___remove_from_prlist(struct proc *___p) { + if(___prlist == ___p) // is ___p first element of ___prlist? + ___prlist = ___p->next_in_prlist; + if(___p->prev_in_prlist) + ___p->prev_in_prlist->next_in_prlist = ___p->next_in_prlist; + if(___p->next_in_prlist) + ___p->next_in_prlist->prev_in_prlist = ___p->prev_in_prlist; + ___p->next_in_prlist = 0; // these two lines unnecessary if ___p is freed next + ___p->prev_in_prlist = 0; +} + +void inline ___remove_from_queue(struct proc *___p) { + if(___first == ___p) + ___first = ___p->next_in_queue; + if(___last == ___p) + ___last = ___p->prev_in_queue; + if(___p->prev_in_queue) + ___p->prev_in_queue->next_in_queue = ___p->next_in_queue; + if(___p->next_in_queue) + ___p->next_in_queue->prev_in_queue = ___p->prev_in_queue; + ___p->prev_in_queue = 0; + ___p->next_in_queue = 0; +} + +void inline ___remove_from_wtlist(struct proc *___p) { + struct proc **___ap = ___wtlist + ___p->type, **___apL = ___wtlistLast + ___p->type; + + if(*___ap == ___p) + *___ap = ___p->next_in_wtlist; + if(*___apL == ___p) + *___apL = ___p->prev_in_wtlist; + if(___p->prev_in_wtlist) + ___p->prev_in_wtlist->next_in_wtlist = ___p->next_in_wtlist; + if(___p->next_in_wtlist) + ___p->next_in_wtlist->prev_in_wtlist = ___p->prev_in_wtlist; + ___p->prev_in_wtlist = 0; + ___p->next_in_wtlist = 0; +} + + + +void ___free_proc(struct proc* ___p) { + if(___p) { + + if(___p->tlist) free(___p->tlist); + + ___free_comm(___p->comm); // Close communication channels and free memory + + // Remove ___p from process lists + + ___remove_from_prlist(___p); + ___remove_from_queue(___p); + ___remove_from_wtlist(___p); + + free(___p); + } +} + + +struct ___thread_data* get_thread_data(struct proc* ___p, int ___where) { + struct ___thread_data *___pthr; + struct ___thread_comm *___pc; + + ___pthr = calloc(1, sizeof(*___pthr)); + if(!___pthr) { + debugInfo("Could not allocate 'struct ___thread_data' object"); + return 0; + } + ___pc = calloc(1, sizeof(*___pc)); + if(!___pc) { + free(___pthr); + debugInfo("Could not allocate 'struct ___thread_comm' object"); + return 0; + } + + ___pc->pread = ((struct ___comm*) ___p->comm)->pread; + ___pc->pwrite = ((struct ___comm*) ___p->comm)->pwrite; + ___pthr->comm = ___pc; + ___pthr->debug = ___debug; + ___pthr->state = ___where; + ___pthr->id = (void*) ___p; + + return ___pthr; +} + + +void get_process_comm_data(struct proc* ___p) { + sprintf(___com, "%d", ((struct ___comm*)___p->comm)->pread); +} + + +int ___upd_comm_param(int ___sup, struct proc* ___p, int ___where) { + // This function is used for processes created via "fork" instructions. + // Since "fork" creates duplicate file descriptors in the child process, + // unnecessary descriptors are closed in this function. + + struct proc *___pa; + void *___v = ___p; + + if(!___sup) { // if this is the child process, close 'sread' and 'swrite' + close(((struct ___comm*)___p->comm)->sread); + close(((struct ___comm*)___p->comm)->swrite); + for(___pa = ___prlist; ___pa; ___pa = ___pa->next_in_prlist) { + if(___pa == ___p) + continue; + close(((struct ___comm*)___pa->comm)->sread); + close(((struct ___comm*)___pa->comm)->swrite); + } + return 1; + } + else { // if this is the supervisor process + close(((struct ___comm*)___p->comm)->pread); + close(((struct ___comm*)___p->comm)->pwrite); + ((struct ___comm*)___p->comm)->pclosed = 1; + + // send parameters to child process + + if(write(((struct ___comm*)___p->comm)->swrite, \ + &((struct ___comm*)___p->comm)->pwrite, \ + sizeof(((struct ___comm*)___p->comm)->pwrite)) == -1) + return 0; + if(write(((struct ___comm*)___p->comm)->swrite, & ___v, \ + sizeof(void*)) == -1) + return 0; + if(write(((struct ___comm*)___p->comm)->swrite, & ___debug, \ + sizeof(___debug)) == -1) + return 0; + if(write(((struct ___comm*)___p->comm)->swrite, & ___where, \ + sizeof(___where)) == -1) + return 0; + } + return 1; +} + + +inline int ___send_to_supervisor(const void* ___pdata, int ___n, \ + struct proc* ___p) { + // Sends ___n bytes of data located at address ___pdata. Here, ___p is the + // address of the 'struct proc' object of the sender process. + // This function is called only from error conditions. It returns 0 if the + // message could not be sent. + + return ___send_msg(___pdata, ___n, ((struct ___comm*)___p->comm)->pwrite, debugInfo); +} + + +void ___terminate_process(struct proc* ___p) { + if(___p->pid) // then this is a forked process + kill(___p->pid, SIGINT); + else // then this is a thread + pthread_kill(___p->thread_id, SIGINT); + ___free_proc(___p); +} + + +struct proc* ___StartProcess(int ___type, int ___where) { + struct proc *___pr; + int ___i; + struct ___thread_data *___pthr; + pid_t ___cpid; + struct ___msg ___ms; + + ___pr = ___NewProcess(___type); + if( ! ___pr) { + debugInfo("Unable to create new process!\n"); + return 0; + } + + #ifdef ___THREADS + + if(___start_fn[___type]) { + ___pthr = get_thread_data(___pr, ___where); + if(!___pthr) { + debugInfo("Cannot start thread with empty ___thread_data object"); + return 0; + } + ___i = pthread_create(&___pr->thread_id, 0, ___start_fn[___type],\ + (void*) ___pthr); + if(___i) { + debugInfo("pthread_create has returned the error code %d", ___i); + free(___pthr); + ___free_proc(___pr); + return 0; + } + return ___pr; + } + + #endif + + #ifdef ___PROCESSES + + if(___pname[___type]) { + get_process_comm_data(___pr); // updates the ___com variable + ___cpid = fork(); + if(___cpid == -1) { + debugInfo("fork() was not able to create a new process"); + ___free_proc(___pr); + return 0; + } + if( ! ___cpid) { // code execuded by child process + ___upd_comm_param(0, ___pr, ___where); + execlp(___pname[___type], ___pname[___type], ___com, 0); + debugInfo("exclp was unable to start \"%s %s\"", ___pname[___type], ___com); + ___ms.type = ___EXIT_NOTIFICATION; + ___ms.id = ___pr; + ___send_to_supervisor(&___ms, sizeof(___ms), ___pr); + exit(EXIT_FAILURE); // this line should not be reached + } + else { // code executed by supervisor + // upd_comm_param below updates the communication settings of the + // supervisor and sends input parameters to the child process + ___pr->pid = ___cpid; + if( ! ___upd_comm_param(1, ___pr, ___where)) { + debugInfo("Unable to initiate communication with child process"); + ___terminate_process(___pr); // also calls ___free_proc(___pr) + return 0; + } + return ___pr; + } + } + + #endif + + debugInfo("___StartProcess indicates a problem with the supervisor template or\ + the supervisor compiler"); // this line should not be reached + + return 0; +} + + + +void ___finish_sig_handler(int ___sig) { + struct proc* ___p; + + if(getpid() != ___pid) + exit(EXIT_FAILURE); + else if(pthread_self() != ___tid) + pthread_exit(0); + else { + debugInfo("A signal has been received and the program will be terminated"); + for(___p = ___prlist; ___p; ___p = ___p->next_in_prlist) + ___terminate_process(___p); // also calls___free_proc(___p); + exit(EXIT_SUCCESS); + } +} + + +inline int ___check_for_msg(struct proc *___p, struct ___msg *p___ms) { + // The function returns 0 if there are no messages + + return ___get_msg(((struct ___comm*)___p->comm)->sread, p___ms, \ + sizeof(*p___ms), debugInfo); +} + + +void inline ___PerformAction(int ___a, char* ___msk) { + +#ifdef ___ACTIONS + + int ___i, ___j, ___n, ___w; + struct ___action* ___ac = ___act + ___a; + + // Start new processes (if applicable) + + ___n = ___ac->no; + for(___i = 0; ___i < ___n; ___i++) { + if(___msk) + if(___msk[___i]) // ignore masked entries + continue; + ___j = 0; + if(___ac->not[___i] > 1) + ___j = rand() % ___ac->not[___i]; // select one of the source transitions + ___w = ___ac->oweight[___i][___j]; + for( ; ___w; ___w--) + ___StartProcess(___ac->otype[___i], ___ac->oplace[___i][___j]); + } + +#endif + +} + + +void ___execute_action(int ___a) { + int ___i = 1; + +#ifdef ___ACTIONS + + ___i = (___a < 0) || (___a >= ___ACTIONS); + +#endif + + if(___i) { + debugInfo("Action %d is undefined", ___a); + return; + } + + ___UpdateSupervisorMarking(___a); + ___PerformAction(___a, 0); // start new processes, if applicable +} + + +int ___process_msg(struct ___msg *p___ms) { + // Returns zero if the process of p___ms has terminated + struct proc **___ap, **___apL, *___p, *___pa = p___ms->id; + int ___i; + + switch(p___ms->type) { + + case ___EXIT_NOTIFICATION: // then deallocate process + + for(___p = ___prlist; ___p; ___p = ___p->next_in_prlist) { + if(___pa == ___p) { + ___free_proc(___p); + break; + } + } + return 0; + + case ___FIRING_REQUEST: + + + // Is this message about the last answered request? + if(___pa->solved == p___ms->req_id) // req_id may not be zero + return 1; // nothing to do, the request is already answered + + // Is this firing request already in the queue? + + if(___pa->request == p___ms->req_id) { + ___i = ___pa->ntlist; + if(___i >= ___maxOutpTranNum[___pa->type]) + debugInfo("Transition list of (%d:%d) exceeds maximum size", (int) ___pa->pid, (int) ___pa->thread_id); + else { + ___pa->tlist[___i].t = p___ms->t; + ___pa->tlist[___i].a = p___ms->a; + ___pa->ntlist++; + } + debugInfo("Proc. type %d (%d:%d): t%d (a%d) alternative tran. to fir. req. %d", (int)___pa->type, (int) ___pa->pid, (int) ___pa->thread_id, (int)p___ms->t, (int)p___ms->a, (int)___pa->request); + return 1; + } + + // If not in queue, add to queue and wtlist + + ___pa->request = p___ms->req_id; + + ___pa->tlist[0].t = p___ms->t; + ___pa->tlist[0].a = p___ms->a; + ___pa->ntlist = 1; + + if(!___last) { // update queue + ___last = ___pa; + ___first = ___pa; + } + else { + ___last->next_in_queue = ___pa; + ___pa->prev_in_queue = ___last; + ___last = ___pa; + } + + ___ap = ___wtlist + ___pa->type; // update wtlist + ___apL = ___wtlistLast + ___pa->type; + if(!*___apL) { + *___apL = ___pa; + *___ap = ___pa; + } + else { + (*___apL)->next_in_wtlist = ___pa; + ___pa->prev_in_wtlist = *___apL; + *___apL = ___pa; + } + + debugInfo("Firing req. [id:%d] (%d:%d): proc. type %d requests t%d (a%d)", (int)___pa->request, (int) ___pa->pid, (int) ___pa->thread_id, (int) ___pa->type, (int)p___ms->t, (int)p___ms->a); + + return 1; + + case ___FIRING_NOTIFICATION: + + ___execute_action(p___ms->a); + return 1; + + default: + debugInfo("Type %d of (%d:%d) is an undefined message type", (int)p___ms->type, (int) ___pa->pid, (int) ___pa->thread_id); + } + + return 1; +} + + + +inline void ___send_permission_msg(struct proc *___p) { + + ___send_msg(&___p->fireable, sizeof(int), ((struct ___comm*)___p->comm)->swrite, debugInfo); + +} + + +int main(int argc, char* argv[]) { + int ___i, ___j, ___a; + char* ___str, ___no_msg, ___start_flag; + struct proc *___p, *___pa, *___pn; + struct sigaction ___act; + struct ___msg ___ms; + time_t ___ctime; + char ___help_msg[] = "\nOptions: \n\ + -e: suppress error and status messages\n\ + -s: start the program right away without displaying introductory message\n\n\ + Ctrl-C (SIGINT) can be used to stop the program. This will terminate all\n\ + its processes.\n"; + + ___pid = getpid(); + ___tid = pthread_self(); + + ___debug = 0; + ___finish = 0; + ___f = stderr; + ___name = 0; + ___prlist = 0; + ___first = 0; ___last = 0; + + // install signal handlers + + sigaction(SIGINT, 0, &___act); // initialize act + ___act.sa_flags = 0; + //sigemptyset(&act.sa_mask); // no signals blocked + ___act.sa_handler = ___finish_sig_handler; + sigaction(SIGINT, &___act, 0); // initialize act + + time(&___ctime); + srand(___ctime%64000); + + ___debug = 1; + ___start_flag = (argc <= 1); + for(___i = 1; ___i < argc; ___i++) { + if(!strcmp(argv[___i], "-e")) + ___debug = 0; + else if(!strcmp(argv[___i], "-h") || !strcmp(argv[___i], "--help")) { + fprintf(stdout, ___help_msg); + return 0; + } + else if(!strcmp(argv[___i], "-s")) { + ___start_flag = 0; // "-s" is for future use; unnecessary right now + } + } + + if(___start_flag) { + fprintf(stdout, "%s\nThe program will start in five seconds.\n", ___help_msg); + sleep(5); + } + + if(___debug) { + if(argc <= 1) + debugInfo("The main function was entered. The main functions has no parameters."); + else { + for(___i = 0, ___j = 0; ___i < argc; ___i++) + ___j += strlen(argv[___i]); + ___j += argc + 1; + ___str = malloc(___j*sizeof(char)); + for(___i = 0, ___j = 0; ___i < argc - 1; ___i++) { + sprintf(___str + ___j, "%s ", argv[___i]); + ___j += strlen(argv[___i]) + 1; + } + sprintf(___str + ___j, "%s", argv[___i]); + debugInfo("The process was started with the following command line\n\t%s", ___str); + free(___str); + } + } + + // initialize supervisor ___marking + memset(___marking, 0, sizeof(*___marking)*___pnum); + for(___i = 0; ___i < n___m0; ___i++) + ___marking[___m0[___i][0]] = ___m0[___i][1]; + ___fire_zltrans(); // fire zero label transitions of supervisor if enabled + + // start processes + for(___i = 0; ___i < n___pm0; ___i++) + for(___j = 0; ___j < ___pm0[___i][2]; ___j++) // ___pm0[___i][2]: # of tokens + ___StartProcess(___pm0[___i][0], ___pm0[___i][1]); // arguments: type, place + + + while( ! ___finish) { + + if(!___prlist) + break; // all processes have terminated, so the supervisor terminates + + // Check all processes for new messages + + for(___p = ___prlist, ___no_msg = 1; ___p; ___p = ___pn) { + ___pn = ___p->next_in_prlist; // process_msg below may deallocate ___p + for(___i = 0; ___i < MSG_READ_LIMIT; ___i++) { + ___j = ___check_for_msg(___p, &___ms); + if( ! ___j ) + break; // exit loop, since there are no messages + ___no_msg = 0; + if( ! ___process_msg(&___ms) ) // processes the message + break; // exit loop since the process of ___p has terminated + } + } + + if(___no_msg) { + sleep(2); // any interrupt will awake the process + continue; + } + + // Check for queued requests that can be resolved + +#ifdef ___ACTIONS // There may be queued requests only if actions are defined, + // as can be seen in the definition of ___process_msg(). + + for(___p = ___first; ___p; ___p = ___pn) { // search queued requests + ___pn = ___p->next_in_queue; // the loop will not deallocate ___p but + // it may remove ___p from the queue + ___a = IsPermissible(___p); // creates EntryList (qelist) + if(___a > 0) { // then the request of ___p can be resolved + + // Grant permission to fire to the processes in EntryList + // Remove also from queue and wait list processes in EntryList + + for(___pa = ___p; ___pa; ___pa = ___pa->next_in_qelist) { + // This loop does not affect 'qelist' (EntryList). + // However, it does affect 'queue' and 'wtlist'. + if(___pn == ___pa) // if ___pn will be removed from queued requests + ___pn = ___pn->next_in_queue; // select next queued request + ___send_permission_msg(___pa); + ___remove_from_queue(___pa); // remove ___pa from queued requests + ___remove_from_wtlist(___pa); + } + + clear_qel_entries(___p); // delete EntryList except for first element + ___p->atype -= (___p->atype & 2); // remove first el of EntryList + ___a--; // since IsPermissible adds 1 to the return value + ___UpdateSupervisorMarking(___a); // update supervisor marking +#ifdef ___MASK + ___PerformAction(___a, ___mask); // start new processes, if applicable +#else + ___PerformAction(___a, 0); // start new processes, if applicable +#endif + + } + } +#endif // end of ifdef ___ACTIONS + + } // end of while( ! ___finish) (the main loop) + + debugInfo("The end of the main function was reached.\n"); + + return 1; +} + Added: newcodegen/codegen.h =================================================================== --- newcodegen/codegen.h (rev 0) +++ newcodegen/codegen.h 2011-04-02 00:08:32 UTC (rev 244) @@ -0,0 +1,51 @@ +/* codegen.h + + This header file was created for the 2010 version of the code generation tools. +*/ + +/* The code generation module expects processes satisfying the following + + - Nondeterministic places: If a place is nondeterministic and one of its + output transitions is controlled by the supervisor or participates in a + process synchronization, then permission to fire is always requested + from the supervisor. (NOT YET IMPLEMENTED.) + + - The supervisor format: It is assumed that each transition has a + unique label. Process transitions that are synchronized are assumed to + have the same label. The supervisor is connected to the plant using the + conventional parallel composition of PNs. + + - The select function: If defined, it should return the number of + transitions selected. Let n be that number. The select function writes the + list of enabled transitions by writing their data to the first n elements + of the array ___TR of ProcessTemplate.c. + + It is assumed that for a pn structure, the select[i] item contains a + string indicating how the select function should be called. Example: + select[0] = "myselect(1, x, y);", where x and y should be defined in + the context of the segment[i] code. Note that select[0] does not specify + any assignment of the return value. The code generation module is + responsible for writing the assignment of the return value. + +*/ + + + +#define INDENT 2 // indentation increment used in generated C code + +#define DBG3 is_verbose()>=3 + + +int FillTemplate(FILE* template, FILE* outp, ...); // in filltmpl.lex + +FILE* searchTemplate(char* s); // in plantCompiler.c + +char* GetFileName(const char* s, const char *ext); +// Similar to "asprintf(&x, "%s.%s", s, ext); return x;" + +void compileSupervisor(pns *supervisor, char* sname, process **procTypes, \ + int nbrTypes, TrData** TrInfo, struct synclist* sl, \ + const char* buildparam); + +void compileProcessArray(process **procArray, int nbrElements, TrData** TrInfo, \ + int** actlabels); Added: newcodegen/compexample.c =================================================================== --- newcodegen/compexample.c (rev 0) +++ newcodegen/compexample.c 2011-04-02 00:08:32 UTC (rev 244) @@ -0,0 +1,278 @@ +#include"pns.h" +#include"codegen.h" + + +int verb = 3; + +int inline is_verbose() { return verb; } + +int main() { + int i; + + /* Declaring pn objects */ + + pns pn_p, pn_s, pn_s2, pn, pn2, pn3; + process pr1, pr2, pr3, *apr[2]; + + + /* Petri nets can be initialized using the incidence matrix */ + + /* This will be used for the incidence matrix of one pn */ + + int Dp[] = { 1, 1, -1, 1, 0, 0,\ + 0, 0, 1, 0, -1, 0,\ + 0, -1, 1, 0, 0, -1,\ + -1, 0, 0, 0, 1, 0,\ + 0, 0, 0, -1, 0, 1}; + + int mp[] = { 1, 1, 1, 1, 1}; /* The initial marking */ + + /* These will be used for the input and output matrices of another pn */ + + int Is[] = { 0, 1, 0, 0,\ + 0, 0, 1, 0,\ + 0, 0, 0, 1,\ + 1, 0, 0, 0}; + + int Os[] = { 0, 0, 1, 0,\ + 0, 0, 0, 1,\ + 1, 0, 0, 0,\ + 0, 1, 0, 0}; + + int ms[] = {0, 0, 1, 1}; /* The initial marking */ + + struct placelist *plist; + arcs* alist; + char *str; + + /* Here is how the pn objects are created */ + + /* The following creates a pn of 5 places, 6 transitions, incidence + matrix Dp, and initial marking mp */ + pn_p = createpn("pnum tnum D m0", 5, 6, Dp, mp); + + /* Here the input and output matrices are used to initialize the pn */ + pn_s = createpn("pnum tnum I O m0", 4, 4, Is, Os, ms); + + /* This creates a pn object without transition arcs */ + pn = createpn("pnum tnum", 3, 5); + + int m0pn[] = {1, 0, 0}; + updatepn(&pn, "m0", m0pn); + + // Let's create the following PN: + // + // t2 + // -------|<---- + // | p0 p1 |p2 + // ->O->|->O->|->O<-- + // | t0 | t1 | + // | | | + // | V | + // | --- t3 | + // | | + // ------>|------- + // t4 + + /* GetMatrixEl and SetMatrixEl can be used to read or write the elements + of a matrix. */ + + /* For instance, arcs could be added by changing the value of the input + and output matrices of the pn */ + + SetMatrixEl(&pn.out, 0, 0, 1); /* add arc from p0 to t0 of weight 1 */ + SetMatrixEl(&pn.out, 0, 4, 1); /* add arc from p0 to t4 of weight 1 */ + SetMatrixEl(&pn.in, 0, 2, 1); + + SetMatrixEl(&pn.out, 1, 1, 1); + SetMatrixEl(&pn.out, 1, 3, 1); + SetMatrixEl(&pn.in, 1, 0, 1); + + SetMatrixEl(&pn.out, 2, 2, 1); + SetMatrixEl(&pn.in, 2, 1, 1); + SetMatrixEl(&pn.in, 2, 4, 1); + + int labls[] = {-1, -2, -3, -4, -5}; + updatepn(&pn, "labels", labls); + + // Let's create one more PN: + // + // p0 p1 + // |->O->|->O->| + // t2 t0 t1 + // + + pn3= createpn("pnum tnum", 2, 3); + int labl2[] = {-1, -7, -5}; + + SetMatrixEl(&pn3.out, 0, 0, 1); /* add arc from p0 to t0 of weight 1 */ + SetMatrixEl(&pn3.in, 0, 2, 1); + + SetMatrixEl(&pn3.out, 1, 1, 1); + SetMatrixEl(&pn3.in, 1, 0, 1); + + updatepn(&pn3, "labels", labl2); + + /* For instance, to check whether there is an arc from t1 to p2: */ + i = GetMatrixEl(&pn.in, 2, 1); + if(i) + fprintf(stderr, "\nThe arc (t1, p2) has the weight %d.\n", i); + else + fprintf(stderr, "\nThere is no arc from t1 to p2.\n"); + + /* To display in text format a Petri net object use displaypn */ + + fprintf(stderr, "\n** PN_P *************************************\n"); + displaypn(pn_p, stderr); /* displays pn_p */ + fprintf(stderr, "\n** PN_S *************************************\n"); + displaypn(pn_s, stderr); /* displays pn_s */ + fprintf(stderr, "\n** PN *************************************\n"); + displaypn(pn, stderr); /* displays pn */ + + /* Properties of the pn objects can be set or changed with updatepn */ + + updatepn(&pn, "place_name", 0, "start_p"); + /* The line above associates the name "start_p" with the place 0 */ + + updatepn(&pn, "trans_name", 0, "tr0"); + /* The line above associates the name "tr0" with the transition 0 */ + + updatepn(&pn, "select", 1, "f1(u)"); /*select function 'f1' for place 1*/ + + updatepn(&pn, "segment", 0, "u++; printf(\"\\nPN: State 0 u = %d\", u);\ndelay(1);"); + updatepn(&pn, "segment", 1, "printf(\"\\nPN: State 1\");\ndelay(1);"); + updatepn(&pn, "segment", 2, "printf(\"\\nPN: State 2\");\ndelay(1);"); + + updatepn(&pn3, "segment", 0, "u++; printf(\"\\nPN3: State 0 u = %d\", u);\ndelay(2);"); + updatepn(&pn3, "segment", 1, "printf(\"\\nPN3: State 1\");\ndelay(2);"); + + /* Text transmitted by means of createpn/updatepn is copied to the + corresponding items of the pns object; thus it should be + deallocated, when applicable. For instance: */ + + //str = tcalloc(strlen("f1(i, j);")+1, sizeof(char)); + //strcpy(str, "f1(i, j);"); + //updatepn(&pn, "segment", 1, str); + ///* Now, str may be freed, since its content has been copied */ + // free(str); + + /* Flags are set as follows. */ + + updatepn(&pn, "unobservable nondeterministic", 0, 1); + /* marks transition 0 unobservable and place 1 as nondeterministic */ + + updatepn(&pn, "live uncontrollable uncontrollable", 0, 0, 2); + /* The line above sets the "live" and "uncontrollable" flags of + transition 0 and the uncontrollable flag of transition 2 */ + + /* To create a copy */ + + pn2 = copypn(&pn); + + + + /* Arcs are added similarly (using createpn or updatepn). Here is + an example. */ + + plist = tmalloc(sizeof(struct placelist)); + plist->place = 1; + plist->next = tmalloc(sizeof(*plist)); + plist->next->place = 2; + plist->next->next = 0; + + alist = tmalloc(sizeof(arcs)); + alist->in_place = 0; + alist->out_places = plist; + alist->condition = tcalloc(strlen("j == i || z == 0.1")+1, sizeof(char)); + strcpy(alist->condition, "j == i || z == 0.1"); + alist->next = 0; + + updatepn(&pn, "arcs", 0, alist); /* arc list associated with transition 0 */ + + /* The line above updates the arc_list item of the pns object as well as the + input & output matrices. */ + + /* Note the absence of the lines of code deallocating alist. The object alist is + placed in the pns object, it is not copied. Thus, alist is deallocated when + the pns object is deallocated with the function deallocpn. */ + + + TrData **TInf; + + // Let's create also some processes + + asprintf(&(pr1.name), "type_one"); asprintf(&(pr2.name), "PN3"); + pr1.instance = "pr1"; pr2.instance = "pr2"; + pr1.thread = 0; pr2.thread = 1; + pr1.pn = &pn2; pr2.pn = &pn3; + asprintf(&(pr1.build), "gcc -g -o $$$.exe $$$.c"); + pr2.build = 0; + // pr2.build = "make -f pn3.mak"; + pr1.include = "#include<stdio.h>\nint pr1_state = 0, i, j, u = 0;\n\n\ +void delay(int n) {\n time_t a, b;\n\ + for(time(&a), time(&b); a + n > b; time(&b));\n}\n\nint f1(int z) {\n\ + if(u > 5) {\n\ + ___TR[0].no_output = 1;\n\ + ___TR[0].label = -4;\n\ + ___TR[0].trans = 3;\n\ + }\n\ + else {\n\ + ___TR[0].no_output = 0;\n\ + ___TR[0].label = -2;\n\ + ___TR[0].trans = 1;\n\ + ___TR[0].place = 2;\n\ + }\n\ + return 1;\n\ +}\n"; + pr2.include = "#include<stdio.h>\nint pr1_state = 0, i, j, u = 0;\n\n\ +void delay(int n) {\n time_t a, b;\n\ + for(time(&a), time(&b); a + n > b; time(&b));\n}\n\n"; + + pr1.type = 0; pr1.start = 1; pr2.type = 1; pr2.start = 0; + apr[0] = &pr1; + apr[1] = &pr2; + + TInf = calloc(sizeof(TrData*), 2); + TInf[0] = calloc(sizeof(TrData), pn2.tnum); + TInf[1] = calloc(sizeof(TrData), pn3.tnum); + + // int labls[] = {-1, -2, -3, -4, -5}; + // int labl2[] = {-1, -7, -5}; + + struct synclist *sn1; + struct sync_element *se; + + sn1 = calloc(2, sizeof(*sn1)); + se = calloc(10, sizeof(*se)); + + sn1[0].next = sn1+1; sn1->s = &se[0]; + se[0].prtype = 0; se[0].n = 1; + int t1[] = {0}, w1[] = {1}; + se[0].t = t1; se[0].w = w1; se[0].next = &se[1]; + se[1].prtype = 1; se[1].t = t1; se[1].w = w1; se[1].n = 1; + sn1[1].s = &se[2]; + int t2[] = {4}; + se[2].prtype = 0; se[2].t = t2; se[2].w = w1; se[2].n = 1; + sn1[1].o = &se[3]; se[3].n = 1; + int t3[] = {2}, p1[] = {0}; + se[3].prtype = 1; se[3].t = t3; se[3].w = w1; se[3].p = p1; + + //compileProcessArray(apr, 2, TInf); + //fprintf(stderr, "\nNow generating the supervisor ..."); + //compileSupervisor(&pn2, "spr", apr, 2, TInf, sn1, 0); + + CodeGenerator(&pn2, "spr", apr, 2, sn1, TInf, 0); + + for(i = 0; i < 2; i++) + free(TInf[i]); + free(TInf); + free(se); free(sn1); free(pr1.name); free(pr2.name); + /* To deallocate a pn object use deallocpn */ + + deallocpn(&pn_p); + deallocpn(&pn_s); + deallocpn(&pn); + deallocpn(&pn2); + + return 0; +} Added: newcodegen/filltmpl.lex =================================================================== --- newcodegen/filltmpl.lex (rev 0) +++ newcodegen/filltmpl.lex 2011-04-02 00:08:32 UTC (rev 244) @@ -0,0 +1,92 @@ + +LABEL ([ \t]*\/\/[ \t]*[+]{3,}[[:print:]]*) +IDENTIFIER ("(GENERATED CODE HERE)") + +%{ + #include<stdio.h> + #include<stdarg.h> + + int flag, skip, i, j; + va_list param; + FILE *out; + char *stmp, cc; + +%} + + +%% + +{LABEL}/{IDENTIFIER} { + flag = 0; skip = 1; + fprintf(out, "%s (BEGINNING OF CODE)\n", yytext); + for(i = 0; yytext[i] == ' ' || yytext[i] == '\t'; i++); + cc = yytext[i]; + yytext[i] = 0; // g... [truncated message content] |
From: <com...@us...> - 2009-08-23 07:45:51
|
Revision: 243 http://pntool.svn.sourceforge.net/pntool/?rev=243&view=rev Author: compaqdrew Date: 2009-08-23 07:45:43 +0000 (Sun, 23 Aug 2009) Log Message: ----------- Local simulation Modified Paths: -------------- codegen/supervisor_algorithm.txt Modified: codegen/supervisor_algorithm.txt =================================================================== --- codegen/supervisor_algorithm.txt 2009-08-23 07:45:39 UTC (rev 242) +++ codegen/supervisor_algorithm.txt 2009-08-23 07:45:43 UTC (rev 243) @@ -44,17 +44,27 @@ Then the reservation has been cancelled. The reservation-id may also be re-used. -Instead, the supervisor could send you a Y message, in which case the plant needs to respect it and fire the appropriate transition. Reservations are not canceled until the plant receives notification of such. +Instead, the supervisor could send a Y message, in which case the plant needs to respect it and fire the appropriate transition. Reservations are not canceled until the plant receives notification of such. RESERVATION INTERNALS When the supervisor receives a reservation request, it places a reservation into a hashmap and for each option communicated by the plant, a fire_something associated with that reservation. For instance, if a plant makes a reservation with five transitions, a single reservation struct with five child fire_something structs will be created. -Periodically, the supervisor polls its list of outstanding reservations (close_reservation_pass), and attempts to resolve it by iterating through the fire_something list to see if a transition can be fired (attempt_close_reservation). If it can be fired, it immediately halts its search, informs the plant that reservation has been resolved (and informs the plant which transition has been selected), immediately halts its own simulation (by setting the somebodys_firing_transition to a non-zero value) and waits for the plant to indicate the fire was successful. +Periodically, the supervisor polls its list of outstanding reservations (close_reservation_pass), and attempts to resolve reservations by iterating through the fire_something list to see if a transition can be fired (attempt_close_reservation). If it can be fired, it immediately halts its search, informs the plant that reservation has been resolved (and informs the plant which transition has been selected), immediately halts its own simulation (by setting the somebodys_firing_transition to a non-zero value) and waits for the plant to indicate the fire was successful. A reservation can be fired iff >=1 of the following cases hold (attempt_fire_something): A) The supervisor has no matching label B) The supervisor has a transition with a matching label and that transition is able to fire +I believe the current plant implementation queries the supervisor for every transition (whether the supervisor is interested or not). This behavior is not strictly required by the supervisor. + +I believe the current plant implementation sends only one transition choice to the supervisor, while the supervisor supports a list priority for transition choices as described above. + LOCAL SIMULATION +The supervisor has a full petri net simulation implementation, meaning that places and transitions that are not tied to external plants behave as expected. The supervisor iterates through tokens and transitions (simulation_pass_local) and fires all fireable transitions. +If a transition is blocked (at compile-time, i.e. a plant shares its label), it is not fired during local simulation. These transitions are only fired with the reservation system. +If a transition does not have enough input tokens in the correct input places, it will not fire. +Otherwise, the transition will fire. + +At this point, the input tokens are destroyed and the new tokens are created. Since the supervisor operates on a single thread, there's no danger of concurrency problems. \ No newline at end of file This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <com...@us...> - 2009-08-23 07:45:45
|
Revision: 242 http://pntool.svn.sourceforge.net/pntool/?rev=242&view=rev Author: compaqdrew Date: 2009-08-23 07:45:39 +0000 (Sun, 23 Aug 2009) Log Message: ----------- reservation internals Modified Paths: -------------- codegen/supervisor_algorithm.txt Modified: codegen/supervisor_algorithm.txt =================================================================== --- codegen/supervisor_algorithm.txt 2009-08-23 07:45:34 UTC (rev 241) +++ codegen/supervisor_algorithm.txt 2009-08-23 07:45:39 UTC (rev 242) @@ -18,7 +18,7 @@ ___?25:3-0,4-1,5-2,6-2\n <--several options here or ___?30:2-1\n <--only one option here -Using the [reservation-id]:[label number]-[transition number] syntax. Comma separated where applicable. Reservation-id is a unique unsigned char associated with a reservation for its lifetime. Typically token numbers are used, although any unique char is valid with respect to the supervisor. +Using the [reservation-id]:[label number]-[transition number] syntax. Comma separated where applicable. Reservation-id is a unique unsigned char associated with a reservation for its lifetime. Typically token numbers are used, although any unique char (unique plant-wide) is valid with respect to the supervisor. Once a reservation is made, the supervisor will examine its list of outstanding reservations and resolve them in a first-come, first-serve manner. In the first example, the supervisor might respond: @@ -46,3 +46,15 @@ Instead, the supervisor could send you a Y message, in which case the plant needs to respect it and fire the appropriate transition. Reservations are not canceled until the plant receives notification of such. +RESERVATION INTERNALS +When the supervisor receives a reservation request, it places a reservation into a hashmap and for each option communicated by the plant, a fire_something associated with that reservation. For instance, if a plant makes a reservation with five transitions, a single reservation struct with five child fire_something structs will be created. + +Periodically, the supervisor polls its list of outstanding reservations (close_reservation_pass), and attempts to resolve it by iterating through the fire_something list to see if a transition can be fired (attempt_close_reservation). If it can be fired, it immediately halts its search, informs the plant that reservation has been resolved (and informs the plant which transition has been selected), immediately halts its own simulation (by setting the somebodys_firing_transition to a non-zero value) and waits for the plant to indicate the fire was successful. + +A reservation can be fired iff >=1 of the following cases hold (attempt_fire_something): + +A) The supervisor has no matching label +B) The supervisor has a transition with a matching label and that transition is able to fire + +LOCAL SIMULATION + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <com...@us...> - 2009-08-23 07:45:40
|
Revision: 241 http://pntool.svn.sourceforge.net/pntool/?rev=241&view=rev Author: compaqdrew Date: 2009-08-23 07:45:34 +0000 (Sun, 23 Aug 2009) Log Message: ----------- Message passing format Modified Paths: -------------- codegen/supervisor_algorithm.txt Modified: codegen/supervisor_algorithm.txt =================================================================== --- codegen/supervisor_algorithm.txt 2009-08-23 07:45:30 UTC (rev 240) +++ codegen/supervisor_algorithm.txt 2009-08-23 07:45:34 UTC (rev 241) @@ -10,5 +10,39 @@ Since the processes are created with fork/exec, it's important to close file descriptors that are not needed by the process. For instance, on 491-499 of supervisor_static_include.h, the parent process closes the ends of the pipe that have been handed to the child. If the parent did not close these ends, the pipes would not flush properly. Likewise, the child must close its existing STDIN and STDOUT, as well as any pipe-ends it has inherited from the parent process during the exec. As a side note, file descriptor numbers are preserved across exec for posix platforms, so debug output from different processes should agree, which can assist in debugging pipe issues. - +Files are read with non-blocking I/O, to enable the supervisor to simultaneously poll the plants and perform its own simulation on a single thread. The supervisor holds one buffer for each plant process, and reads characters until it encounters a newline. +MESSAGE PASSING FORMAT + +Plant sends an [ordered] list of transition options: +___?25:3-0,4-1,5-2,6-2\n <--several options here +or +___?30:2-1\n <--only one option here +Using the [reservation-id]:[label number]-[transition number] syntax. Comma separated where applicable. Reservation-id is a unique unsigned char associated with a reservation for its lifetime. Typically token numbers are used, although any unique char is valid with respect to the supervisor. + +Once a reservation is made, the supervisor will examine its list of outstanding reservations and resolve them in a first-come, first-serve manner. In the first example, the supervisor might respond: + +___Y25:3-0\n +or +___Y25:4-1\n + +using [reservation-id]:[label number]-[transition number] syntax. When the plant receives this message, it should immediately to fire the transition and then send back: + +___F25\n +(25 here is the reservation-id) +with "F" meaning the transition has been fired. The supervisor will then close the outstanding reservation, and the plant is no longer obligated by the "ready-to-fire" condition. The reservation-id may also be re-used at this time. + +CANCELLING A RESERVATION + +If the plant wants to cancel an outstanding reservation, it can send the following message + +___C25\n + +When an echo is received, that is + +___C25\n + +Then the reservation has been cancelled. The reservation-id may also be re-used. + +Instead, the supervisor could send you a Y message, in which case the plant needs to respect it and fire the appropriate transition. Reservations are not canceled until the plant receives notification of such. + This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |