[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] |