[Pntool-developers] SF.net SVN: pntool:[260] present_version/spnbox
Brought to you by:
compaqdrew,
miordache
|
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] |