CE alte Probeklausur und aktuelle Folien

FoC aktuelle Folien
This commit is contained in:
M.Scholz 2011-10-31 13:36:29 +01:00
parent 63af4b992e
commit 3076751364
150 changed files with 28876 additions and 0 deletions

Binary file not shown.

BIN
ws2011/CE/Probeklausur.pdf Normal file

Binary file not shown.

View File

@ -0,0 +1,20 @@
ACKNOWLEDGMENTS
---------------
The ascii-soccer environment which was published
under the GPL is contained in that distribution
with special permission by Tucker Balch.
The "dot" tool from the GraphViz collection
(http://www.graphviz.org) is used for behavior
documentation purposes.
The LibXSLT (http://xmlsoft.org/XSLT/) library is used
used for behavior documentation purposes.
This product includes software developed by the
Apache Software Foundation (http://www.apache.org/).
This product includes DOTML developed by Martin Loetzsch
(http://www.martin-loetzsch.de/DOTML).

View File

@ -0,0 +1,348 @@
/**
* @file XabslAction.cpp
*
* Implementation of class Action and helper classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslAction.h"
#include "XabslOption.h"
namespace xabsl
{
Action* Action::create(
InputSource& input,
NamedArray<Option*>& options,
NamedArray<BasicBehavior*>& basicBehaviors,
Symbols& symbols,
Option& option,
State& state,
ErrorHandler& errorHandler,
const unsigned& time)
{
char c[2];
char buf[100];
input.readString(c,1);
input.readString(buf,99);
switch (*c)
{
case 'o':
XABSL_DEBUG_INIT(errorHandler.message("creating reference to option \"%s\"",buf));
if (!options.exists(buf))
{
errorHandler.error("XabslAction::create(): unknown option \"%s\" was encountered",buf);
return 0;
}
else
{
ActionOption* action = new ActionOption(time);
action->option = options[buf];
action->parameters = new ParameterAssignment(action->option->parameters, errorHandler);
action->parameters->create(input,
symbols,
option,
state);
return action;
}
break;
case 'a':
XABSL_DEBUG_INIT(errorHandler.message("creating reference to basic behavior \"%s\"",buf));
if (!basicBehaviors.exists(buf))
{
errorHandler.error("XabslAction::create(): the subsequent basic behavior \"%s\" was not registered",buf);
return 0;
}
else
{
ActionBasicBehavior* action = new ActionBasicBehavior(time);
action->basicBehavior = basicBehaviors[buf];
action->parameters = new ParameterAssignment(action->basicBehavior->parameters, errorHandler);
action->parameters->create(input,
symbols,
option,
state);
return action;
}
break;
case 'd':
XABSL_DEBUG_INIT(errorHandler.message("creating reference to decimal output symbol \"%s\"",buf));
if (!symbols.decimalOutputSymbols.exists(buf))
{
errorHandler.error("XabslAction::create(): decimal output symbol \"%s\" does not exist",buf);
return 0;
}
else
{
ActionDecimalOutputSymbol* action = new ActionDecimalOutputSymbol(time);
action->decimalOutputSymbol = symbols.decimalOutputSymbols[buf];
action->decimalOutputSymbolExpression = DecimalExpression::create(input,errorHandler,symbols,option,state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslAction::create(): could not create decimal expression for output symbol \"%s\"",buf);
delete action;
return 0;
}
return action;
}
case 'b':
XABSL_DEBUG_INIT(errorHandler.message("creating reference to boolean output symbol \"%s\"",buf));
if (!symbols.booleanOutputSymbols.exists(buf))
{
errorHandler.error("XabslAction::create(): boolean output symbol \"%s\" does not exist",buf);
return 0;
}
else
{
ActionBooleanOutputSymbol* action = new ActionBooleanOutputSymbol(time);
action->booleanOutputSymbol = symbols.booleanOutputSymbols[buf];
action->booleanOutputSymbolExpression = BooleanExpression::create(input,errorHandler,symbols,option,state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslAction::create(): could not create boolean expression for output symbol \"%s\"",buf);
delete action;
return 0;
}
return action;
}
case 'e':
XABSL_DEBUG_INIT(errorHandler.message("creating reference to enumerated output symbol \"%s\"",buf));
if (!symbols.enumeratedOutputSymbols.exists(buf))
{
errorHandler.error("XabslAction::create(): enumerated output symbol \"%s\" does not exist",buf);
return 0;
}
else
{
ActionEnumeratedOutputSymbol* action = new ActionEnumeratedOutputSymbol(time);
action->enumeratedOutputSymbol = symbols.enumeratedOutputSymbols[buf];
action->enumeratedOutputSymbolExpression = EnumeratedExpression::create(action->enumeratedOutputSymbol->enumeration,input,errorHandler,symbols,option,state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslAction::create(): could not create enumerated expression for output symbol \"%s\"",buf);
delete action;
return 0;
}
return action;
}
}
return 0;
}
Action* Action::create(
Behavior* behavior,
ErrorHandler& errorHandler,
const unsigned& time)
{
ActionBehavior* action = 0;
if (Option* option = dynamic_cast<Option*>(behavior))
{
action = new ActionOption(time);
static_cast<ActionOption*>(action)->option = option;
}
else if (BasicBehavior* basicBehavior = dynamic_cast<BasicBehavior*>(behavior))
{
action = new ActionBasicBehavior(time);
static_cast<ActionBasicBehavior*>(action)->basicBehavior = basicBehavior;
}
if (action != 0)
action->parameters = new ParameterAssignment(behavior->parameters, errorHandler);
return action;
}
ActionBehavior::~ActionBehavior()
{
if (parameters!=0)
delete parameters;
}
ActionDecimalOutputSymbol::~ActionDecimalOutputSymbol()
{
if (decimalOutputSymbolExpression!=0)
delete decimalOutputSymbolExpression;
}
ActionBooleanOutputSymbol::~ActionBooleanOutputSymbol()
{
if (booleanOutputSymbolExpression!=0)
delete booleanOutputSymbolExpression;
}
ActionEnumeratedOutputSymbol::~ActionEnumeratedOutputSymbol()
{
if (enumeratedOutputSymbolExpression!=0)
delete enumeratedOutputSymbolExpression;
}
void ActionBehavior::execute()
{
// execute subsequent option or basic behavior
if (parameters->set())
getBehavior()->parametersChanged();
if (!getBehavior()->wasActive) getBehavior()->timeWhenActivated = time;
getBehavior()->timeOfExecution = time - getBehavior()->timeWhenActivated;
getBehavior()->execute();
getBehavior()->isActive = true;
}
void ActionDecimalOutputSymbol::execute()
{
decimalOutputSymbolValue = decimalOutputSymbolExpression->getValue();
decimalOutputSymbol->setValue(decimalOutputSymbolValue);
}
void ActionBooleanOutputSymbol::execute()
{
booleanOutputSymbolValue = booleanOutputSymbolExpression->getValue();
booleanOutputSymbol->setValue(booleanOutputSymbolValue);
}
void ActionEnumeratedOutputSymbol::execute()
{
enumeratedOutputSymbolValue = enumeratedOutputSymbolExpression->getValue();
enumeratedOutputSymbol->setValue(enumeratedOutputSymbolValue);
}
const Behavior* ActionOption::getBehavior() const
{
return option;
}
const Behavior* ActionBasicBehavior::getBehavior() const
{
return basicBehavior;
}
Behavior* ActionOption::getBehavior()
{
return option;
}
Behavior* ActionBasicBehavior::getBehavior()
{
return basicBehavior;
}
Behavior* Action::getBehavior()
{
if (ActionBehavior* action = dynamic_cast<ActionBehavior*>(this))
return action->getBehavior();
else
return 0;
}
Option* Action::getOption()
{
if (ActionOption* action = dynamic_cast<ActionOption*>(this))
return action->option;
else
return 0;
}
BasicBehavior* Action::getBasicBehavior()
{
if (ActionBasicBehavior* action = dynamic_cast<ActionBasicBehavior*>(this))
return action->basicBehavior;
else
return 0;
}
const Behavior* Action::getBehavior() const
{
if (const ActionBehavior* action = dynamic_cast<const ActionBehavior*>(this))
return action->getBehavior();
else
return 0;
}
const Option* Action::getOption() const
{
if (const ActionOption* action = dynamic_cast<const ActionOption*>(this))
return action->option;
else
return 0;
}
const BasicBehavior* Action::getBasicBehavior() const
{
if (const ActionBasicBehavior* action = dynamic_cast<const ActionBasicBehavior*>(this))
return action->basicBehavior;
else
return 0;
}
ParameterAssignment* Action::getParameters()
{
if (ActionBehavior* action = dynamic_cast<ActionBehavior*>(this))
return action->parameters;
else
return 0;
}
const ParameterAssignment* Action::getParameters() const
{
if (const ActionBehavior* action = dynamic_cast<const ActionBehavior*>(this))
return action->parameters;
else
return 0;
}
const DecimalOutputSymbol* Action::getDecimalOutputSymbol() const
{
if (const ActionDecimalOutputSymbol* action = dynamic_cast<const ActionDecimalOutputSymbol*>(this))
return action->decimalOutputSymbol;
else
return 0;
}
const BooleanOutputSymbol* Action::getBooleanOutputSymbol() const
{
if (const ActionBooleanOutputSymbol* action = dynamic_cast<const ActionBooleanOutputSymbol*>(this))
return action->booleanOutputSymbol;
else
return 0;
}
const EnumeratedOutputSymbol* Action::getEnumeratedOutputSymbol() const
{
if (const ActionEnumeratedOutputSymbol* action = dynamic_cast<const ActionEnumeratedOutputSymbol*>(this))
return action->enumeratedOutputSymbol;
else
return 0;
}
double Action::getDecimalOutputSymbolValue() const
{
if (const ActionDecimalOutputSymbol* action = dynamic_cast<const ActionDecimalOutputSymbol*>(this))
return action->decimalOutputSymbolValue;
else
return 0;
}
bool Action::getBooleanOutputSymbolValue() const
{
if (const ActionBooleanOutputSymbol* action = dynamic_cast<const ActionBooleanOutputSymbol*>(this))
return action->booleanOutputSymbolValue;
else
return false;
}
int Action::getEnumeratedOutputSymbolValue() const
{
if (const ActionEnumeratedOutputSymbol* action = dynamic_cast<const ActionEnumeratedOutputSymbol*>(this))
return action->enumeratedOutputSymbolValue;
else
return 0;
}
} // namespace

View File

@ -0,0 +1,317 @@
/**
* @file XabslAction.h
*
* Definition of class Action and Helper classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslAction_h_
#define __XabslAction_h_
#include "XabslBasicBehavior.h"
#include "XabslDecimalExpression.h"
#include "XabslBooleanExpression.h"
#include "XabslEnumeratedExpression.h"
namespace xabsl
{
// class prototype needed for declaration of Action
class Option;
/**
* @class Action
*
* Represents an action execution. This is either a subsequent option or basic behavior to be executed, or an
* output symbol assignment.
*
* @author Max Risler
*/
class Action
{
public:
/**
* Constructor.
* @param time The system time in ms.
*/
Action(const unsigned &time) :
time(time)
{}
/**
* Virtual destructor.
*/
virtual ~Action() {}
/**
* Creates an action definition.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a state starts.
* @param options All available options
* @param basicBehaviors All available basicBehaviors
* @param symbols All available symbols
* @param option The current option
* @param state The current state
* @param errorHandler A reference to a ErrorHandler instance
* @param time The system time in ms.
*/
static Action* create(
InputSource& input,
NamedArray<Option*>& options,
NamedArray<BasicBehavior*>& basicBehaviors,
Symbols& symbols,
Option& option,
State& state,
ErrorHandler& errorHandler,
const unsigned& time);
/**
* Creates an action definition which just calls a single option or basic behavior
* without setting any parameters.
* @param behavior The referenced option or basic behavior.
* @param errorHandler A reference to a ErrorHandler instance
* @param time The system time in ms.
*/
static Action* create(
Behavior* behavior,
ErrorHandler& errorHandler,
const unsigned &time);
/** Execute the behavior or assign the output symbol */
virtual void execute() = 0;
/** Returns a pointer to the option or basic behavior to be executed, or 0 if an output symbol is set */
Behavior* getBehavior();
const Behavior* getBehavior() const;
/** Returns a pointer to the option, if an option is to be executed, 0 otherwise */
Option* getOption();
const Option* getOption() const;
/** Returns a pointer to the basic behavior, if a basic behavior is to be executed, 0 otherwise */
BasicBehavior* getBasicBehavior();
const BasicBehavior* getBasicBehavior() const;
/** Returns a pointer to the parameter assignments for an option or basic behavior, or 0 if an output symbol is set */
ParameterAssignment* getParameters();
const ParameterAssignment* getParameters() const;
/** Returns a pointer to the output symbol, if a decimal output symbol is to be assigned, 0 otherwise */
const DecimalOutputSymbol* getDecimalOutputSymbol() const;
/** Returns a pointer to the output symbol, if a boolean output symbol is to be assigned, 0 otherwise */
const BooleanOutputSymbol* getBooleanOutputSymbol() const;
/** Returns a pointer to the output symbol, if an enumerated output symbol is to be assigned, 0 otherwise */
const EnumeratedOutputSymbol* getEnumeratedOutputSymbol() const;
/** Returns the last symbol value, if a decimal output symbol is to be assigned, 0 otherwise */
double getDecimalOutputSymbolValue() const;
/** Returns the last symbol value, if a boolean output symbol is to be assigned, 0 otherwise */
bool getBooleanOutputSymbolValue() const;
/** Returns the last symbol value, if an enumerated output symbol is to be assigned, 0 otherwise */
int getEnumeratedOutputSymbolValue() const;
protected:
/** The system time in ms. */
const unsigned& time;
};
/**
* @class ActionBehavior
*
* Represents an action execution. This is either a subsequent option or basic behavior to be executed.
*
* @author Max Risler
*/
class ActionBehavior : public Action
{
public:
/**
* Constructor.
* @param time The system time in ms.
*/
ActionBehavior(const unsigned& time) :
Action(time),
parameters(0)
{}
/** Destructor */
~ActionBehavior();
/**
* Parameters of the option or basic behavior that is executed
*/
ParameterAssignment* parameters;
/**
* The option or basic behavior that is executed
*/
virtual const Behavior* getBehavior() const = 0;
virtual Behavior* getBehavior() = 0;
/** Execute the behavior */
virtual void execute();
};
/**
* @class ActionBasicBehavior
*
* Represents an action execution. In this case a basic behavior is to be executed.
*
* @author Max Risler
*/
class ActionBasicBehavior : public ActionBehavior
{
public:
/**
* Constructor.
* @param time The system time in ms.
*/
ActionBasicBehavior(const unsigned& time) :
ActionBehavior(time),
basicBehavior(0)
{}
BasicBehavior* basicBehavior;
virtual const Behavior* getBehavior() const;
virtual Behavior* getBehavior();
};
/**
* @class ActionOption
*
* Represents an action execution. In this case an option is to be executed.
*
* @author Max Risler
*/
class ActionOption : public ActionBehavior
{
public:
/**
* Constructor.
* @param time The system time in ms.
*/
ActionOption(const unsigned& time) :
ActionBehavior(time),
option(0)
{}
Option* option;
virtual const Behavior* getBehavior() const;
virtual Behavior* getBehavior();
};
/**
* @class ActionDecimalOutputSymbol
*
* Represents an action execution, in this case a decimal output symbol assignment
*
* @author Max Risler
*/
class ActionDecimalOutputSymbol : public Action
{
public:
/**
* Constructor.
* @param time The system time in ms.
*/
ActionDecimalOutputSymbol(const unsigned& time) :
Action(time),
decimalOutputSymbol(0),
decimalOutputSymbolExpression(0),
decimalOutputSymbolValue(0)
{}
/** Destructor */
~ActionDecimalOutputSymbol();
/** A decimal output symbol that is set if the state is active, null when a behavior is executed or another output symbol is set */
DecimalOutputSymbol* decimalOutputSymbol;
/** The expression for the decimal output symbol that is set if the state is active */
const DecimalExpression* decimalOutputSymbolExpression;
/** Current decimal output symbol value, this is stored just for debugging purposes */
double decimalOutputSymbolValue;
/** Execute the behavior */
virtual void execute();
};
/**
* @class ActionBooleanOutputSymbol
*
* Represents an action execution, in this case a boolean output symbol assignment
*
* @author Max Risler
*/
class ActionBooleanOutputSymbol : public Action
{
public:
/**
* Constructor.
* @param time The system time in ms.
*/
ActionBooleanOutputSymbol(const unsigned& time) :
Action(time),
booleanOutputSymbol(0),
booleanOutputSymbolExpression(0),
booleanOutputSymbolValue(false)
{}
/** Destructor */
~ActionBooleanOutputSymbol();
/** A boolean output symbol that is set if the state is active, null when a behavior is executed or another output symbol is set */
BooleanOutputSymbol* booleanOutputSymbol;
/** The expression for the boolean output symbol that is set if the state is active */
const BooleanExpression* booleanOutputSymbolExpression;
/** Current boolean output symbol value, this is stored just for debugging purposes */
bool booleanOutputSymbolValue;
/** Execute the behavior */
virtual void execute();
};
/**
* @class ActionEnumeratedOutputSymbol
*
* Represents an action execution, in this case an enumerated output symbol assignment
*
* @author Max Risler
*/
class ActionEnumeratedOutputSymbol : public Action
{
public:
/**
* Constructor.
* @param time The system time in ms.
*/
ActionEnumeratedOutputSymbol(const unsigned& time) :
Action(time),
enumeratedOutputSymbol(0),
enumeratedOutputSymbolExpression(0),
enumeratedOutputSymbolValue(0)
{}
/** Destructor */
~ActionEnumeratedOutputSymbol();
/** An enumerated output symbol that is set if the state is active, null when a behavior is executed or another output symbol is set */
EnumeratedOutputSymbol* enumeratedOutputSymbol;
/** The expression for the enumerated output symbol that is set if the state is active */
const EnumeratedExpression* enumeratedOutputSymbolExpression;
/** Current enumerated output symbol value, this is stored just for debugging purposes */
int enumeratedOutputSymbolValue;
/** Execute the behavior */
virtual void execute();
};
} // namespace
#endif //__XabslAction_h_

View File

@ -0,0 +1,27 @@
/**
* @file XabslAgent.cpp
*
* Implementation of class Agent
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
#include "XabslAgent.h"
namespace xabsl
{
Agent::Agent(const char* name, Behavior* rootOption,
ErrorHandler& errorHandler, int index)
: NamedItem(name), rootOption(rootOption), errorHandler(errorHandler), index(index)
{
XABSL_DEBUG_INIT(errorHandler.message("created agent \"%s\" with root option \"%s\"", n, rootOption->n));
}
Behavior* Agent::getRootOption() const
{
return rootOption;
}
} // namespace

View File

@ -0,0 +1,54 @@
/**
* @file XabslAgent.h
*
* Definition of class Agent
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
#ifndef __XabslAgent_h_
#define __XabslAgent_h_
#include "XabslBehavior.h"
#include "XabslTools.h"
namespace xabsl
{
/**
* @class Agent
*
* Combines some options to an agent
*
* @author Martin Loetzsch
*/
class Agent : public NamedItem
{
public:
/**
* Constructor
* @param name The name of the agent
* @param rootOption A pointer to the initial option of the agent
* @param errorHandler Is invoked when errors occur
* @param index Index of the agent in array agents in corresponding engine
*/
Agent(const char* name, Behavior* rootOption,
ErrorHandler& errorHandler, int index);
/** Returns the root option */
Behavior* getRootOption() const;
private:
/** A pointer to the root option */
Behavior* rootOption;
/** Is invoked when errors occur */
ErrorHandler& errorHandler;
/** Index of the agent in array agents in corresponding engine */
int index;
};
} // namespace
#endif // __XabslAgent_h_

View File

@ -0,0 +1,396 @@
/**
* @file XabslArray.h
*
* Declaration and implementation of template class NamedArray
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
* @author <a href="http://www.tzi.de/~roefer/">Thomas Ršfer</a>
*/
#ifndef __XabslArray_h_
#define __XabslArray_h_
#include <stdlib.h>
#include <string.h>
namespace xabsl
{
/**
* @class NamedItem
* A class that has a text label
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class NamedItem
{
public:
/**
* Constructor
* @param name The name of the item
*/
NamedItem(const char* name)
{
n = new char[strlen(name)+1];
strcpy(n,name);
}
/** Destructor. Deletes the name */
virtual ~NamedItem() { delete[] n; }
/** The text label */
char* n;
};
/**
* An element of an NamedArray.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
* @author <a href="http://www.tzi.de/~roefer/">Thomas Ršfer</a>
*/
template<class T> class NamedArrayElement : public NamedItem
{
public:
/**
* Constructor.
* @param name A string label for the element.
* @param element The new element.
*/
NamedArrayElement(const char* name, T element)
: NamedItem(name), e(element) {}
/**
* Destructor. If the element is a pointer, it has to be
* deleted externally
*/
virtual ~NamedArrayElement() {}
/** The element */
T e;
};
/**
* The class implements a dynamic array.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
* @author <a href="http://www.tzi.de/~roefer/">Thomas Ršfer</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
template <class T> class Array
{
public:
/** Constructor */
Array()
{
usedSize = 0;
allocatedSize = 2;
data = new T[allocatedSize];
}
/** Destructor */
virtual ~Array()
{
delete[] data;
}
/** Assignment operator
*\param other The other Array that is assigned to this one
*\return A reference to this object after the assignment.
*/
Array<T>& operator=(const Array<T>& other)
{
delete[] data;
usedSize = other.usedSize;
allocatedSize = other.allocatedSize;
data = new T[allocatedSize];
for (int i = 0; i < usedSize; ++i)
data[i]=other.data[i];
return *this;
}
/** Copy constructor
*\param other The other vector that is copied to this one
*/
Array(const Array<T>& other)
{
data = new T[0];
*this = other;
}
/** Clears the array */
void clear()
{
delete[] data;
usedSize = 0;
allocatedSize = 2;
data = new T[allocatedSize];
}
/**
* Returns the value for a given array position.
* Note that the function crashes if the required position is bigger than the
* size of the array.
*/
T getElement(int pos) const
{
return data[pos];
}
/**
* The function appends a new element to the array.
* @param element The new element.
*/
void append(T element)
{
if(usedSize == allocatedSize)
{
allocatedSize += allocatedSize / 2; // note that allocatedSize must be at least 2
T* temp = new T[allocatedSize];
for(int i = 0; i < getSize(); ++i)
temp[i] = data[i];
delete[] data;
data = temp;
}
data[usedSize++] = element;
}
/**
* The function sets the value of an element in the array.
* Note that the function crashes if the element does not exist.
* @param pos The position of the element in the array.
* @param value The new element.
*/
void setElement(int pos, T value)
{
data[pos] = value;
}
/**
* The function returns the number of elements in the array.
* @return The length of the list.
*/
int getSize() const {return usedSize;}
/**
* Returns the value for a given array position.
* Note that the function crashes if the required position is bigger than the
* size of the array.
*/
const T& operator[](int pos) const
{
return data[pos];
}
T& operator[](int pos)
{
while (pos >= usedSize) append(T());
return data[pos];
}
/** Removes the last element of the array */
void removeLast()
{
if (usedSize > 0)
usedSize--;
}
operator Array<const T>&() {return this;}
protected:
/** The array */
T* data;
/** The number of elements in the array */
int usedSize, allocatedSize;
};
/**
* The class implements a dynamic array. Each array element can have a text label.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
* @author <a href="http://www.tzi.de/~roefer/">Thomas Ršfer</a>
*/
template <class T> class NamedArray : public Array<NamedArrayElement<T>*>
{
public:
/** Destructor */
virtual ~NamedArray()
{
for(int i = 0; i < this->getSize(); ++i)
delete this->data[i];
}
/** Assignment operator
*\param other The other NamedArray that is assigned to this one
*\return A reference to this object after the assignment.
*/
NamedArray<T>& operator=(const NamedArray<T>& other)
{
for(int i = 0; i < this->usedSize; ++i)
delete this->data[i];
delete[] this->data;
this->usedSize = other.usedSize;
this->allocatedSize = other.allocatedSize;
this->data = new T[this->allocatedSize];
for (int i = 0; i < this->usedSize; ++i)
this->data[i]=new NamedArrayElement<T>(other.data[i]->n,other.data[i]->e);
return *this;
}
/** Clears the array */
void clear()
{
for(int i = 0; i < this->getSize(); ++i)
delete this->data[i];
Array<NamedArrayElement<T>*>::clear();
}
/**
* Returns the value for a given name.
* If no element exists for the name, the default value is returned.
* @param name The name element
* @param defaultValue The value that is returned if no element exists for the name.
* @return Either the element found or the default value.
*/
T getElement(const char* name, T defaultValue) const
{
int pos = find(name);
if(pos < 0)
return defaultValue;
else
return getElement(pos)->e;
}
/**
* Returns the value for a given name.
* Note that the function crashes if the element does not exist.
* @param name The name of the element
*/
T& getElement(const char* name) const
{
return getElement(find(name));
}
/**
* Returns the value for a given array position.
* Note that the function crashes if the required position is bigger than the
* size of the array.
*/
T& getElement(int pos) const
{
return this->data[pos]->e;
}
/**
* Returns a pointer to the array element for a given name.
* Note that the function crashes if the element does not exist
* @param name the name of the element
*/
NamedArrayElement<T>* getPElement(const char* name)
{
return this->data[find(name)];
}
/** Returns the name of an element */
const char* getName(int pos) const
{
return this->data[pos]->n;
}
/**
* The function appends a new element to the array.
* @param name A string label for the element.
* @param element The new element.
*/
void append(const char* name, T element)
{
Array<NamedArrayElement<T>*>::append(new NamedArrayElement<T>(name,element));
}
void append(T element)
{
append("",element);
}
/**
* The function sets the value of an element in the array.
* Note that the function crashes if the element does not exist.
* @param name A string label for the element.
* @param value The new element.
*/
void setElement(const char* name, T value)
{
setElement(find(name),value);
}
/**
* The function sets the value of an element in the array.
* Note that the function crashes if the element does not exist.
* @param pos The position of the element in the array.
* @param value The new element.
*/
void setElement(int pos, T value)
{
this->data[pos]->e = value;
}
/**
* Returns the value for a given array position.
* Note that the function crashes if the required position is bigger than the
* size of the array.
*/
T operator[](int pos) const
{
return getElement(pos);
}
/**
* Returns the value for a given name.
* Note that the function crashes if the element does not exist.
* @param name The name of the element
*/
T operator[](const char* name) const
{
return getElement(name);
}
/** Returns whether an element for the given name exists */
bool exists(const char* name) const
{
return find(name) >= 0;
}
/** Removes the last element of the array */
void removeLast()
{
if (this->usedSize > 0)
delete this->data[--this->usedSize];
}
protected:
/**
* Returns the index of an element with the given name.
* @param name The name that is searched for.
* @return The index of the element of -1 if the name does not exist.
*/
int find(const char* name) const
{
for(int i = 0; i < this->getSize(); ++i)
if(!strcmp(getName(i),name))
return i;
return -1;
}
};
} // namespace
#endif // __XabslArray_h_

View File

@ -0,0 +1,59 @@
/**
* @file XabslBasicBehavior.h
*
* Declaration class BasicBehavior
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
*/
#ifndef __XabslBasicBehavior_h_
#define __XabslBasicBehavior_h_
#include "XabslTools.h"
#include "XabslBehavior.h"
namespace xabsl
{
/**
* The base class for basic behaviors that are used by the Engine
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
*/
class BasicBehavior : public Behavior
{
public:
/**
* Constructor
* @param name The name of the basic behavior
* @param errorHandler A reference to the error handler
*/
BasicBehavior(const char* name, ErrorHandler& errorHandler)
: Behavior(name), index(-1)
{
parameters = new Parameters(errorHandler);
};
/** Destructor */
virtual ~BasicBehavior()
{
delete parameters;
}
/** Registers the parameters. */
virtual void registerParameters() {}
/** Index of the basic behavior in array basicBehaviors in corresponding engine */
int index;
};
} // namespace
#endif // __XabslBasicBehavior_h_

View File

@ -0,0 +1,72 @@
/**
* @file XabslBehavior.h
*
* Definition of class Behavior
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslBehavior_h_
#define __XabslBehavior_h_
#include "XabslArray.h"
#include "XabslSymbols.h"
namespace xabsl
{
/**
* @class Behavior
*
* Parent class for Option and BasicBehavior
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class Behavior : public NamedItem
{
public:
/**
* Constructor.
* @param name The name of the behavior. For debugging purposes.
*/
Behavior(const char* name) :
NamedItem(name),
isActive(false),
wasActive(false),
timeOfExecution(0),
timeWhenActivated(0),
parameters(0)
{};
/**
* Destructor
*/
virtual ~Behavior() {};
/** the behavior is activated in the current path through the option graph */
bool isActive;
/** the behavior was activated in the last path trough the option graph */
bool wasActive;
/**
* executes the behavior
*/
virtual void execute() = 0;
/** the time how long the option is already active */
unsigned timeOfExecution;
/** The time, when the option was activated */
unsigned timeWhenActivated;
/** The parameters of the behavior */
Parameters* parameters;
/** Notify the software environment about a parameter change */
virtual void parametersChanged() {};
};
} // namespace
#endif //__XabslBehavior_h_

View File

@ -0,0 +1,477 @@
/**
* @file XabslBooleanExpression.cpp
*
* Implementation of BooleanExpression and derivates
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslBooleanExpression.h"
#include "XabslOption.h"
namespace xabsl
{
BooleanExpression::~BooleanExpression()
{
}
BooleanExpression* BooleanExpression::create(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
char c[100];
BooleanExpression* booleanOperand = 0;
DecimalExpression* decimalOperand1 = 0;
DecimalExpression* decimalOperand2 = 0;
RelationalAndEqualityOperator* relationalAndEqualityOperator = 0;
input.readString(c,1);
switch (*c)
{
case 'v':
return new BooleanValue(input,errorHandler);
case 'p':
return new BooleanOptionParameterRef(input,errorHandler,option);
case 'i':
return new BooleanInputSymbolRef(input,errorHandler,symbols,option,state);
case 'o':
return new BooleanOutputSymbolRef(input,errorHandler,symbols);
case 't':
return new SubsequentOptionReachedTargetStateCondition(errorHandler, state);
case 'c':
return new EnumeratedInputSymbolComparison(input, errorHandler, symbols, option, state);
case '&':
{
XABSL_DEBUG_INIT(errorHandler.message("creating and operator"));
int numberOfOperands = (int)input.readValue();
AndOperator* andOperator = new AndOperator();
for (int i=0; i<numberOfOperands; i++)
{
if (!BooleanExpression::createOperand(booleanOperand, input, errorHandler, symbols, option, state))
{
delete andOperator;
return 0;
}
andOperator->addOperand(booleanOperand);
}
return andOperator;
}
case '|':
{
XABSL_DEBUG_INIT(errorHandler.message("creating or operator"));
int numberOfOperands = (int)input.readValue();
OrOperator* orOperator = new OrOperator();
for (int i=0; i<numberOfOperands; i++)
{
if (!BooleanExpression::createOperand(booleanOperand, input, errorHandler, symbols, option, state))
{
delete orOperator;
return 0;
}
orOperator->addOperand(booleanOperand);
}
return orOperator;
}
case '!':
XABSL_DEBUG_INIT(errorHandler.message("creating not operator"));
if (!BooleanExpression::createOperand(booleanOperand, input, errorHandler, symbols, option, state))
return 0;
return new NotOperator(booleanOperand);
case '=':
XABSL_DEBUG_INIT(errorHandler.message("creating == operator"));
if (!DecimalExpression::createOperand(decimalOperand1,input, errorHandler, symbols, option, state))
return 0;
if (!DecimalExpression::createOperand(decimalOperand2,input, errorHandler, symbols, option, state))
return 0;
relationalAndEqualityOperator = new EqualToOperator();
relationalAndEqualityOperator->create(decimalOperand1,decimalOperand2);
return relationalAndEqualityOperator;
case 'n':
XABSL_DEBUG_INIT(errorHandler.message("creating != operator"));
if (!DecimalExpression::createOperand(decimalOperand1,input,errorHandler,symbols,option,state))
return 0;
if (!DecimalExpression::createOperand(decimalOperand2,input,errorHandler,symbols,option,state))
return 0;
relationalAndEqualityOperator = new NotEqualToOperator();
relationalAndEqualityOperator->create(decimalOperand1,decimalOperand2);
return relationalAndEqualityOperator;
case '<':
XABSL_DEBUG_INIT(errorHandler.message("creating < operator"));
if (!DecimalExpression::createOperand(decimalOperand1,input,errorHandler,symbols,option,state))
return 0;
if (!DecimalExpression::createOperand(decimalOperand2,input,errorHandler,symbols,option,state))
return 0;
relationalAndEqualityOperator = new LessThanOperator();
relationalAndEqualityOperator->create(decimalOperand1,decimalOperand2);
return relationalAndEqualityOperator;
case 'l':
XABSL_DEBUG_INIT(errorHandler.message("creating <= operator"));
if (!DecimalExpression::createOperand(decimalOperand1,input,errorHandler, symbols, option, state))
return 0;
if (!DecimalExpression::createOperand(decimalOperand2,input,errorHandler, symbols, option, state))
return 0;
relationalAndEqualityOperator = new LessThanOrEqualToOperator();
relationalAndEqualityOperator->create(decimalOperand1,decimalOperand2);
return relationalAndEqualityOperator;
case '>':
XABSL_DEBUG_INIT(errorHandler.message("creating > operator"));
if (!DecimalExpression::createOperand(decimalOperand1,input,errorHandler, symbols, option, state))
return 0;
if (!DecimalExpression::createOperand(decimalOperand2,input,errorHandler, symbols, option, state))
return 0;
relationalAndEqualityOperator = new GreaterThanOperator();
relationalAndEqualityOperator->create(decimalOperand1,decimalOperand2);
return relationalAndEqualityOperator;
case 'g':
XABSL_DEBUG_INIT(errorHandler.message("creating >= operator"));
if (!DecimalExpression::createOperand(decimalOperand1,input,errorHandler, symbols, option, state))
return 0;
if (!DecimalExpression::createOperand(decimalOperand2,input,errorHandler, symbols, option, state))
return 0;
relationalAndEqualityOperator = new GreaterThanOrEqualToOperator();
relationalAndEqualityOperator->create(decimalOperand1,decimalOperand2);
return relationalAndEqualityOperator;
case 'x':
return new ConflictCondition(errorHandler, state);
default:
errorHandler.error("XabslBooleanExpression::create(): unknown expression type \"%c\"",*c);
}
return 0;
}
bool BooleanExpression::createOperand(BooleanExpression*& operand,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
operand = BooleanExpression::create(input,errorHandler,symbols,option,state);
if (operand == 0)
{
errorHandler.error("XabslBooleanExpression::createOperand(): created operand is 0");
return false;
}
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslBooleanExpression::createOperand(): could not create operand");
if (operand != 0) delete operand;
return false;
}
return true;
}
BooleanValue::BooleanValue(InputSource& input,
ErrorHandler& errorHandler)
{
char buf[6];
input.readString(buf,5);
value = (strcmp("true",buf) == 0);
XABSL_DEBUG_INIT(errorHandler.message("created boolean value: \"%s\"",value?"true":"false"));
}
bool BooleanValue::getValue() const
{
return value;
}
BooleanOptionParameterRef::BooleanOptionParameterRef(InputSource& input,
ErrorHandler& errorHandler,
Option& option)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to boolean option parameter \"%s\"",buf));
if (!option.parameters->boolean.exists(buf))
{
errorHandler.error("XabslBooleanOptionParameterRef::BooleanOptionParameterRef(): boolean option parameter \"%s\" does not exist",buf);
return;
}
parameter = option.parameters->boolean.getPElement(buf)->e;
}
bool BooleanOptionParameterRef::getValue() const
{
return *parameter;
}
AndOperator::AndOperator()
{
operands.clear();
}
AndOperator::~AndOperator()
{
for (int i=0; i< operands.getSize(); i++)
{
if (operands[i]!=0) delete operands[i];
}
}
bool AndOperator::getValue() const
{
for (int i=0; i< operands.getSize(); i++)
{
if (operands[i]->getValue() == false) return false;
}
return true;
}
void AndOperator::addOperand(BooleanExpression* operand)
{
operands.append(operand);
}
OrOperator::OrOperator()
{
operands.clear();
}
OrOperator::~OrOperator()
{
for (int i=0; i< operands.getSize(); i++)
{
if (operands[i]!=0) delete operands[i];
}
}
bool OrOperator::getValue() const
{
for (int i=0; i< operands.getSize(); i++)
{
if (operands[i]->getValue() == true) return true;
}
return false;
}
void OrOperator::addOperand(BooleanExpression* operand)
{
operands.append(operand);
}
NotOperator::NotOperator(BooleanExpression* operand1) :
operand1(operand1)
{
}
NotOperator::~NotOperator()
{
if (operand1!=0) delete operand1;
}
bool NotOperator::getValue() const
{
return !(operand1->getValue());
}
BooleanInputSymbolRef::BooleanInputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state) :
symbol(0), parameters(0)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating reference to boolean input symbol \"%s\"",buf));
if (!symbols.booleanInputSymbols.exists(buf))
{
errorHandler.error("XabslBooleanInputSymbolRef::XabslBooleanInputSymbolRef(): boolean input symbol \"%s\" was not registered at the engine",buf);
return;
}
symbol = symbols.booleanInputSymbols[buf];
parameters = new ParameterAssignment(&symbol->parameters, errorHandler);
parameters->create(input, symbols, option, state);
}
BooleanInputSymbolRef::~BooleanInputSymbolRef()
{
if (parameters != 0)
delete parameters;
}
bool BooleanInputSymbolRef::getValue() const
{
// set the symbol parameters
if (parameters->set())
symbol->parametersChanged();
return symbol->getValue();
}
BooleanOutputSymbolRef::BooleanOutputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to a boolean output symbol \"%s\"",buf));
if (!symbols.booleanOutputSymbols.exists(buf))
{
errorHandler.error("XabslBooleanOutputSymbolRef::BooleanOutputSymbolRef(): boolean output symbol \"%s\" was not registered",buf);
return;
}
symbol = symbols.booleanOutputSymbols[buf];
}
bool BooleanOutputSymbolRef::getValue() const
{
return symbol->getValue();
}
SubsequentOptionReachedTargetStateCondition::SubsequentOptionReachedTargetStateCondition(
ErrorHandler& errorHandler,
State& state)
: state(state)
{
XABSL_DEBUG_INIT(errorHandler.message("creating a \"subsequent-option-reached-target-state\" element"));
}
bool SubsequentOptionReachedTargetStateCondition::getValue() const
{
bool anySubsequentBehaviorReachedTargetState = false;
for (int i = 0; i < state.actions.getSize(); i++)
if (ActionOption* subsequentAction = dynamic_cast<ActionOption*>(state.actions[i]))
if (subsequentAction->option->getOptionReachedATargetState())
anySubsequentBehaviorReachedTargetState = true;
return anySubsequentBehaviorReachedTargetState;
}
ConflictCondition::ConflictCondition(
ErrorHandler& errorHandler,
State& state)
: state(state)
{
XABSL_DEBUG_INIT(errorHandler.message("creating a \"conflict\" element"));
}
bool ConflictCondition::getValue() const
{
return state.getConflict();
}
EnumeratedInputSymbolComparison::EnumeratedInputSymbolComparison(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
if (!EnumeratedExpression::createOperand(operand1,NULL,input,errorHandler,symbols,option,state))
{
errorHandler.error("XabslEnumeratedInputSymbolComparison::EnumeratedInputSymbolComparison(): could not create enumerated expression");
operand1 = operand2 = 0;
return;
}
if (!EnumeratedExpression::createOperand(operand2,operand1->enumeration,input,errorHandler,symbols,option,state))
{
errorHandler.error("XabslEnumeratedInputSymbolComparison::EnumeratedInputSymbolComparison(): could not create enumerated expression");
operand2 = 0;
return;
}
}
EnumeratedInputSymbolComparison::~EnumeratedInputSymbolComparison()
{
if (operand1!=0) delete operand1;
if (operand2!=0) delete operand2;
}
bool EnumeratedInputSymbolComparison::getValue() const
{
return (operand1->getValue() == operand2->getValue());
}
void RelationalAndEqualityOperator::create(DecimalExpression* operand1,
DecimalExpression* operand2)
{
this->operand1 = operand1;
this->operand2 = operand2;
}
RelationalAndEqualityOperator ::~RelationalAndEqualityOperator ()
{
if (operand1!=0) delete operand1;
if (operand2!=0) delete operand2;
}
bool EqualToOperator::getValue() const
{
return (operand1->getValue() == operand2->getValue());
}
bool NotEqualToOperator::getValue() const
{
return (operand1->getValue() != operand2->getValue());
}
bool LessThanOperator::getValue() const
{
return (operand1->getValue() < operand2->getValue());
}
bool LessThanOrEqualToOperator::getValue() const
{
return (operand1->getValue() <= operand2->getValue());
}
bool GreaterThanOperator::getValue() const
{
return (operand1->getValue() > operand2->getValue());
}
bool GreaterThanOrEqualToOperator::getValue() const
{
return (operand1->getValue() >= operand2->getValue());
}
} // namespace

View File

@ -0,0 +1,495 @@
/**
* @file XabslBooleanExpression.h
*
* Definition of BooleanExpression and derivates
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslBooleanExpression_h_
#define __XabslBooleanExpression_h_
#include "XabslDecimalExpression.h"
namespace xabsl
{
/**
* @class BooleanExpression
*
* Base class for all boolean expressions inside an option graph.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class BooleanExpression
{
public:
/** Evaluates the boolean expression. */
virtual bool getValue() const = 0;
/**
* Creates a boolean expression depending on the input.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a boolean expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
static BooleanExpression* create(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
virtual ~BooleanExpression() = 0;
/**
* Creates a boolean expression depending on the input.
* Uses the create() function to create boolean operands.
* @param operand The expression to be created
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a boolean operand starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
* @return If the creation was successful
*/
static bool createOperand(
BooleanExpression*& operand,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
};
/**
* @class BooleanValue
*
* Represents a boolean value.
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class BooleanValue : public BooleanExpression
{
public:
/**
* Constructor. Creates the value
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a value starts.
* @param errorHandler A reference to a ErrorHandler instance
*/
BooleanValue(InputSource& input,
ErrorHandler& errorHandler);
/**
* Constructor. Creates an expression for a fixed boolean value
* @param value The boolean value
*/
BooleanValue(bool value) : value(value) {}
/** Calculates the value of the decimal expression. */
virtual bool getValue() const;
private:
/** The value */
bool value;
};
/**
* @class BooleanOptionParameterRef
*
* Represents a reference to a decimal option parameter.
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class BooleanOptionParameterRef : public BooleanExpression
{
public:
/**
* Constructor. Creates the reference
* @param input An input source for the intermediate code. It must be opened and read until
* A position where the expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param option The current option
*/
BooleanOptionParameterRef(InputSource& input,
ErrorHandler& errorHandler,
Option& option);
/** Calculates the value of the boolean expression. */
virtual bool getValue() const;
private:
/** A pointer to the parameter */
bool* parameter;
};
/**
* @class AndOperator
*
* Represents an 'and' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class AndOperator : public BooleanExpression
{
public:
/** Constructor */
AndOperator();
/** Destructor. Deletes the two operands */
~AndOperator();
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
/** Adds an operand to the operands array */
void addOperand(BooleanExpression* operand);
private:
/** the 2+n operands of the operator */
Array<BooleanExpression*> operands;
};
/**
* @class OrOperator
*
* Represents an 'or' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class OrOperator : public BooleanExpression
{
public:
/** Constructor */
OrOperator();
/** Destructor. Deletes the two operands */
~OrOperator();
/** Evaluates the boolean expression. */
virtual bool getValue() const;
/** Adds an operand to the operands array */
void addOperand(BooleanExpression* operand);
private:
/** the 2+n operands of the operator */
Array<BooleanExpression*> operands;
};
/**
* @class NotOperator
*
* Represents an 'not' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class NotOperator : public BooleanExpression
{
public:
/**
* Constructor. Creates the element.
* @param operand1 A boolean expression
*/
NotOperator(BooleanExpression* operand1);
/** Destructor. Deletes the operand */
~NotOperator();
/** Evaluates the boolean expression. */
virtual bool getValue() const;
private:
/** operand 1 */
BooleanExpression* operand1;
};
/**
* @class BooleanInputSymbolRef
*
* Represents an 'boolean-input-symbol-ref' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class BooleanInputSymbolRef : public BooleanExpression
{
public:
/**
* Constructor. Creates the element
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
BooleanInputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
~BooleanInputSymbolRef();
/** Evaluates the boolean expression. */
virtual bool getValue() const;
private:
/** The referenced symbol */
BooleanInputSymbol* symbol;
/** The parameter assignments of the referenced symbol */
ParameterAssignment* parameters;
};
/**
* @class BooleanOutputSymbolRef
*
* Represents a reference to a boolean input symbol.
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class BooleanOutputSymbolRef : public BooleanExpression
{
public:
/** Calculates the value of the boolean expression. */
virtual bool getValue() const;
/**
* Constructor. Creates the function call depending on the input.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where the function reference starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
*/
BooleanOutputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols);
private:
/** The referenced symbol */
BooleanOutputSymbol* symbol;
};
/**
* @class SubsequentOptionReachedTargetStateCondition
*
* Represents an 'subsequent-option-reached-target-state' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class SubsequentOptionReachedTargetStateCondition : public BooleanExpression
{
public:
/**
* Constructor. Creates the element.
* @param errorHandler A reference to a ErrorHandler instance
* @param state The current state
*/
SubsequentOptionReachedTargetStateCondition(
ErrorHandler& errorHandler,
State& state);
/** Evaluates the boolean expression. */
virtual bool getValue() const;
private:
/** The state */
State& state;
};
/**
* @class ConflictCondition
*
* Represents an 'conflict' element of the option graph
*
* @author Max Risler
*/
class ConflictCondition : public BooleanExpression
{
public:
/**
* Constructor. Creates the element.
* @param errorHandler A reference to a ErrorHandler instance
* @param state The current state
*/
ConflictCondition(
ErrorHandler& errorHandler,
State& state);
/** Evaluates the boolean expression. */
virtual bool getValue() const;
private:
/** The state */
State& state;
};
/**
* @class EnumeratedInputSymbolComparison
*
* Represents an 'enumerated-input-symbol-comparison' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class EnumeratedInputSymbolComparison : public BooleanExpression
{
public:
/**
* Constructor. Creates the element
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
EnumeratedInputSymbolComparison(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor. Deletes the two operands */
~EnumeratedInputSymbolComparison();
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
protected:
/** operand 1 */
const EnumeratedExpression* operand1;
/** operand 2 */
const EnumeratedExpression* operand2;
};
/**
* @class RelationalAndEqualityOperator
*
* Base class for the operators <, <=, >, >=, == and !=
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class RelationalAndEqualityOperator : public BooleanExpression
{
public:
/**
* Creates the element.
* @param operand1 A decimal expression
* @param operand2 A decimal expression
*/
void create(DecimalExpression* operand1,
DecimalExpression* operand2);
/** Destructor. Deletes the two operands */
~RelationalAndEqualityOperator();
/** Evaluates the boolean expression.*/
virtual bool getValue() const = 0;
protected:
/** operand 1 */
DecimalExpression* operand1;
/** operand 2 */
DecimalExpression* operand2;
};
/**
* @class EqualToOperator
*
* Represents an 'equal-to' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class EqualToOperator : public RelationalAndEqualityOperator
{
public:
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
};
/**
* @class NotEqualToOperator
*
* Represents an 'not-equal-to' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class NotEqualToOperator : public RelationalAndEqualityOperator
{
public:
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
};
/**
* @class LessThanOperator
*
* Represents an 'less-than' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class LessThanOperator : public RelationalAndEqualityOperator
{
public:
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
};
/**
* @class LessThanOrEqualToOperator
*
* Represents an 'less-than-or-equal-to' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class LessThanOrEqualToOperator : public RelationalAndEqualityOperator
{
public:
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
};
/**
* @class GreaterThanOperator
*
* Represents an 'greater-than' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class GreaterThanOperator : public RelationalAndEqualityOperator
{
public:
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
};
/**
* @class GreaterThanOrEqualToOperator
*
* Represents an 'greater-than-or-equal-to' element of the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class GreaterThanOrEqualToOperator : public RelationalAndEqualityOperator
{
public:
/** Evaluates the boolean expression.*/
virtual bool getValue() const;
};
} // namespace
#endif //__XabslBooleanExpression_h_

View File

@ -0,0 +1,238 @@
/**
* @file XabslCoopState.h
*
* Definition of class CoopState and Helper classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslCoopState_h_
#define __XabslCoopState_h_
#include "XabslState.h"
namespace xabsl
{
/**
* @class CoopState
*
* Represents a state which has features to connect to other cooperating agents
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class CoopState : public State
{
public:
/**
* Constructor. Does not create the state.
* @param name The name of the state. For debugging purposes.
* @param errorHandler A reference to a ErrorHandler instance
* @param time The system time in ms.
* @param optionIndex Index of the corresponding option this state belongs to
* @param index Index of the state in array states in corresponding option
* @param agentPriority Priority value of the agent, used for solving conflicts in cooperative state assignment
* @param synchronizationTicks Number of execution cycles that is required for synchonization with other agents, i.e time from sending a message until answer is received
*/
CoopState(const char* name,
ErrorHandler& errorHandler,
const unsigned& time,
int optionIndex,
int index,
const int& agentPriority,
const int& synchronizationTicks) :
State(name, errorHandler, time, optionIndex, index),
numberOfAgentsExecuting(0),
numberOfAgentsEntering(0),
numberOfAgentsInOption(0),
highestPriorityOfAgentsEntering(0),
entering(false),
enterCount(0),
agentPriority(agentPriority),
synchronizationTicks(synchronizationTicks)
{};
/** Number of other agents currently executing this state, not including myself */
int numberOfAgentsExecuting;
/** Number of other agents currently trying to execute this state, but are blocked due to cooperating agents, not including myself */
int numberOfAgentsEntering;
/** Number of other agents currently executing the option corresponding to this state, not including myself */
int numberOfAgentsInOption;
/** Highest priority values of agents currently entering this state, not including myself */
int highestPriorityOfAgentsEntering;
/** Flag whether the agent is currently trying to execute this state, but is blocked due to cooperating agents */
bool entering;
/** Counter for number of cycles that the enter flag of this state is set */
int enterCount;
/** Priority value of the agent, used for solving conflicts in cooperative state assignment */
const int &agentPriority;
/** Number of execution cycles that is required for synchonization with other agents, i.e time from sending a message until answer is received */
const int &synchronizationTicks;
/** Prepare for processing incoming team messages. This resets previously processed messages. */
void prepareIncomingMessages()
{
numberOfAgentsExecuting = numberOfAgentsEntering = numberOfAgentsInOption = 0;
if (entering)
enterCount++;
else
enterCount = 0;
entering = false;
}
};
/**
* @class SynchronizedState
*
* Represents a state which can only be entered by all agents simultaneously
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class SynchronizedState : public CoopState
{
public:
/**
* Constructor. Does not create the state.
* @param name The name of the state. For debugging purposes.
* @param errorHandler A reference to a ErrorHandler instance
* @param time The system time in ms.
* @param optionIndex Index of the corresponding option this state belongs to
* @param index Index of the state in array states in corresponding option
* @param agentPriority Priority value of the agent, used for solving conflicts in cooperative state assignment
* @param synchronizationTicks Number of execution cycles that is required for synchonization with other agents, i.e time from sending a message until answer is received
*/
SynchronizedState(const char* name,
ErrorHandler& errorHandler,
const unsigned& time,
int optionIndex,
int index,
const int& agentPriority,
const int& synchronizationTicks,
int minAgents) :
CoopState(name, errorHandler, time, optionIndex, index, agentPriority, synchronizationTicks), minAgents(minAgents)
{};
/** Minimum number of agents that have to enter the state at once */
int minAgents;
/** Check whether this state can be entered, or whether entering is blocked due to cooperating agents */
virtual bool coopCheck()
{
entering = true;
return (numberOfAgentsInOption >= minAgents &&
numberOfAgentsExecuting + numberOfAgentsEntering == numberOfAgentsInOption &&
enterCount > synchronizationTicks / 2);
}
};
/**
* @class CapacityState
*
* Represents a state which can only be entered by at most the given number of agents simultaneously
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class CapacityState : public CoopState
{
public:
/**
* Constructor. Does not create the state.
* @param name The name of the state. For debugging purposes.
* @param errorHandler A reference to a ErrorHandler instance
* @param time The system time in ms.
* @param optionIndex Index of the corresponding option this state belongs to
* @param index Index of the state in array states in corresponding option
* @param agentPriority Priority value of the agent, used for solving conflicts in cooperative state assignment
* @param synchronizationTicks Number of execution cycles that is required for synchonization with other agents, i.e time from sending a message until answer is received
* @param capacity Number of agents that can enter the state simultaneously
*/
CapacityState(const char* name,
ErrorHandler& errorHandler,
const unsigned& time,
int optionIndex,
int index,
const int& agentPriority,
const int& synchronizationTicks,
int capacity) :
CoopState(name, errorHandler, time, optionIndex, index, agentPriority, synchronizationTicks), capacity(capacity), conflict(false)
{};
/** Number of agents that can enter the state simultaneously */
int capacity;
/** Whether this state is currently conflicted, i.e. there are more robots executing than the given capacity.*/
bool conflict;
/** Whether this state is currently conflicted, i.e. there are more robots executing than the given capacity.*/
virtual bool getConflict()
{
return conflict;
}
/**
* Executes the decision tree and determines the next active state (can be the same).
*/
virtual State* getNextState()
{
conflict = numberOfAgentsExecuting >= capacity;
//if (conflict)
//{
// errorHandler.message("xabsl::CapacityState::getNextState(): Conflict detected in capacity state \"%s\". Number of agents executing is %d while the capacity is %d. Number of synchronization ticks might need to be increased; current value is %d.",n,numberOfAgentsExecuting,capacity,synchronizationTicks);
//}
return CoopState::getNextState();
}
/** Check whether this state can be entered, or whether entering is blocked due to cooperating agents */
virtual bool coopCheck()
{
//if (numberOfAgentsInOption < capacity)
//{
// // no potential conflict for state capacity => enter state
// return true;
//}
//else
if (numberOfAgentsExecuting >= capacity)
{
// state is currently busy
entering = true;
return false;
}
else if (numberOfAgentsExecuting + numberOfAgentsEntering >= capacity && highestPriorityOfAgentsEntering > agentPriority)
{
// state seems to have available capacity but other agents with higher priority want to enter it
entering = true;
return false;
}
else if (numberOfAgentsExecuting + numberOfAgentsEntering >= capacity && highestPriorityOfAgentsEntering == agentPriority)
{
// another agent wants to enter the state that has the same priority
errorHandler.message("xabsl::CapacityState::coopCheck(): Conflict detected in capacity state \"%s\". Multiple agents with the same priority value %d are trying to execute the state.",n,agentPriority);
// in order to resolve the conflict we do not set enter flag
// if both agents remove their flag at the same time this situation might repeat indefinitely
return false;
}
else if (enterCount < synchronizationTicks)
{
// state seems to have available capacity => set enter flag and wait specified tick count
entering = true;
return false;
}
else
{
// enter state only after enter count has reached specified count
return true;
}
}
};
} // namespace
#endif //__XabslCoopState_h_

View File

@ -0,0 +1,342 @@
/**
* @file XabslDecimalExpression.cpp
*
* Implementation of DecimalExpression and derivates
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslOption.h"
#include "XabslDecimalExpression.h"
#include "XabslBooleanExpression.h"
#include "XabslEnumeratedExpression.h"
namespace xabsl
{
DecimalExpression::~DecimalExpression()
{
}
DecimalExpression* DecimalExpression::create(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
char c[100];
input.readString(c,1);
ArithmeticOperator* arithmeticOperator;
DecimalExpression* operand1;
DecimalExpression* operand2;
switch (*c)
{
case 'i':
return new DecimalInputSymbolRef(input,errorHandler,symbols,option,state);
case 'o':
return new DecimalOutputSymbolRef(input,errorHandler,symbols);
case 'c':
// constants are treates as decimal values (there is no difference from the engines point of view.)
case 'v':
return new DecimalValue(input,errorHandler);
case 'p':
return new DecimalOptionParameterRef(input,errorHandler,option);
case '+':
if (!DecimalExpression::createOperand(operand1,input,errorHandler,symbols,option,state))
return 0;
if (!DecimalExpression::createOperand(operand2,input,errorHandler,symbols,option,state))
return 0;
XABSL_DEBUG_INIT(errorHandler.message("creating + operator"));
arithmeticOperator = new PlusOperator();
arithmeticOperator->create(operand1,operand2);
return arithmeticOperator;
case '-':
if (!DecimalExpression::createOperand(operand1,input,errorHandler,symbols,option,state))
return 0;
if (!DecimalExpression::createOperand(operand2,input,errorHandler,symbols,option,state))
return 0;
XABSL_DEBUG_INIT(errorHandler.message("creating - operator"));
arithmeticOperator = new MinusOperator();
arithmeticOperator->create(operand1,operand2);
return arithmeticOperator;
case '*':
if (!DecimalExpression::createOperand(operand1,input,errorHandler,symbols,option,state))
return 0;
if (!DecimalExpression::createOperand(operand2,input,errorHandler,symbols,option,state))
return 0;
XABSL_DEBUG_INIT(errorHandler.message("creating * operator"));
arithmeticOperator = new MultiplyOperator();
arithmeticOperator->create(operand1,operand2);
return arithmeticOperator;
case 'd':
if (!DecimalExpression::createOperand(operand1,input,errorHandler,symbols,option,state))
return 0;
if (!DecimalExpression::createOperand(operand2,input,errorHandler,symbols,option,state))
return 0;
XABSL_DEBUG_INIT(errorHandler.message("creating / operator"));
arithmeticOperator = new DivideOperator();
arithmeticOperator->create(operand1,operand2);
return arithmeticOperator;
case '%':
if (!DecimalExpression::createOperand(operand1,input,errorHandler,symbols,option,state))
return 0;
if (!DecimalExpression::createOperand(operand2,input,errorHandler,symbols,option,state))
return 0;
XABSL_DEBUG_INIT(errorHandler.message("creating % operator"));
arithmeticOperator = new ModOperator();
arithmeticOperator->create(operand1,operand2);
return arithmeticOperator;
case 's':
return new TimeRef(errorHandler,state.timeOfStateExecution);
case 't':
return new TimeRef(errorHandler,option.timeOfExecution);
case 'q':
return new ConditionalDecimalExpression(input,errorHandler,symbols,option,state);
default:
errorHandler.error("XabslDecimalExpression::create(): unknown expression type: \"%c\"",*c);
return 0;
}
}
bool DecimalExpression::createOperand(DecimalExpression*& operand,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
operand = DecimalExpression::create(input,errorHandler,symbols,option,state);
if (operand == 0)
{
errorHandler.error("XabslDecimalExpression::createOperand(): created operand is 0");
return false;
}
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslDecimalExpression::createOperand(): could not create operand");
if (operand != 0) delete operand;
return false;
}
return true;
}
DecimalValue::DecimalValue(InputSource& input,
ErrorHandler& errorHandler)
{
value = input.readValue();
XABSL_DEBUG_INIT(errorHandler.message("created decimal value: \"%.2f\"",value));
}
double DecimalValue::getValue() const
{
return value;
}
DecimalOptionParameterRef::DecimalOptionParameterRef(InputSource& input,
ErrorHandler& errorHandler,
Option& option)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to decimal option parameter \"%s\"",buf));
if (!option.parameters->decimal.exists(buf))
{
errorHandler.error("XabslDecimalOptionParameterRef::DecimalOptionParameterRef(): decimal option parameter \"%s\" does not exist",buf);
return;
}
parameter = option.parameters->decimal.getPElement(buf)->e;
}
double DecimalOptionParameterRef::getValue() const
{
return *parameter;
}
void ArithmeticOperator::create(DecimalExpression* operand1, DecimalExpression* operand2)
{
this->operand1 = operand1;
this->operand2 = operand2;
}
ArithmeticOperator::~ArithmeticOperator()
{
if (operand1 != 0) delete operand1;
if (operand2 != 0) delete operand2;
}
double PlusOperator::getValue() const
{
return operand1->getValue() + operand2->getValue();
}
double MinusOperator::getValue() const
{
return operand1->getValue() - operand2->getValue();
}
double MultiplyOperator::getValue() const
{
return operand1->getValue() * operand2->getValue();
}
double DivideOperator::getValue() const
{
double o2 = operand2->getValue();
if (o2==0)
return operand1->getValue() / 0.0000001;
else
return operand1->getValue() / o2;
}
double ModOperator::getValue() const
{
return (int)operand1->getValue() % (int)operand2->getValue();
}
TimeRef::TimeRef(ErrorHandler& errorHandler,
unsigned& time) :
time(time)
{
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to state or option execution time"));
}
double TimeRef::getValue() const
{
return time;
}
DecimalInputSymbolRef::DecimalInputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state) :
symbol(0), parameters(0)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to decimal input symbol \"%s\"",buf));
if (!symbols.decimalInputSymbols.exists(buf))
{
errorHandler.error("XabslDecimalInputSymbolRef::DecimalInputSymbolRef(): decimal input symbol \"%s\" was not registered",buf);
return;
}
symbol = symbols.decimalInputSymbols[buf];
parameters = new ParameterAssignment(&symbol->parameters, errorHandler);
parameters->create(input, symbols, option, state);
}
DecimalInputSymbolRef::~DecimalInputSymbolRef()
{
if (parameters != 0)
delete parameters;
}
double DecimalInputSymbolRef::getValue() const
{
// set the symbol parameters
if (parameters->set())
symbol->parametersChanged();
return symbol->getValue();
}
DecimalOutputSymbolRef::DecimalOutputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to a decimal output symbol \"%s\"",buf));
if (!symbols.decimalOutputSymbols.exists(buf))
{
errorHandler.error("XabslDecimalOutputSymbolRef::DecimalOutputSymbolRef(): decimal output symbol \"%s\" was not registered",buf);
return;
}
symbol = symbols.decimalOutputSymbols[buf];
}
double DecimalOutputSymbolRef::getValue() const
{
return symbol->getValue();
}
ConditionalDecimalExpression::ConditionalDecimalExpression(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
XABSL_DEBUG_INIT(errorHandler.message("creating a question mark operator"));
condition = BooleanExpression::create(input,errorHandler,symbols,option,state);
if (condition == 0)
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): created condition is 0");
return;
}
else if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): could not create condition");
delete condition;
return;
}
if (!DecimalExpression::createOperand(expression1,input,errorHandler,symbols,option,state))
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): could not create decimal expression1");
return;
}
if (!DecimalExpression::createOperand(expression2,input,errorHandler,symbols,option,state))
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): could not create decimal expression2");
return;
}
}
ConditionalDecimalExpression::~ConditionalDecimalExpression()
{
if (condition!=0) delete condition;
if (expression1!=0) delete expression1;
if (expression2!=0) delete expression2;
}
double ConditionalDecimalExpression::getValue() const
{
if (condition->getValue())
{
return expression1->getValue();
}
else
{
return expression2->getValue();
}
}
} // namespace

View File

@ -0,0 +1,383 @@
/**
* @file XabslDecimalExpression.h
*
* Definition of DecimalExpression and derivates
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
*/
#ifndef __XabslDecimalExpression_h_
#define __XabslDecimalExpression_h_
#include "XabslSymbols.h"
namespace xabsl
{
// class prototypes used by symbol parameters / conditional expressions
class BooleanExpression;
class EnumeratedExpression;
class Option;
class State;
/**
* @class DecimalExpression
*
* Base class for all decimal expressions inside an option graph.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class DecimalExpression
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const = 0;
/**
* Creates a decimal expression depending on the input.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a decimal expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
static DecimalExpression* create(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
virtual ~DecimalExpression() = 0;
/**
* Creates a decimal expression depending on the input.
* Uses the create() function to create decimal operands.
* @param operand The expression to be created
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a decimal operand starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
* @return If the creation was successful
*/
static bool createOperand(
DecimalExpression*& operand,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
};
/**
* @class DecimalValue
*
* Represents a decimal value.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class DecimalValue : public DecimalExpression
{
public:
/**
* Constructor. Creates the value
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a value starts.
* @param errorHandler A reference to a ErrorHandler instance
*/
DecimalValue(InputSource& input,
ErrorHandler& errorHandler);
/**
* Constructor. Creates an expression for a fixed decimal value
* @param value The decimal value
*/
DecimalValue(double value) : value(value) {}
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
private:
/** The value */
double value;
};
/**
* @class DecimalOptionParameterRef
*
* Represents a reference to a decimal option parameter.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class DecimalOptionParameterRef : public DecimalExpression
{
public:
/**
* Constructor. Creates the reference
* @param input An input source for the intermediate code. It must be opened and read until
* A position where the expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param option The current option
*/
DecimalOptionParameterRef(InputSource& input,
ErrorHandler& errorHandler,
Option& option);
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
private:
/** A pointer to the parameter */
double* parameter;
};
/**
* @class ArithmeticOperator
*
* Base class for the +, -, *, / and % operator.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class ArithmeticOperator : public DecimalExpression
{
public:
/**
* Creates the operator
* @param operand1 The first operand
* @param operand2 The second operand
*/
void create(DecimalExpression* operand1, DecimalExpression* operand2);
/** Calculates the value of the decimal expression. */
virtual double getValue() const = 0;
/** Destructor. Deletes the operands */
~ArithmeticOperator();
protected:
/** The first operand */
DecimalExpression* operand1;
/** The second operand */
DecimalExpression* operand2;
};
/**
* @class PlusOperator
*
* Represents a + operator in the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class PlusOperator : public ArithmeticOperator
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
};
/**
* @class MinusOperator
*
* Represents a - operator in the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class MinusOperator : public ArithmeticOperator
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
};
/**
* @class MultiplyOperator
*
* Represents a * operator in the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class MultiplyOperator : public ArithmeticOperator
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
};
/**
* @class DivideOperator
*
* Represents a / operator in the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class DivideOperator : public ArithmeticOperator
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
};
/**
* @class ModOperator
*
* Represents a % operator in the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class ModOperator : public ArithmeticOperator
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
};
/**
* @class TimeRef
*
* Represents a time-of-option-execution or time-of-state-execution element in the option graph
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class TimeRef : public DecimalExpression
{
public:
/**
* Constructor
* @param errorHandler A reference to a ErrorHandler instance
* @param time the referenced time
*/
TimeRef(ErrorHandler& errorHandler,
unsigned& time);
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
private:
/** The referenced time */
unsigned& time;
};
/**
* @class DecimalInputSymbolRef
*
* Represents a reference to a decimal input symbol.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class DecimalInputSymbolRef : public DecimalExpression
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
/**
* Constructor. Creates the function call depending on the input.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where the function reference starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
DecimalInputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
~DecimalInputSymbolRef();
private:
/** The referenced symbol */
DecimalInputSymbol* symbol;
/** The parameter assignments of the referenced symbol */
ParameterAssignment* parameters;
};
/**
* @class DecimalOutputSymbolRef
*
* Represents a reference to a decimal input symbol.
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class DecimalOutputSymbolRef : public DecimalExpression
{
public:
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
/**
* Constructor. Creates the function call depending on the input.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where the function reference starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
*/
DecimalOutputSymbolRef(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols);
private:
/** The referenced symbol */
DecimalOutputSymbol* symbol;
};
/**
* @class ConditionalDecimalExpression
*
* Represents an ANSI C (condition?expression:expression) question mark operator
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class ConditionalDecimalExpression : public DecimalExpression
{
public:
/**
* Constructor. Creates the expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
ConditionalDecimalExpression(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
~ConditionalDecimalExpression();
/** Calculates the value of the decimal expression. */
virtual double getValue() const;
private:
/** The condition */
BooleanExpression* condition;
/** The expression that is returned when the condition evaluates true */
DecimalExpression* expression1;
/** The expression that is returned when the condition evaluates false */
DecimalExpression* expression2;
};
} // namespace
#endif //__XabslDecimalExpression_h_

View File

@ -0,0 +1,552 @@
/**
* @file XabslEngine.cpp
*
* Implementation of class Engine
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
*/
#include "XabslEngine.h"
namespace xabsl
{
Engine::Engine(ErrorHandler& e,unsigned (*pTimeFunction)())
: Symbols(e), selectedAgent(0),
errorHandler(e), initialized(false), pTimeFunction(pTimeFunction),
agentPriority(0),
synchronizationTicks(0),
timeOfExecutionStart(pTimeFunction())
{
}
Engine::~Engine()
{
int i;
for (i=0; i< options.getSize(); i++)
if (options[i]!=0)
delete options[i];
for (i=0; i< agents.getSize(); i++)
if (agents[i]!=0)
delete agents[i];
for (i=0; i< rootActions.getSize(); i++)
if (rootActions[i]!=0)
delete rootActions[i];
}
void Engine::execute()
{
if (!initialized)
{
errorHandler.error("execute(): Call createOptionGraph before first execute.");
return;
}
timeOfExecutionStart = pTimeFunction();
resetOutputSymbols();
for (int i=0; i< rootActions.getSize(); i++)
rootActions[i]->execute();
for (int i=0; i < options.getSize(); i++)
{
options[i]->wasActive = options[i]->isActive;
options[i]->isActive = false;
}
for (int i=0;i<basicBehaviors.getSize();i++)
{
basicBehaviors[i]->wasActive = basicBehaviors[i]->isActive;
basicBehaviors[i]->isActive = false;
}
}
void Engine::createOptionGraph(InputSource& input)
{
int i;
char buf1[100],buf2[100];
errorHandler.errorsOccurred = false;
timeOfExecutionStart = pTimeFunction();
if (initialized)
{
errorHandler.error("createOptionGraph(): Don't call this function twice");
return;
}
if (!input.open())
{
errorHandler.error("createOptionGraph(): Can't open input source");
return;
}
// create internal enumerations
int numberOfInternalEnumerations = (int)input.readValue();
for (i=0; i < numberOfInternalEnumerations; i++)
{
input.readString(buf1, 99);
int numberOfElements = (int)input.readValue();
for (int j=0; j < numberOfElements; j++)
{
input.readString(buf2, 99);
registerEnumElement(buf1, buf2, j);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslEngine::createOptionGraph(): could not register internal enumeration \"%s\"",buf1);
return;
}
}
}
// create internal symbols
int numberOfInternalSymbols = (int)input.readValue();
for (i=0; i < numberOfInternalSymbols; i++)
{
char c[2];
input.readString(c,1);
switch (c[0])
{
case 'd':
input.readString(buf1,99);
internalDecimalSymbols.append(buf1, 0);
registerDecimalOutputSymbol(buf1, &(internalDecimalSymbols.getElement(internalDecimalSymbols.getSize() - 1)));
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslEngine::createOptionGraph(): could not register internal decimal symbol \"%s\"",buf1);
return;
}
break;
case 'b':
input.readString(buf1,99);
internalBooleanSymbols.append(buf1, false);
registerBooleanOutputSymbol(buf1, &(internalBooleanSymbols.getElement(internalBooleanSymbols.getSize() - 1)));
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslEngine::createOptionGraph(): could not register internal boolean symbol \"%s\"",buf1);
return;
}
break;
case 'e':
input.readString(buf1,99);
if (!enumerations.exists(buf1))
{
errorHandler.error("XabslEngine::createOptionGraph(): enumeration \"%s\" was not registered",buf1);
return;
}
const Enumeration* enumeration = enumerations[buf1];
if (enumeration->enumElements.getSize() == 0)
{
errorHandler.error("XabslEngine::createOptionGraph(): no enumeration elements for \"%s\" were registered",buf1);
return;
}
input.readString(buf2,99);
internalEnumeratedSymbols.append(buf2, enumeration->enumElements[0]->v);
registerEnumeratedOutputSymbol(buf2, buf1, &(internalEnumeratedSymbols.getElement(internalEnumeratedSymbols.getSize() - 1)));
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslEngine::createOptionGraph(): could not register internal enumerated symbol \"%s\"",buf2);
return;
}
break;
}
}
// the total number of options in the intermediate code
int numberOfOptions = (int)input.readValue();
// create empty options
for (i=0; i< numberOfOptions; i++)
{
input.readString(buf1,99);
options.append(buf1,new Option(buf1,input,errorHandler,*this,timeOfExecutionStart,i));
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslEngine::createOptionGraph(): could not create option \"%s\"",options[i]->n);
return;
}
}
XABSL_DEBUG_INIT(errorHandler.message("registered %i options",numberOfOptions));
// create the options and its states
for (i=0; i< numberOfOptions; i++)
{
XABSL_DEBUG_INIT(errorHandler.message("creating option \"%s\"",options[i]->n));
options[i]->create(input,options,basicBehaviors,*this,agentPriority,synchronizationTicks);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslEngine::createOptionGraph(): could not create option \"%s\"",options[i]->n);
return;
}
}
// create the agents
int numberOfAgents = (int)input.readValue();
for (i=0; i< numberOfAgents; i++)
{
input.readString(buf1,99);
input.readString(buf2,99);
agents.append(buf1,new Agent(buf1,options[buf2],errorHandler, i));
}
// check for loops in the option graph
for (i=0;i<agents.getSize();i++)
{
if (Option* option = dynamic_cast<Option*>(agents[i]->getRootOption()))
{
int size = countActions(option) + 1;
ActionBehavior** currentOptionPath = new ActionBehavior*[size];
currentOptionPath[0] = dynamic_cast<ActionBehavior*>(Action::create(option, errorHandler, timeOfExecutionStart));
// call recursively the checkForLoops function
if (checkForLoops(option, currentOptionPath, 1, size))
{
errorHandler.error("createOptionGraph(): The created option graph contains loops");
};
delete currentOptionPath[0];
delete[] currentOptionPath;
}
}
// create array of cooperating states
for (i=0;i<options.getSize();i++)
for (int j=0;j<options[i]->states.getSize();j++)
if (CoopState* state = dynamic_cast<CoopState*>(options[i]->states[j]))
coopStates.append(state);
selectedAgent = agents[0];
setRootAction();
XABSL_DEBUG_INIT(errorHandler.message("selected agent: \"%s\"",selectedAgent->n));
input.close();
initialized = true;
}
bool Engine::checkForLoops(Option* currentOption, ActionBehavior* currentOptionTree[], int currentLength, int maxSize)
{
int i,j,k,l;
for (i=0; i<currentOption->states.getSize(); i++)
{
int newLength = currentLength;
for (j=0; j<currentOption->states[i]->actions.getSize(); j++)
{
if (ActionBehavior* nextAction = dynamic_cast<ActionBehavior*>(currentOption->states[i]->actions[j]))
{
for(k=0; k<newLength; k++)
{
// check for the subsequent option of each state whether the referenced
// option is contained in the current option tree
if (nextAction->getBehavior() == currentOptionTree[k]->getBehavior())
{
errorHandler.error("checkForLoops() : state \"%s\" in option \"%s\" references subsequent behavior \"%s\", which is already included in another possible activation tree.",
currentOption->states[i]->n,
currentOption->n,
nextAction->getBehavior()->n);
return true;
}
}
if(newLength>=maxSize)
{
errorHandler.error("checkForLoops() : max size exceeded when processing state \"%s\" in option \"%s\".",
currentOption->states[i]->n,
currentOption->n);
return true;
}
currentOptionTree[newLength++] = nextAction;
}
}
// recursion
for (k = currentLength; k < newLength; k++)
{
int recursionLength = newLength;
for (l = currentLength; l < newLength; l++)
{
if (l != k)
{
addActions(currentOptionTree[l], currentOptionTree, recursionLength, maxSize);
}
}
if (ActionOption* nextAction = dynamic_cast<ActionOption*>(currentOptionTree[k]))
{
if (checkForLoops(nextAction->option, currentOptionTree, recursionLength, maxSize))
{
return true;
}
}
}
}
return false;
}
void Engine::addActions(ActionBehavior* actionToAdd, ActionBehavior* currentOptionTree[], int& currentLength, int maxSize)
{
int i,j;
if (ActionOption* optionToAdd = dynamic_cast<ActionOption*>(actionToAdd))
{
for (i=0; i<optionToAdd->option->states.getSize(); i++)
{
for (j=0; j<optionToAdd->option->states[i]->actions.getSize(); j++)
{
if (ActionBehavior* nextAction = dynamic_cast<ActionBehavior*>(optionToAdd->option->states[i]->actions[j]))
{
if(currentLength>=maxSize)
{
errorHandler.error("checkForLoops() : max size exceeded when processing state \"%s\" in option \"%s\".",
optionToAdd->option->states[i]->n,
optionToAdd->option->n);
return;
}
currentOptionTree[currentLength++] = nextAction;
addActions(nextAction, currentOptionTree, currentLength, maxSize);
}
}
}
}
}
int Engine::countActions(Option* option)
{
int i,j;
int count = 0;
for (i=0; i<option->states.getSize(); i++)
{
for (j=0; j<option->states[i]->actions.getSize(); j++)
{
if (ActionBehavior* nextAction = dynamic_cast<ActionBehavior*>(option->states[i]->actions[j]))
{
count++;
if (ActionOption* nextOption = dynamic_cast<ActionOption*>(nextAction))
{
count += countActions(nextOption->option);
}
}
}
}
return count;
}
void Engine::registerBasicBehavior(BasicBehavior& basicBehavior)
{
XABSL_DEBUG_INIT(errorHandler.message("registering basic behavior \"%s\"",basicBehavior.n));
if (basicBehaviors.exists(basicBehavior.n))
{
errorHandler.error("registerBasicBehavior(): basic behavior \"%s\" was already registered",basicBehavior.n);
return;
}
basicBehavior.parameters->registerEnumerations(enumerations);
basicBehavior.registerParameters();
basicBehavior.index = basicBehaviors.getSize();
basicBehaviors.append(basicBehavior.n,&basicBehavior);
}
void Engine::clearRootActions()
{
for (int i=0; i< rootActions.getSize(); i++)
if (rootActions[i]!=0)
delete rootActions[i];
rootActions.clear();
}
bool Engine::addRootAction(const char* name, bool isOption)
{
if (isOption)
{
// check if the option exists
if (!options.exists(name)) return false;
// set the current root option to the requested option
addRootAction(options[name]);
}
else
{
// check if the basic behavior exists
if (!basicBehaviors.exists(name)) return false;
// set the current root option to the requested option
addRootAction(basicBehaviors[name]);
}
return true;
}
bool Engine::setRootAction(const char* name, bool isOption)
{
clearRootActions();
return addRootAction(name, isOption);
}
void Engine::setRootAction()
{
setRootAction(selectedAgent->getRootOption());
}
void Engine::addRootAction(Behavior* behavior)
{
rootActions.append(Action::create(behavior, errorHandler, timeOfExecutionStart));
}
void Engine::setRootAction(Behavior* behavior)
{
clearRootActions();
addRootAction(behavior);
}
bool Engine::addRootActionDecimalOutputSymbol(const char* name, double value)
{
if (!decimalOutputSymbols.exists(name)) return false;
ActionDecimalOutputSymbol* action = new ActionDecimalOutputSymbol(timeOfExecutionStart);
action->decimalOutputSymbol = decimalOutputSymbols[name];
action->decimalOutputSymbolExpression = new DecimalValue(value);
rootActions.append(action);
return true;
}
bool Engine::addRootActionBooleanOutputSymbol(const char* name, bool value)
{
if (!booleanOutputSymbols.exists(name)) return false;
ActionBooleanOutputSymbol* action = new ActionBooleanOutputSymbol(timeOfExecutionStart);
action->booleanOutputSymbol = booleanOutputSymbols[name];
action->booleanOutputSymbolExpression = new BooleanValue(value);
rootActions.append(action);
return true;
}
bool Engine::addRootActionEnumeratedOutputSymbol(const char* name, const char* value)
{
if (!enumeratedOutputSymbols.exists(name) || !enumeratedOutputSymbols[name]->enumeration->enumElements.exists(value))
return false;
ActionEnumeratedOutputSymbol* action = new ActionEnumeratedOutputSymbol(timeOfExecutionStart);
action->enumeratedOutputSymbol = enumeratedOutputSymbols[name];
action->enumeratedOutputSymbolExpression = new EnumeratedValue(enumeratedOutputSymbols[name]->enumeration, enumeratedOutputSymbols[name]->enumeration->enumElements[value]->v);
rootActions.append(action);
return true;
}
const Action* Engine::getRootAction(int i) const
{
return rootActions[i];
}
Action* Engine::getRootAction(int i)
{
return rootActions[i];
}
const Array<Action*>& Engine::getRootActions() const
{
return rootActions;
}
Array<Action*>& Engine::getRootActions()
{
return rootActions;
}
const char* Engine::getSelectedAgentName() const
{
if (selectedAgent)
return selectedAgent->n;
else
return "";
}
bool Engine::setSelectedAgent(const char* name)
{
if (!agents.exists(name))
{
return false;
}
Agent* newAgent = agents[name];
if (selectedAgent != newAgent)
{
selectedAgent = newAgent;
setRootAction();
}
return true;
}
void Engine::reset()
{
int i;
for (i=0; i< options.getSize(); i++)
{
options[i]->wasActive = false;
}
for (i=0; i< basicBehaviors.getSize(); i++)
{
basicBehaviors[i]->wasActive = false;
}
errorHandler.errorsOccurred = false;
}
void Engine::prepareIncomingMessages()
{
for (int i=0; i<coopStates.getSize(); i++)
{
coopStates[i]->prepareIncomingMessages();
}
}
void Engine::processIncomingMessage(const TeamMessage& message)
{
for (int i=0; i<message.coopStatesExecuted.getSize(); i++)
coopStates[message.coopStatesExecuted[i]]->numberOfAgentsExecuting++;
for (int i=0; i<message.coopStatesEntering.getSize(); i++)
{
if (coopStates[message.coopStatesEntering[i]]->numberOfAgentsEntering == 0 ||
coopStates[message.coopStatesEntering[i]]->highestPriorityOfAgentsEntering < message.agentPriority)
coopStates[message.coopStatesEntering[i]]->highestPriorityOfAgentsEntering = message.agentPriority;
coopStates[message.coopStatesEntering[i]]->numberOfAgentsEntering++;
}
for (int i=0; i<message.coopStatesOptionExecuted.getSize(); i++)
coopStates[message.coopStatesOptionExecuted[i]]->numberOfAgentsInOption++;
}
void Engine::generateOutgoingMessage(TeamMessage& message)
{
message.reset();
for (int i=0; i<coopStates.getSize(); i++)
{
// is option currently active?
if (options[coopStates[i]->optionIndex]->wasActive)
{
message.coopStatesOptionExecuted.append(i);
// is state currently active?
if (options[coopStates[i]->optionIndex]->activeState == coopStates[i])
{
message.coopStatesExecuted.append(i);
}
else if (coopStates[i]->entering)
{
message.coopStatesEntering.append(i);
}
}
}
message.agentPriority = agentPriority;
}
} // namespace

View File

@ -0,0 +1,248 @@
/**
* @file XabslEngine.h
*
* Declaration class Engine
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
*/
#ifndef __XabslEngine_h_
#define __XabslEngine_h_
#include "XabslAgent.h"
#include "XabslOption.h"
#include "XabslCoopState.h"
#include "XabslTeamMessage.h"
namespace xabsl
{
/**
* Executes a behavior that was specified in the Xabsl language.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias JŸngel</a>
*/
class Engine : public Symbols
{
public:
/**
* Constructor
* @param e Is invoked when there are problems during initialization
* @param pTimeFunction a pointer to a function that returns the system time in ms.
*/
Engine(ErrorHandler& e, unsigned (*pTimeFunction)());
/** Destructor */
~Engine();
/**
* Executes the engine for the selected agent starting from the root option.
* (Including the selected basic behavior)
*/
void execute();
/**
* Reads the intermediate code from an input source and creates the option graph.
* Note that the basic behaviors and symbols have to be registered before that function is
* called.
*/
void createOptionGraph(InputSource& input);
/**
* Registers a basic behavior at the engine.
* This must be done before the intermediate code is read.
* @param basicBehavior A reference to the basic behavior
*/
void registerBasicBehavior(BasicBehavior& basicBehavior);
/**
* Sets the selected Agent.
* If the last selected agent was different from the new one,
* the root option is changed depending on the new agent.
* @param name The name of the agent
* @return if the requested agent exists
*/
bool setSelectedAgent(const char* name);
/**
* Resets all active options.
* Next cycle will execute initial state of currently set root option.
*/
void reset();
private:
/**
* The time of the start of the current engine execution
*/
unsigned timeOfExecutionStart;
/** The agents of the engine */
NamedArray<Agent*> agents;
/** The selected agent */
Agent* selectedAgent;
/** The options of the engine */
NamedArray<Option*> options;
/** The actions for the execution of the start of the option graph */
Array<Action*> rootActions;
/** The registered basic behaviors of the engine */
NamedArray<BasicBehavior*> basicBehaviors;
/** Is invoked when there are problems during initialization */
ErrorHandler& errorHandler;
/**
* A recursive function that is used to check for loops in the option graph.
* @param currentOption The option to be checked
* @param currentOptionTree An array of the currently traced option tree
* @param currentLength The length of the current option tree array
* @param maxSize maximum allowed size of the array
* @return If true, then a loop was detected.
*/
bool checkForLoops(Option* currentOption, ActionBehavior* currentOptionTree[], int currentLength, int maxSize);
/** A recursive function that generates a list of actions referenced from a starting option
* This is used by checkForLoops.
* @param actionToAdd The option whose referenced actions are to be added to the current array
* @param currentOptionTree An array to which the referenced options are to be added
* @param currentLength The current length of the array. Actions will be appended at the end of the array. currentLength will increase accordingly.
* @param maxSize maximum allowed size of the array
*/
void addActions(ActionBehavior* actionToAdd, ActionBehavior* currentOptionTree[], int& currentLength, int maxSize);
/**
* Rescursively count the number of actions referenced from an option
* @param option A pointer to the option for which the referenced options are counted.
* @return Number of actions */
int countActions(Option* option);
/** If true, the engine was successfully initialized */
bool initialized;
/** A pointer to a function that returns the system time in ms. */
unsigned (*pTimeFunction)();
/** Arrays containing internal symbol values */
NamedArray<double> internalDecimalSymbols;
NamedArray<bool> internalBooleanSymbols;
NamedArray<int> internalEnumeratedSymbols;
/** Array of states which are used for cooperating agents */
Array<CoopState*> coopStates;
/** Priority value of the agent, used for solving conflicts in cooperative state assignment */
int agentPriority;
/** Number of execution cycles that is required for synchonization with other agents, i.e time from sending a message until answer is received */
int synchronizationTicks;
public:
//!@name Debugging Interface
//!@{
/** Returns the agents of the engine */
const NamedArray<Agent*>& getAgents() const {return agents;}
/** Return the options of the engine */
const NamedArray<Option*>& getOptions() const {return options;}
/** Returns the registered basic behaviors of the engine */
const NamedArray<BasicBehavior*>& getBasicBehaviors() const {return basicBehaviors;}
/**
* Clears the list of actions executed starting the option graph.
*/
void clearRootActions();
/**
* Adds a given option or basic behavior to the list of actions executed starting the option graph.
* Can be called to test a single option or basic behavior.
* @param name The name of the option or basic behavior
* @param isOption True for an option, false for a basic behavior
* @return When false, the option is not known to the engine
*/
bool addRootAction(const char* name, bool isOption = true);
/**
* Executes the option graph starting from a given option or basic behavior.
* Can be called to test a single option or basic behavior.
* @param name The name of the option or basic behavior
* @param isOption True for an option, false for a basic behavior
* @return When false, the option is not known to the engine
*/
bool setRootAction(const char* name, bool isOption = true);
/**
* Sets the root option of the selected agent
*/
void setRootAction();
/**
* Adds the specified option or basic behavior to the list of root actions.
*/
void addRootAction(Behavior* behavior);
/**
* Adds a decimal output symbol assignment to the list of root actions.
*/
bool addRootActionDecimalOutputSymbol(const char* name, double value);
/**
* Adds a boolean output symbol assignment to the list of root actions.
*/
bool addRootActionBooleanOutputSymbol(const char* name, bool value);
/**
* Adds an enumerated output symbol assignment to the list of root actions.
*/
bool addRootActionEnumeratedOutputSymbol(const char* name, const char* value);
/**
* Sets the root option to the specified option or basic behavior
*/
void setRootAction(Behavior* behavior);
/** Returns the selected root actions */
const Action* getRootAction(int i) const;
/** Returns the selected root actions */
Action* getRootAction(int i);
/** Returns the selected root actions */
const Array<Action*>& getRootActions() const;
/** Returns the selected root actions */
Array<Action*>& getRootActions();
/** Returns the name of the selected agent */
const char* getSelectedAgentName() const;
/** Prepare for processing incoming team messages. This resets previously processed messages. */
void prepareIncomingMessages();
/** Process an incoming team message from another agent */
void processIncomingMessage(const TeamMessage& message);
/** Generate the outgoing team message to be sent to other agents */
void generateOutgoingMessage(TeamMessage& message);
/** Set the number of execution cycles that is required for synchonization with other agents, i.e time from sending a message until answer is received */
void setSynchronizationTicks(int ticks) {synchronizationTicks = ticks;}
/** Sets the priority value of the agent, used for solving conflicts in cooperative state assignment */
void setAgentPriority(int priority) {agentPriority = priority;}
//!@}
};
} // namespace
#endif // __XabslEngine_h_

View File

@ -0,0 +1,264 @@
/**
* @file XabslEnumeratedExpression.cpp
*
* Implementation of EnumeratedExpression and derivates
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslEnumeratedExpression.h"
#include "XabslOption.h"
namespace xabsl
{
EnumeratedExpression::~EnumeratedExpression()
{
}
EnumeratedExpression* EnumeratedExpression::create(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
char c[2];
input.readString(c,1);
switch (*c)
{
case 'v':
return new EnumeratedValue(enumeration, input,errorHandler);
case 'p':
return new EnumeratedOptionParameterRef(enumeration, input,errorHandler,option);
case 'i':
return new EnumeratedInputSymbolRef(enumeration, input,errorHandler,symbols,option,state);
case 'o':
return new EnumeratedOutputSymbolRef(enumeration, input,errorHandler,symbols);
case 'q':
return new ConditionalEnumeratedExpression(enumeration, input,errorHandler,symbols,option,state);
default:
errorHandler.error("XabslEnumeratedExpression::create(): unknown expression type \"%c\"",*c);
}
return 0;
}
bool EnumeratedExpression::createOperand(const EnumeratedExpression*& operand,
const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
operand = EnumeratedExpression::create(enumeration,input,errorHandler,symbols,option,state);
if (operand == 0)
{
errorHandler.error("XabslEnumeratedExpression::createOperand(): created operand is 0");
return false;
}
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslEnumeratedExpression::createOperand(): could not create operand");
if (operand != 0) delete operand;
return false;
}
return true;
}
EnumeratedValue::EnumeratedValue(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler)
{
char buf[100];
input.readString(buf,99);
if (enumeration == NULL)
{
errorHandler.error("XabslEnumeratedValue::EnumeratedValue(): enumerated value can not be created without specifying enumeration");
return;
}
if (!enumeration->enumElements.exists(buf))
{
errorHandler.error("XabslEnumeratedValue::EnumeratedValue(): enum element \"%s\" of enumeration \"%s\" was not registered", buf, enumeration->n);
return;
}
value = enumeration->enumElements[buf]->v;
this->enumeration = enumeration;
}
int EnumeratedValue::getValue() const
{
return value;
}
EnumeratedOptionParameterRef::EnumeratedOptionParameterRef(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Option& option)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to enumerated option parameter \"%s\"",buf));
if (!option.parameters->enumerated.exists(buf))
{
errorHandler.error("XabslEnumeratedOptionParameterRef::EnumeratedOptionParameterRef(): enumerated option parameter \"%s\" does not exist",buf);
return;
}
parameter = option.parameters->enumerated.getPElement(buf)->e;
this->enumeration = option.parameters->enumerations[buf];
if (enumeration != NULL && enumeration != this->enumeration)
{
errorHandler.error("XabslEnumeratedOptionParameterRef::EnumeratedOptionParameterRef(): enumeration input symbol \"%s\" does not match enumeration type \"%s\"", buf, enumeration->n);
}
}
int EnumeratedOptionParameterRef::getValue() const
{
return *parameter;
}
EnumeratedInputSymbolRef::EnumeratedInputSymbolRef(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state) :
symbol(0), parameters(0)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating reference to enumerated input symbol \"%s\"",buf));
if (!symbols.enumeratedInputSymbols.exists(buf))
{
errorHandler.error("XabslEnumeratedInputSymbolRef::XabslEnumeratedInputSymbolRef(): enumerated input symbol \"%s\" was not registered at the engine",buf);
return;
}
symbol = symbols.enumeratedInputSymbols[buf];
this->enumeration = symbol->enumeration;
if (enumeration != NULL && enumeration != this->enumeration)
{
errorHandler.error("XabslEnumeratedInputSymbolRef::XabslEnumeratedInputSymbolRef(): enumeration input symbol \"%s\" does not match enumeration type \"%s\"", buf, enumeration->n);
}
parameters = new ParameterAssignment(&symbol->parameters, errorHandler);
parameters->create(input, symbols, option, state);
}
EnumeratedInputSymbolRef::~EnumeratedInputSymbolRef()
{
if (parameters != 0)
delete parameters;
}
int EnumeratedInputSymbolRef::getValue() const
{
// set the symbol parameters
if (parameters->set())
symbol->parametersChanged();
return symbol->getValue();
}
EnumeratedOutputSymbolRef::EnumeratedOutputSymbolRef(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols)
{
char buf[100];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating a reference to an enumerated output symbol \"%s\"",buf));
if (!symbols.enumeratedOutputSymbols.exists(buf))
{
errorHandler.error("XabslEnumeratedOutputSymbolRef::EnumeratedOutputSymbolRef(): enumerated output symbol \"%s\" was not registered",buf);
return;
}
symbol = symbols.enumeratedOutputSymbols[buf];
this->enumeration = symbol->enumeration;
if (enumeration != NULL && enumeration != this->enumeration)
{
errorHandler.error("XabslEnumeratedInputSymbolRef::XabslEnumeratedInputSymbolRef(): enumeration input symbol \"%s\" does not match enumeration type \"%s\"", buf, enumeration->n);
}
}
int EnumeratedOutputSymbolRef::getValue() const
{
return symbol->getValue();
}
ConditionalEnumeratedExpression::ConditionalEnumeratedExpression(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
XABSL_DEBUG_INIT(errorHandler.message("creating a question mark operator"));
condition = BooleanExpression::create(input,errorHandler,symbols,option,state);
if (condition == 0)
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): created condition is 0");
return;
}
else if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): could not create condition");
delete condition;
return;
}
if (!EnumeratedExpression::createOperand(expression1,enumeration,input,errorHandler,symbols,option,state))
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): could not create decimal expression1");
return;
}
if (!EnumeratedExpression::createOperand(expression2,enumeration,input,errorHandler,symbols,option,state))
{
errorHandler.error("XabslQuestionMarkOperator::QuestionMarkOperator(): could not create decimal expression2");
return;
}
this->enumeration = enumeration;
}
ConditionalEnumeratedExpression::~ConditionalEnumeratedExpression()
{
if (condition!=0) delete condition;
if (expression1!=0) delete expression1;
if (expression2!=0) delete expression2;
}
int ConditionalEnumeratedExpression::getValue() const
{
if (condition->getValue())
{
return expression1->getValue();
}
else
{
return expression2->getValue();
}
}
} // namespace

View File

@ -0,0 +1,266 @@
/**
* @file XabslEnumeratedExpression.h
*
* Definition of EnumeratedExpression and derivates
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslEnumeratedExpression_h_
#define __XabslEnumeratedExpression_h_
#include "XabslSymbols.h"
#include "XabslDecimalExpression.h"
namespace xabsl
{
/**
* @class EnumeratedExpression
*
* Base class for all enumerated expressions inside an option graph.
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class EnumeratedExpression
{
public:
/** Evaluates the enumerated expression. */
virtual int getValue() const = 0;
/**
* Creates an enumerated expression depending on the input.
* @param enumeration A reference to the enumeration which is the domain of this expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a enumerated expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
static EnumeratedExpression* create(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/**
* Creates an enumerated expression depending on the input.
* Uses the create() function to create enumerated operands.
* @param operand The expression to be created
* @param enumeration A reference to the enumeration which is the domain of this expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a decimal operand starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
* @return If the creation was successful
*/
static bool createOperand(
const EnumeratedExpression*& operand,
const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
virtual ~EnumeratedExpression() = 0;
const Enumeration* enumeration;
};
/**
* @class EnumeratedValue
*
* Represents a enumerated value.
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class EnumeratedValue : public EnumeratedExpression
{
public:
/**
* Constructor. Creates the value
* @param enumeration A reference to the enumeration which is the domain of this expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a value starts.
* @param errorHandler A reference to a ErrorHandler instance
*/
EnumeratedValue(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler);
/**
* Constructor. Creates an expression for a fixed enumerated value
* @param value The enumerated value
*/
EnumeratedValue(const Enumeration* enumeration, int value) :
value(value)
{
this->enumeration = enumeration;
}
/** Calculates the value of the decimal expression. */
virtual int getValue() const;
private:
/** The value */
int value;
};
/**
* @class EnumeratedOptionParameterRef
*
* Represents a reference to a enumerated option parameter.
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class EnumeratedOptionParameterRef : public EnumeratedExpression
{
public:
/**
* Constructor. Creates the reference
* @param enumeration A reference to the enumeration which is the domain of this expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where the expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param option The current option
*/
EnumeratedOptionParameterRef(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Option& option);
/** Calculates the value of the enumerated expression. */
virtual int getValue() const;
private:
/** A pointer to the parameter */
int* parameter;
};
/**
* @class EnumeratedInputSymbolRef
*
* Represents an 'enumerated-input-symbol-ref' element of the option graph
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class EnumeratedInputSymbolRef : public EnumeratedExpression
{
public:
/**
* Constructor. Creates the element
* @param enumeration A reference to the enumeration which is the domain of this expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
EnumeratedInputSymbolRef(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
~EnumeratedInputSymbolRef();
/** Evaluates the enumerated expression. */
virtual int getValue() const;
private:
/** The referenced symbol */
EnumeratedInputSymbol* symbol;
/** The parameter assignments of the referenced symbol */
ParameterAssignment* parameters;
};
/**
* @class EnumeratedOutputSymbolRef
*
* Represents a reference to a enumerated input symbol.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class EnumeratedOutputSymbolRef : public EnumeratedExpression
{
public:
/** Calculates the value of the enumerated expression. */
virtual int getValue() const;
/**
* Constructor. Creates the function call depending on the input.
* @param enumeration A reference to the enumeration which is the domain of this expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where the function reference starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
*/
EnumeratedOutputSymbolRef(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols);
private:
/** The referenced symbol */
const EnumeratedOutputSymbol* symbol;
};
/**
* @class ConditionalEnumeratedExpression
*
* Represents an ANSI C (condition?expression:expression) question mark operator
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class ConditionalEnumeratedExpression : public EnumeratedExpression
{
public:
/**
* Constructor. Creates the expression
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a expression starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
ConditionalEnumeratedExpression(const Enumeration* enumeration,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
~ConditionalEnumeratedExpression();
/** Calculates the value of the decimal expression. */
virtual int getValue() const;
private:
/** The condition */
const BooleanExpression* condition;
/** The expression that is returned when the condition evaluates true */
const EnumeratedExpression* expression1;
/** The expression that is returned when the condition evaluates false */
const EnumeratedExpression* expression2;
};
} // namespace
#endif //__XabslEnumeratedExpression_h_

View File

@ -0,0 +1,190 @@
/**
* @file XabslOption.cpp
*
* Implementation of class Option and helper classes
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslOption.h"
#include "XabslCoopState.h"
namespace xabsl
{
OptionParameters::OptionParameters(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols) : Parameters(errorHandler)
{
int numberOfOptionParameters = (int)input.readValue();
char buf[100];
char c[2];
for (int i=0; i< numberOfOptionParameters; i++)
{
input.readString(c,1);
switch (c[0])
{
case 'd':
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("registering decimal option parameter \"%s\"",buf));
decimal.append(buf, new double(0));
break;
case 'b':
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("registering boolean option parameter \"%s\"",buf));
boolean.append(buf, new bool(false));
break;
case 'e':
input.readString(buf,99);
if (!symbols.enumerations.exists(buf))
{
errorHandler.error("XabslOptionParameters::OptionParameters(): enumeration \"%s\" was not registered",buf);
return;
}
const Enumeration* enumeration = symbols.enumerations[buf];
if (enumeration->enumElements.getSize() == 0)
{
errorHandler.error("XabslOptionParameters::OptionParameters(): no enumeration elements for \"%s\" were registered",buf);
return;
}
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated option parameter \"%s\"",buf));
enumerated.append(buf, new int(enumeration->enumElements[0]->v));
enumerations.append(buf,enumeration);
break;
}
}
}
OptionParameters::~OptionParameters()
{
int i;
for (i = 0; i < decimal.getSize(); i++)
delete decimal[i];
for (i = 0; i < boolean.getSize(); i++)
delete boolean[i];
for (i = 0; i < enumerated.getSize(); i++)
delete enumerated[i];
}
Option::Option(const char* name,
InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
const unsigned& time,
int index)
: Behavior(name), activeState(0),
initialState(0), errorHandler(errorHandler),
time(time),
index(index)
{
parameters = new OptionParameters(input, errorHandler, symbols);
}
Option::~Option()
{
for (int i=0;i<states.getSize();i++)
if (states[i]!=0)
delete states[i];
delete parameters;
}
void Option::create(InputSource& input,
NamedArray<Option*>& options,
NamedArray<BasicBehavior*>& basicBehaviors,
Symbols& symbols,
const int& agentPriority,
const int& synchronizationTicks
)
{
int i;
// the number of states of the option
int numberOfStates = (int)input.readValue();
char stateName[100];
char c[2];
// register all states to the array
for (i=0; i< numberOfStates; i++)
{
input.readString(stateName, 99);
// cooperative state or not
input.readString(c,1);
switch (*c)
{
case 'n':
states.append(stateName, new State(stateName,errorHandler,time,index,i));
break;
case 's':
states.append(stateName, new SynchronizedState(stateName,errorHandler,time,index,i,agentPriority,synchronizationTicks,(int)input.readValue()));
break;
case 'c':
states.append(stateName, new CapacityState(stateName,errorHandler,time,index,i,agentPriority,synchronizationTicks,(int)input.readValue()));
break;
}
}
XABSL_DEBUG_INIT(errorHandler.message("XabslOption::create(): registered %i states",numberOfStates));
// set the initial state
input.readString(stateName,99);
initialState = states[stateName];
activeState = initialState;
XABSL_DEBUG_INIT(errorHandler.message("XabslOption::create(): initial state: \"%s\"",initialState->n));
// create the states and their subelements
for (i=0; i< numberOfStates; i++)
{
states[i]->create(input, options, basicBehaviors, states, symbols);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslOption::create(): could not create state \"%s\"",states[i]->n);
return;
}
}
}
void Option::execute()
{
if (isActive)
{
errorHandler.error("XabslOption::execute(): option \"%s\" is contained in activation tree more than once. Aborting execution.",n);
return;
}
if (!wasActive)
{
activeState = initialState;
activeState->reset();
}
State* newState = activeState->getNextState();
if (newState != activeState)
{
activeState = newState;
activeState->reset();
}
for (int j=0; j < activeState->actions.getSize(); j++)
{
activeState->actions[j]->execute();
}
}
bool Option::getOptionReachedATargetState() const
{
if (wasActive && activeState->isTargetState())
{
return true;
}
else
{
return false;
}
}
} // namespace

View File

@ -0,0 +1,124 @@
/**
* @file XabslOption.h
*
* Definition of class Option and Helper classes
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslOption_h_
#define __XabslOption_h_
#include "XabslState.h"
#include "XabslBehavior.h"
namespace xabsl
{
/**
* @class OptionParameters
*
* Represents the current set of parameters of an option or basic behavior
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class OptionParameters : public Parameters
{
public:
/**
* Constructor.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where an option starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
*/
OptionParameters(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols);
/** Destructor */
~OptionParameters();
};
/**
* @class Option
*
* Represents a single option written in
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class Option : public Behavior
{
public:
/**
* Constructor. Does not create the option.
* @param name The name of the option. For debugging purposes.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where an option starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param time The system time in ms.
* @param Index of the option in array options in corresponding engine
*/
Option(const char* name, InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
const unsigned& time,
int index);
/** Destructor. Deletes the states */
~Option();
/**
* Creates the option and it's states from the intermediate code.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where an option starts.
* @param options All other options
* @param basicBehaviors All basic behaviors
* @param symbols All available symbols
* @param agentPriority Priority value of the agent, used for solving conflicts in cooperative state assignment
* @param synchronizationTicks Number of execution cycles that is required for synchonization with other agents, i.e time from sending a message until answer is received
*/
void create(InputSource& input,
NamedArray<Option*>& options,
NamedArray<BasicBehavior*>& basicBehaviors,
Symbols& symbols,
const int& agentPriority,
const int& synchronizationTicks);
/**
* Executes the option. The state machine is carried out to determine the subsequent
* option or the subsequent basic behavior. Output symbols are set.
*/
virtual void execute();
/** The states of the option */
NamedArray<State*> states;
/** A pointer to the active state. If 0, then no state is active */
State* activeState;
/** Returns wheter the option reached a target state */
bool getOptionReachedATargetState() const;
/** Index of the option in array options in corresponding engine */
int index;
private:
/** A pointer to the initial state */
State* initialState;
/** Used for error handling */
ErrorHandler& errorHandler;
/** The system time in ms. */
const unsigned& time;
};
} // namespace
#endif //__XabslOption_h_

View File

@ -0,0 +1,312 @@
/**
* @file XabslParameters.cpp
*
* Implementation of class Parameters
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslParameters.h"
#include "XabslSymbols.h"
#include "XabslOption.h"
#include "XabslDecimalExpression.h"
#include "XabslBooleanExpression.h"
#include "XabslEnumeratedExpression.h"
namespace xabsl
{
void Parameters::reset()
{
for (int i=0; i<decimal.getSize(); i++) *decimal[i] = 0;
for (int i=0; i<boolean.getSize(); i++) *boolean[i] = false;
for (int i=0; i<enumerated.getSize(); i++) *enumerated[i] = enumerations[i]->enumElements[0]->v;
}
void Parameters::registerEnumerations(NamedArray<Enumeration*>& enumerations)
{
pEnumerations = &enumerations;
}
void Parameters::registerDecimal(const char* name, double& parameter)
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal parameter \"%s\"",name));
if (decimal.exists(name))
{
errorHandler.error("registerDecimalParameter(): decimal parameter \"%s\" was already registered",name);
return;
}
decimal.append(name,&parameter);
parameter = 0;
}
void Parameters::registerBoolean(const char* name, bool& parameter)
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean parameter \"%s\"",name));
if (boolean.exists(name))
{
errorHandler.error("registerBooleanParameter(): boolean parameter \"%s\" was already registered",name);
return;
}
boolean.append(name,&parameter);
parameter = false;
}
void Parameters::registerEnumerated(const char* name, const char* enumName, int& parameter)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated parameter \"%s\"",name));
if (pEnumerations == 0)
{
errorHandler.error("XabslParameters::registerEnumerated(): call Parameters::registerEnumerations first");
return;
}
if (enumerated.exists(name))
{
errorHandler.error("XabslParameters::registerEnumerated(): enumerated parameter \"%s\" was already registered",name);
return;
}
if (!pEnumerations->exists(enumName))
{
errorHandler.error("XabslParameters::registerEnumerated(): enumeration \"%s\" was not registered",enumName);
return;
}
const Enumeration* enumeration = (*pEnumerations)[enumName];
if (enumeration->enumElements.getSize() == 0)
{
errorHandler.error("XabslParameters::registerEnumerated(): no enumeration elements for \"%s\" were registered",enumName);
return;
}
enumerations.append(name, enumeration);
enumerated.append(name,&parameter);
parameter = enumeration->enumElements[0]->v;
}
ParameterAssignment::ParameterAssignment(
Parameters* refParameters,
ErrorHandler& errorHandler) :
Parameters(errorHandler)
{
for (int i = 0; i < refParameters->decimal.getSize(); i++)
{
decimal.append(refParameters->decimal.getName(i), refParameters->decimal.getElement(i));
decimalValues.append(refParameters->decimal.getName(i), 0);
decimalExpressions.append(refParameters->decimal.getName(i), new DecimalValue(0));
}
for (int i = 0; i < refParameters->boolean.getSize(); i++)
{
boolean.append(refParameters->boolean.getName(i), refParameters->boolean.getElement(i));
booleanValues.append(refParameters->boolean.getName(i), false);
booleanExpressions.append(refParameters->boolean.getName(i), new BooleanValue(false));
}
for (int i = 0; i < refParameters->enumerated.getSize(); i++)
{
enumerated.append(refParameters->enumerated.getName(i), refParameters->enumerated.getElement(i));
enumeratedValues.append(refParameters->enumerated.getName(i), false);
enumeratedExpressions.append(refParameters->enumerated.getName(i), new EnumeratedValue(refParameters->enumerations[i], 0));
}
}
void ParameterAssignment::create(
InputSource& input,
Symbols& symbols,
Option& option,
State& state)
{
int i;
// read the parameters
int numberOfParameters = (int)input.readValue();
for (i = 0; i<numberOfParameters; i++)
{
char c[2];
char buf[100];
input.readString(c,1);
switch(c[0])
{
case 'd':
{
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating expession for set decimal parameter \"%s\"",buf));
const DecimalExpression* exp = DecimalExpression::create(input,errorHandler,symbols,option,state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslParameterAssignment::create(): could not create decimal expression for parameter \"%s\"",buf);
return;
}
if (!setDecimalParameter(buf, exp)) return;
}
break;
case 'b':
{
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating expession for set boolean parameter \"%s\"",buf));
const BooleanExpression* exp = BooleanExpression::create(input,errorHandler,symbols,option,state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslParameterAssignment::create(): could not create boolean expression for parameter \"%s\"",buf);
return;
}
if (!setBooleanParameter(buf, exp)) return;
}
break;
case 'e':
{
input.readString(buf,99);
if(!symbols.enumerations.exists(buf))
{
errorHandler.error("XabslParameterAssignment::create(): enumeration \"%s\" was not registered",buf);
return;
}
const Enumeration* enumeration = symbols.enumerations[buf];
input.readString(buf,99);
XABSL_DEBUG_INIT(errorHandler.message("creating expession for set enumerated parameter \"%s\"",buf));
const EnumeratedExpression* exp = EnumeratedExpression::create(enumeration,input,errorHandler,symbols,option,state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslParameterAssignment::create(): could not create enumerated expression for parameter \"%s\"",buf);
return;
}
if (!setEnumeratedParameter(buf, exp)) return;
}
break;
}
}
}
ParameterAssignment::~ParameterAssignment()
{
for (int i=0; i<decimalExpressions.getSize(); i++)
delete decimalExpressions[i];
for (int i=0; i<booleanExpressions.getSize(); i++)
delete booleanExpressions[i];
for (int i=0; i<enumeratedExpressions.getSize(); i++)
delete enumeratedExpressions[i];
}
bool ParameterAssignment::setDecimalParameter(const char* param, const DecimalExpression* exp)
{
if (!decimalExpressions.exists(param))
{
errorHandler.error("XabslParameterAssignment::setDecimalParameter(): decimal parameter \"%s\" does not exist", param);
delete exp;
return false;
}
delete decimalExpressions[param];
decimalExpressions.setElement(param, exp);
return true;
}
bool ParameterAssignment::setBooleanParameter(const char* param, const BooleanExpression* exp)
{
if (!booleanExpressions.exists(param))
{
errorHandler.error("XabslParameterAssignment::setBooleanParameter(): boolean parameter \"%s\" does not exist",param);
delete exp;
return false;
}
delete booleanExpressions[param];
booleanExpressions.setElement(param, exp);
return true;
}
bool ParameterAssignment::setEnumeratedParameter(const char* param, const EnumeratedExpression* exp)
{
if (!enumeratedExpressions.exists(param))
{
errorHandler.error("XabslParameterAssignment::create(): enumerated parameter \"%s\" does not exist",param);
delete exp;
return false;
}
if (exp->enumeration != enumeratedExpressions[param]->enumeration)
{
errorHandler.error("XabslParameterAssignment::create(): type mismatch on enumerated parameter \"%s\", expected \"%s\", found \"%s\"", param, enumeratedExpressions[param]->enumeration->n, exp->enumeration->n);
return false;
}
delete enumeratedExpressions[param];
enumeratedExpressions.setElement(param, exp);
return true;
}
bool ParameterAssignment::setDecimalParameter(const char* param, double value)
{
return setDecimalParameter(param, new DecimalValue(value));
}
bool ParameterAssignment::setBooleanParameter(const char* param, bool value)
{
return setBooleanParameter(param, new BooleanValue(value));
}
bool ParameterAssignment::setEnumeratedParameter(const char* param, const Enumeration* enumeration, int value)
{
return setEnumeratedParameter(param, new EnumeratedValue(enumeration, value));
}
bool ParameterAssignment::setEnumeratedParameter(const char* param, const char* value)
{
if (!enumeratedExpressions.exists(param))
{
return false;
}
else if (!enumeratedExpressions[param]->enumeration->enumElements.exists(value))
{
return false;
}
else
{
return setEnumeratedParameter(param, enumeratedExpressions[param]->enumeration, enumeratedExpressions[param]->enumeration->enumElements[value]->v);
}
}
bool ParameterAssignment::set()
{
int i;
bool parametersChanged = false;
// Set the parameters.
for (i=0; i<decimal.getSize(); i++)
{
decimalValues.setElement(i, decimalExpressions[i]->getValue());
if (*decimal[i] != decimalValues[i])
{
parametersChanged = true;
*decimal[i] = decimalValues[i];
}
}
for (i=0; i<boolean.getSize(); i++)
{
booleanValues.setElement(i, booleanExpressions[i]->getValue());
if (*boolean[i] != booleanValues[i])
{
parametersChanged = true;
*boolean[i] = booleanValues[i];
}
}
for (i=0; i<enumerated.getSize(); i++)
{
enumeratedValues.setElement(i, enumeratedExpressions[i]->getValue());
if (*enumerated[i] != enumeratedValues[i])
{
parametersChanged = true;
*enumerated[i] = enumeratedValues[i];
}
}
return parametersChanged;
}
} // namespace

View File

@ -0,0 +1,202 @@
/**
* @file XabslParameters.h
*
* Definition of class Parameters
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslParameters_h_
#define __XabslParameters_h_
#include "XabslTools.h"
namespace xabsl
{
// class prototypes needed for declaration of Parameters
class Symbols;
class Enumeration;
class Option;
class State;
class DecimalExpression;
class BooleanExpression;
class EnumeratedExpression;
/**
* @class Parameters
*
* Represents the current set of parameters of a behavior or an input symbol
*/
class Parameters
{
public:
/**
* Constructor.
* @param errorHandler A reference to a ErrorHandler instance
*/
Parameters(ErrorHandler& errorHandler)
: errorHandler(errorHandler), pEnumerations(0)
{}
/**
* Destructor
*/
virtual ~Parameters() {};
/** Reset all parameters to default values (=0) */
void reset();
/** The decimal parameters */
NamedArray<double*> decimal;
/** The boolean parameters */
NamedArray<bool*> boolean;
/** The enumerated parameters */
NamedArray<int*> enumerated;
/** The enumeration domain of the enumerated parameters */
NamedArray<const Enumeration*> enumerations;
/**
* Registers a reference to the enumerations of the engine
* This is only required when registerEnumerated is called afterwards
*/
void registerEnumerations(NamedArray<Enumeration*>& enumerations);
/**
* Registers a reference to a decimal parameter at the parameters array.
* @param name The name of the parameter
* @param parameter The reference to a parameter
*/
void registerDecimal(const char* name, double& parameter);
/**
* Registers a reference to a boolean parameter at the parameters array.
* @param name The name of the parameter
* @param parameter The reference to a parameter
*/
void registerBoolean(const char* name, bool& parameter);
/**
* Registers a reference to an enumerated parameter at the parameters array.
* @param name The name of the parameter
* @param enumName The name of the corresponding enumeration
* @param parameter The reference to a parameter
*/
void registerEnumerated(const char* name, const char* enumName, int& parameter);
protected:
/** Used for error handling */
ErrorHandler& errorHandler;
private:
/** Pointer to the enumerations of the engine */
NamedArray<Enumeration*>* pEnumerations;
};
/**
* @class ParameterAssignment
*
* Represents the assignment of parameters of a subsequent basic behaviors or an option or an input symbol
*/
class ParameterAssignment : public Parameters
{
public:
/** Constructor.
* @param refParameters The referenced set of parameters
* @param errorHandler A reference to a ErrorHandler instance
*/
ParameterAssignment(
Parameters* refParameters,
ErrorHandler& errorHandler
);
/**
* Creates the parameter assignment.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a state starts.
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
void create(
InputSource& input,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
~ParameterAssignment();
/** Adds a decimal parameter assignment
* @param param name of the parameter
* @param exp expression to be set to the parameter value when executing
* @return False, if an error occurred
*/
bool setDecimalParameter(const char* param, const DecimalExpression* exp);
/** Adds a decimal parameter assignment
* @param param name of the parameter
* @param value value to be set to the parameter value when executing
* @return False, if an error occurred
*/
bool setDecimalParameter(const char* param, double value);
/** Adds a boolean parameter assignment
* @param param name of the parameter
* @param exp expression to be set to the parameter value when executing
* @return False, if an error occurred
*/
bool setBooleanParameter(const char* param, const BooleanExpression* exp);
/** Adds a boolean parameter assignment
* @param param name of the parameter
* @param value value to be set to the parameter value when executing
* @return False, if an error occurred
*/
bool setBooleanParameter(const char* param, bool value);
/** Adds an enumerated parameter assignment
* @param param name of the parameter
* @param exp expression to be set to the parameter value when executing
* @return False, if an error occurred
*/
bool setEnumeratedParameter(const char* param, const EnumeratedExpression* exp);
/** Adds an enumerated parameter assignment
* @param param name of the parameter
* @param value value to be set to the parameter value when executing
* @return False, if an error occurred
*/
bool setEnumeratedParameter(const char* param, const Enumeration* enumeration, int value);
/** Adds an enumerated parameter assignment
* @param param name of the parameter
* @param value value to be set to the parameter value when executing
* @return False, if an error occurred
*/
bool setEnumeratedParameter(const char* param, const char* value);
/** Current parameter values, these are stored just for debugging purposes */
NamedArray<double> decimalValues;
NamedArray<bool> booleanValues;
NamedArray<int> enumeratedValues;
/** Decimal expressions for the parameters */
NamedArray<const DecimalExpression*> decimalExpressions;
/** Boolean expressions for the parameters */
NamedArray<const BooleanExpression*> booleanExpressions;
/** Enumerated expressions for the parameters */
NamedArray<const EnumeratedExpression*> enumeratedExpressions;
/**
* sets parameter variables to current expression values
* returns true when parameter values have been changed
*/
bool set();
};
} // namespace
#endif // __XabslParameters_h_

View File

@ -0,0 +1,112 @@
/**
* @file XabslState.cpp
*
* Implementation of class State and helper classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslState.h"
#include "XabslOption.h"
namespace xabsl
{
State* TransitionToState::getNextState()
{
return nextState;
}
State::State(const char* name, ErrorHandler& errorHandler,
const unsigned& time,
int optionIndex,
int index)
: NamedItem(name),
targetState(false),
errorHandler(errorHandler),
decisionTree(0),
time(time),
optionIndex(optionIndex),
index(index)
{
}
State::~State()
{
if (decisionTree != 0) delete decisionTree;
for (int i=0; i<actions.getSize(); i++)
delete actions[i];
}
void State::create(InputSource& input,
NamedArray<Option*>& options,
NamedArray<BasicBehavior*>& basicBehaviors,
NamedArray<State*>& states,
Symbols& symbols)
{
XABSL_DEBUG_INIT(errorHandler.message("creating state \"%s\"",n));
char c[100];
int i;
// target state or not
input.readString(c,1);
if (*c == '1')
{
targetState = true;
}
// subsequent option, basic behaviors and output symbol assignments
int numberOfActions = (int)input.readValue();
subsequentOption = 0;
for(i = 0; i< numberOfActions; i++)
{
Action* action =
Action::create(input,
options,
basicBehaviors,
symbols,
*options[optionIndex],
*this,
errorHandler,
time);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslState::create(): could not create action for state \"%s\"",n);
return;
}
if (subsequentOption == 0)
if (ActionOption* actionOption = dynamic_cast<ActionOption*>(action))
subsequentOption = actionOption->option;
actions.append(action);
}
// transition to state or if / else block
decisionTree = Statement::createStatement(input,errorHandler,symbols,*options[optionIndex],*this);
if (errorHandler.errorsOccurred)
errorHandler.error("XabslState::create(): could not create decision tree for state \"%s\"",n);
}
State* State::getNextState()
{
timeOfStateExecution = time - timeWhenStateWasActivated;
State* nextState = decisionTree->getNextState();
return nextState->coopCheck() ? nextState : this;
}
void State::reset()
{
timeWhenStateWasActivated = time;
timeOfStateExecution = 0;
}
bool State::isTargetState() const
{
return targetState;
}
} // namespace

View File

@ -0,0 +1,124 @@
/**
* @file XabslState.h
*
* Definition of class State and Helper classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslState_h_
#define __XabslState_h_
#include "XabslStatement.h"
#include "XabslBasicBehavior.h"
#include "XabslDecimalExpression.h"
#include "XabslBooleanExpression.h"
#include "XabslEnumeratedExpression.h"
#include "XabslAction.h"
namespace xabsl
{
// class prototype needed for declaration of State
class Option;
/**
* @class State
*
* Represents a single state written in
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class State : public NamedItem
{
public:
/**
* Constructor. Does not create the state.
* @param name The name of the state. For debugging purposes.
* @param errorHandler A reference to a ErrorHandler instance
* @param time The system time in ms.
* @param optionIndex Index of the corresponding option this state belongs to
* @param index Index of the state in array states in corresponding option
*/
State(const char* name,
ErrorHandler& errorHandler,
const unsigned& time,
int optionIndex,
int index);
/** Destructor */
~State();
/**
* Creates the state and it's subelements from the intermediate code.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a state starts.
* @param options All available options
* @param basicBehaviors All available basicBehaviors
* @param states All states of the option
* @param symbols All available symbols
*/
void create(InputSource& input,
NamedArray<Option*>& options,
NamedArray<BasicBehavior*>& basicBehaviors,
NamedArray<State*>& states,
Symbols& symbols);
/**
* Executes the decision tree and determines the next active state (can be the same).
*/
virtual State* getNextState();
/** The actions of the state */
Array<Action*> actions;
/**
* The first subsequent option that is executed after that option if the state is active.
* If 0, no subsequent option is executed after that option.
* This pointer is present just for compatibility reasons, please use getactions instead
*/
Option* subsequentOption;
/** The time how long the state is already active */
unsigned timeOfStateExecution;
/** Sets the time when the state was activated to 0 */
void reset();
/** Returns wheter the state is a target state */
bool isTargetState() const;
/** Index of the state in array states in corresponding option */
int index;
/** The time, when the state was activated */
unsigned timeWhenStateWasActivated;
/** Index of the corresponding option this state belongs to */
int optionIndex;
/** Check whether this state can be entered, or whether entering is blocked due to cooperating agents */
virtual bool coopCheck() {return true;}
/** Whether this state is currently conflicted, i.e whether cooperation conditions are violated */
virtual bool getConflict() {return false;}
protected:
/** If true, the state is a target state */
bool targetState;
/** Used for error handling */
ErrorHandler& errorHandler;
/** The root element of the decision tree */
Statement* decisionTree;
/** The system time in ms. */
const unsigned& time;
};
} // namespace
#endif //__XabslState_h_

View File

@ -0,0 +1,118 @@
/**
* @file XabslStatement.cpp
*
* Implementation of class Statement and helper classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslStatement.h"
#include "XabslState.h"
#include "XabslOption.h"
namespace xabsl
{
Statement* Statement::createStatement(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state)
{
char c[100];
input.readString(c,1);
switch (*c)
{
case 't':
return new TransitionToState(input, errorHandler, option);
case 'i':
return new IfElseBlock(input, errorHandler, symbols, option, state);
default:
errorHandler.error("XabslStatement::create(): unknown type \"%c\"",*c);
return 0;
}
}
Statement::~Statement()
{
}
IfElseBlock::IfElseBlock(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state) :
ifCondition(0), ifStatement(0), elseStatement(0)
{
// if case
XABSL_DEBUG_INIT(errorHandler.message("creating if statement"));
ifCondition = BooleanExpression::create(input, errorHandler, symbols, option, state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslIfElseBlock::IfElseBlock(): could not create if condition");
return;
}
ifStatement = Statement::createStatement(input, errorHandler, symbols, option, state);
if (errorHandler.errorsOccurred)
{
errorHandler.error("XabslIfElseBlock::IfElseBlock(): could not create if statement");
return;
}
// else case
XABSL_DEBUG_INIT(errorHandler.message("creating else statement"));
elseStatement = Statement::createStatement(input, errorHandler, symbols, option, state);
if (errorHandler.errorsOccurred)
errorHandler.error("XabslIfElseBlock::IfElseBlock(): could not create else statement");
}
IfElseBlock::~IfElseBlock()
{
if (ifCondition != 0) delete ifCondition;
if (ifStatement != 0) delete ifStatement;
int i;
for (i=0; i<elseIfStatements.getSize(); i++)
{
if (elseIfConditions[i] != 0)
delete elseIfConditions[i];
if (elseIfStatements[i] != 0)
delete elseIfStatements[i];
}
if (elseStatement != 0) delete elseStatement;
}
State* IfElseBlock::getNextState()
{
if (ifCondition->getValue()) return ifStatement->getNextState();
for (int i=0; i<elseIfConditions.getSize(); i++)
{
if (elseIfConditions[i]->getValue()) return elseIfStatements[i]->getNextState();
}
return elseStatement->getNextState();
}
TransitionToState::TransitionToState(InputSource& input,
ErrorHandler& errorHandler,
Option& option)
{
char buf[100];
input.readString(buf,99);
nextState = option.states[buf];
XABSL_DEBUG_INIT(errorHandler.message("creating a transition to state \"%s\"",nextState->n));
}
} // namespace

View File

@ -0,0 +1,131 @@
/**
* @file XabslStatement.h
*
* Definition of class Statement and Helper classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslStatement_h_
#define __XabslStatement_h_
#include "XabslBooleanExpression.h"
namespace xabsl
{
// class prototype needed for the declaration of Statement
class State;
/**
* @class Statement
*
* An element of a decision that that determines a transition to a state.
* It can be either a transition to a state or a if/else-if/else block containing other statements.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class Statement
{
public:
/** Executes the statement and determines the next active state (can be the same). */
virtual State* getNextState() = 0;
/**
* Creates a statement depending on the input.
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a statement starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
static Statement* createStatement(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state);
/** Destructor */
virtual ~Statement() = 0;
};
/**
* @class IfElseBlock
*
* An element of a decision tree that that contains of an if - (else-if) - else block
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class IfElseBlock : public Statement
{
public:
/**
* Constructor. Creates the if / else statement
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a transition starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param symbols All available symbols
* @param option The current option
* @param state The current state
*/
IfElseBlock(InputSource& input,
ErrorHandler& errorHandler,
Symbols& symbols,
Option& option,
State& state
);
/** Destructor. Deletes all statements and conditions */
~IfElseBlock();
/** Executes the statement and determines the next active state (can be the same). */
virtual State* getNextState();
private:
/** The boolean expression that is evaluated for the if case */
BooleanExpression* ifCondition;
/** The statement that is executed if the if condition is true */
Statement* ifStatement;
/** The boolean expressions for the else-if cases */
NamedArray<BooleanExpression*> elseIfConditions;
/** The statements that are executed if the else-if condition are true */
NamedArray<Statement*> elseIfStatements;
/** The statement that is executed if all if and else-if conditions fail */
Statement* elseStatement;
};
/**
* Represents a transition to a state inside a decision tree
*/
class TransitionToState : public Statement
{
public:
/**
* Constructor. Creates the transition object
* @param input An input source for the intermediate code. It must be opened and read until
* A position where a transition starts.
* @param errorHandler A reference to a ErrorHandler instance
* @param option The current option
*/
TransitionToState(InputSource& input,
ErrorHandler& errorHandler,
Option& option);
/** Executes the statement and determines the next active state (can be the same). */
virtual State* getNextState();
private:
/** The state where that transition points to */
State* nextState;
};
} // namespace
#endif // __XabslStatement_h_

View File

@ -0,0 +1,464 @@
/**
* @file XabslSymbols.cpp
*
* Implementation of class Symbols and helper classes
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#include "XabslSymbols.h"
namespace xabsl
{
Enumeration::~Enumeration()
{
int i;
for (i=0; i< enumElements.getSize(); i++)
{
delete enumElements[i];
}
}
Symbols::~Symbols()
{
int i;
for (i=0; i< enumerations.getSize(); i++) delete enumerations[i];
for (i=0; i< decimalInputSymbols.getSize(); i++) delete decimalInputSymbols[i];
for (i=0; i< booleanInputSymbols.getSize(); i++) delete booleanInputSymbols[i];
for (i=0; i< enumeratedInputSymbols.getSize(); i++) delete enumeratedInputSymbols[i];
for (i=0; i< decimalOutputSymbols.getSize(); i++) delete decimalOutputSymbols[i];
for (i=0; i< booleanOutputSymbols.getSize(); i++) delete booleanOutputSymbols[i];
for (i=0; i< enumeratedOutputSymbols.getSize(); i++) delete enumeratedOutputSymbols[i];
}
void Symbols::registerEnumElement(const char* symbolName, const char* name, int value)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enum element \"%s\" for enumeration \"%s\"",name, symbolName));
if (!enumerations.exists(symbolName))
{
enumerations.append(symbolName, new Enumeration(symbolName, enumerations.getSize()));
}
if (enumerations[symbolName]->enumElements.exists(name))
{
errorHandler.error("registerEnumElement(): enum element \"%s\" for enumeration \"%s\" was already registered.", name, symbolName);
return;
}
enumerations[symbolName]->enumElements.append(name, new EnumElement(name,value));
}
void Symbols::registerDecimalInputSymbol(const char* name, const double* pVariable)
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal input symbol \"%s\"",name));
if (decimalInputSymbols.exists(name))
{
errorHandler.error("registerDecimalInputSymbol(): symbol \"%s\" was already registered",name);
return;
}
decimalInputSymbols.append(name,new DecimalInputSymbol(name, pVariable, errorHandler, decimalInputSymbols.getSize()));
}
void Symbols::registerDecimalInputSymbol
(const char* name,
double (*pFunction)())
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal input symbol \"%s\"",name));
if (decimalInputSymbols.exists(name))
{
errorHandler.error("registerDecimalInputSymbol(): symbol \"%s\" was already registered",name);
return;
}
decimalInputSymbols.append(name,new DecimalInputSymbol(name, pFunction, errorHandler, decimalInputSymbols.getSize()));
}
void Symbols::registerDecimalInputSymbolParametersChanged(const char* name,
void (*pFunction)())
{
XABSL_DEBUG_INIT(errorHandler.message("registering parameter change notification for decimal input symbol\"%s\"",name));
if (!decimalInputSymbols.exists(name))
{
errorHandler.error("registerDecimalInputSymbolParametersChanged(): symbol \"%s\" was not registered",name);
return;
}
decimalInputSymbols[name]->pParametersChanged = pFunction;
}
void Symbols::registerDecimalInputSymbolDecimalParameter(const char* symbolName,
const char* name, double* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal parameter \"%s\" for decimal input symbol\"%s\"",name, symbolName));
if (!decimalInputSymbols.exists(symbolName))
{
errorHandler.error("registerDecimalInputSymbolDecimalParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (decimalInputSymbols[symbolName]->parameters.decimal.exists(name))
{
errorHandler.error("registerDecimalInputSymbolDecimalParameter(): parameter \"%s\" was already registered",name);
return;
}
decimalInputSymbols[symbolName]->parameters.decimal.append(name,pParam);
}
void Symbols::registerDecimalInputSymbolBooleanParameter(const char* symbolName,
const char* name, bool* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean parameter \"%s\" for decimal input symbol\"%s\"",name, symbolName));
if (!decimalInputSymbols.exists(symbolName))
{
errorHandler.error("registerDecimalInputSymbolBooleanParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (decimalInputSymbols[symbolName]->parameters.boolean.exists(name))
{
errorHandler.error("registerDecimalInputSymbolBooleanParameter(): parameter \"%s\" was already registered",name);
return;
}
decimalInputSymbols[symbolName]->parameters.boolean.append(name,pParam);
}
void Symbols::registerDecimalInputSymbolEnumeratedParameter(const char* symbolName,
const char* name, const char* enumName, int* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated parameter \"%s\" for decimal input symbol\"%s\"",name, symbolName));
if (!decimalInputSymbols.exists(symbolName))
{
errorHandler.error("registerDecimalInputSymbolEnumeratedParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (decimalInputSymbols[symbolName]->parameters.enumerated.exists(name))
{
errorHandler.error("registerDecimalInputSymbolEnumeratedParameter(): parameter \"%s\" was already registered",name);
return;
}
if (!enumerations.exists(enumName))
{
enumerations.append(enumName, new Enumeration(enumName, enumerations.getSize()));
}
decimalInputSymbols[symbolName]->parameters.enumerations.append(name,enumerations.getElement(enumName));
decimalInputSymbols[symbolName]->parameters.enumerated.append(name,pParam);
}
void Symbols::registerBooleanInputSymbol(const char* name, const bool* pVariable)
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean input symbol \"%s\"",name));
if (booleanInputSymbols.exists(name))
{
errorHandler.error("registerBooleanInputSymbol(): symbol \"%s\" was already registered",name);
return;
}
booleanInputSymbols.append(name,new BooleanInputSymbol(name, pVariable, errorHandler, booleanInputSymbols.getSize()));
}
void Symbols::registerBooleanInputSymbol(const char* name,
bool (*pFunction)())
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean input symbol \"%s\"",name));
if (booleanInputSymbols.exists(name))
{
errorHandler.error("registerBooleanInputSymbol(): symbol \"%s\" was already registered",name);
return;
}
booleanInputSymbols.append(name,new BooleanInputSymbol(name, pFunction, errorHandler, booleanInputSymbols.getSize()));
}
void Symbols::registerBooleanInputSymbolParametersChanged(const char* name,
void (*pFunction)())
{
XABSL_DEBUG_INIT(errorHandler.message("registering parameter change notification for boolean input symbol\"%s\"",name));
if (!booleanInputSymbols.exists(name))
{
errorHandler.error("registerBooleanInputSymbolParametersChanged(): symbol \"%s\" was not registered",name);
return;
}
booleanInputSymbols[name]->pParametersChanged = pFunction;
}
void Symbols::registerBooleanInputSymbolDecimalParameter(const char* symbolName,
const char* name, double* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal parameter \"%s\" for boolean input symbol\"%s\"",name, symbolName));
if (!booleanInputSymbols.exists(symbolName))
{
errorHandler.error("registerBooleanInputSymbolDecimalParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (booleanInputSymbols[symbolName]->parameters.decimal.exists(name))
{
errorHandler.error("registerBooleanInputSymbolDecimalParameter(): parameter \"%s\" was already registered",name);
return;
}
booleanInputSymbols[symbolName]->parameters.decimal.append(name,pParam);
}
void Symbols::registerBooleanInputSymbolBooleanParameter(const char* symbolName,
const char* name, bool* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean parameter \"%s\" for boolean input symbol\"%s\"",name, symbolName));
if (!booleanInputSymbols.exists(symbolName))
{
errorHandler.error("registerBooleanInputSymbolBooleanParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (booleanInputSymbols[symbolName]->parameters.boolean.exists(name))
{
errorHandler.error("registerBooleanInputSymbolBooleanParameter(): parameter \"%s\" was already registered",name);
return;
}
booleanInputSymbols[symbolName]->parameters.boolean.append(name,pParam);
}
void Symbols::registerBooleanInputSymbolEnumeratedParameter(const char* symbolName,
const char* name, const char* enumName, int* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated parameter \"%s\" for boolean input symbol\"%s\"",name, symbolName));
if (!booleanInputSymbols.exists(symbolName))
{
errorHandler.error("registerBooleanInputSymbolEnumeratedParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (booleanInputSymbols[symbolName]->parameters.enumerated.exists(name))
{
errorHandler.error("registerBooleanInputSymbolEnumeratedParameter(): parameter \"%s\" was already registered",name);
return;
}
if (!enumerations.exists(enumName))
{
enumerations.append(enumName, new Enumeration(enumName, enumerations.getSize()));
}
booleanInputSymbols[symbolName]->parameters.enumerations.append(name,enumerations.getElement(enumName));
booleanInputSymbols[symbolName]->parameters.enumerated.append(name,pParam);
}
void Symbols::registerEnumeratedInputSymbol(const char* name, const char* enumName, const int* pVariable)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated input symbol \"%s\"",name));
if (enumeratedInputSymbols.exists(name))
{
errorHandler.error("registerEnumeratedInputSymbol(): symbol \"%s\" was already registered",name);
return;
}
if (!enumerations.exists(enumName))
{
enumerations.append(enumName, new Enumeration(enumName, enumerations.getSize()));
}
enumeratedInputSymbols.append(name,new EnumeratedInputSymbol(name, enumerations[enumName], pVariable, errorHandler, enumeratedInputSymbols.getSize()));
}
void Symbols::registerEnumeratedInputSymbol(const char* name, const char* enumName,
int (*pFunction)())
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated input symbol \"%s\"",name));
if (enumeratedInputSymbols.exists(name))
{
errorHandler.error("registerEnumeratedInputSymbol(): symbol \"%s\" was already registered",name);
return;
}
if (!enumerations.exists(enumName))
{
enumerations.append(enumName, new Enumeration(enumName, enumerations.getSize()));
}
enumeratedInputSymbols.append(name,new EnumeratedInputSymbol(name, enumerations[enumName], pFunction, errorHandler, enumeratedInputSymbols.getSize()));
}
void Symbols::registerEnumeratedInputSymbolParametersChanged(const char* name,
void (*pFunction)())
{
XABSL_DEBUG_INIT(errorHandler.message("registering parameter change notification for enumerated input symbol\"%s\"",name));
if (!enumeratedInputSymbols.exists(name))
{
errorHandler.error("registerEnumeratedInputSymbolParametersChanged(): symbol \"%s\" was not registered",name);
return;
}
enumeratedInputSymbols[name]->pParametersChanged = pFunction;
}
void Symbols::registerEnumeratedInputSymbolDecimalParameter(const char* symbolName,
const char* name, double* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal parameter \"%s\" for enumerated input symbol\"%s\"",name, symbolName));
if (!enumeratedInputSymbols.exists(symbolName))
{
errorHandler.error("registerEnumeratedInputSymbolDecimalParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (enumeratedInputSymbols[symbolName]->parameters.decimal.exists(name))
{
errorHandler.error("registerEnumeratedInputSymbolDecimalParameter(): parameter \"%s\" was already registered",name);
return;
}
enumeratedInputSymbols[symbolName]->parameters.decimal.append(name,pParam);
}
void Symbols::registerEnumeratedInputSymbolBooleanParameter(const char* symbolName,
const char* name, bool* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean parameter \"%s\" for enumerated input symbol\"%s\"",name, symbolName));
if (!enumeratedInputSymbols.exists(symbolName))
{
errorHandler.error("registerEnumeratedInputSymbolBooleanParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (enumeratedInputSymbols[symbolName]->parameters.boolean.exists(name))
{
errorHandler.error("registerEnumeratedInputSymbolBooleanParameter(): parameter \"%s\" was already registered",name);
return;
}
enumeratedInputSymbols[symbolName]->parameters.boolean.append(name,pParam);
}
void Symbols::registerEnumeratedInputSymbolEnumeratedParameter(const char* symbolName,
const char* name, const char* enumName, int* pParam)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated parameter \"%s\" for enumerated input symbol\"%s\"",name, symbolName));
if (!enumeratedInputSymbols.exists(symbolName))
{
errorHandler.error("registerEnumeratedInputSymbolEnumeratedParameter(): symbol \"%s\" was not registered",symbolName);
return;
}
if (enumeratedInputSymbols[symbolName]->parameters.enumerated.exists(name))
{
errorHandler.error("registerEnumeratedInputSymbolEnumeratedParameter(): parameter \"%s\" was already registered",name);
return;
}
if (!enumerations.exists(enumName))
{
enumerations.append(enumName, new Enumeration(enumName, enumerations.getSize()));
}
enumeratedInputSymbols[symbolName]->parameters.enumerations.append(name,enumerations.getElement(enumName));
enumeratedInputSymbols[symbolName]->parameters.enumerated.append(name,pParam);
}
void Symbols::registerDecimalOutputSymbol(const char* name, double* pVariable)
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal output symbol \"%s\"",name));
if (decimalOutputSymbols.exists(name))
{
errorHandler.error("registerDcimalOutputSymbol(): symbol \"%s\" was already registered",name);
return;
}
decimalOutputSymbols.append(name,new DecimalOutputSymbol(name, pVariable, decimalOutputSymbols.getSize()));
}
void Symbols::registerDecimalOutputSymbol(const char* name,
void (*pSetFunction)(double),
double (*pGetFunction)()
)
{
XABSL_DEBUG_INIT(errorHandler.message("registering decimal output symbol \"%s\"",name));
if (decimalOutputSymbols.exists(name))
{
errorHandler.error("registerDecimalOutputSymbol(): symbol \"%s\" was already registered",name);
return;
}
decimalOutputSymbols.append(name,new DecimalOutputSymbol(name, pSetFunction, pGetFunction, decimalOutputSymbols.getSize()));
}
void Symbols::registerBooleanOutputSymbol(const char* name, bool* pVariable)
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean output symbol \"%s\"",name));
if (booleanOutputSymbols.exists(name))
{
errorHandler.error("registerBooleanOutputSymbol(): symbol \"%s\" was already registered",name);
return;
}
booleanOutputSymbols.append(name,new BooleanOutputSymbol(name, pVariable, booleanOutputSymbols.getSize()));
}
void Symbols::registerBooleanOutputSymbol(const char* name,
void (*pSetFunction)(bool),
bool (*pGetFunction)()
)
{
XABSL_DEBUG_INIT(errorHandler.message("registering boolean output symbol \"%s\"",name));
if (booleanOutputSymbols.exists(name))
{
errorHandler.error("registerBooleanOutputSymbol(): symbol \"%s\" was already registered",name);
return;
}
booleanOutputSymbols.append(name,new BooleanOutputSymbol(name, pSetFunction, pGetFunction, booleanOutputSymbols.getSize()));
}
void Symbols::registerEnumeratedOutputSymbol(const char* name, const char* enumName, int* pVariable)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated output symbol \"%s\"",name));
if (enumeratedOutputSymbols.exists(name))
{
errorHandler.error("registerEnumeratedOutputSymbol(): symbol \"%s\" was already registered",name);
return;
}
if (!enumerations.exists(enumName))
{
enumerations.append(enumName, new Enumeration(enumName, enumerations.getSize()));
}
enumeratedOutputSymbols.append(name,new EnumeratedOutputSymbol(name, enumerations[enumName], pVariable, enumeratedOutputSymbols.getSize()));
}
void Symbols::registerEnumeratedOutputSymbol(const char* name, const char* enumName,
void (*pSetFunction)(int),
int (*pGetFunction)()
)
{
XABSL_DEBUG_INIT(errorHandler.message("registering enumerated output symbol \"%s\"",name));
if (enumeratedOutputSymbols.exists(name))
{
errorHandler.error("registerEnumeratedOutputSymbol(): symbol \"%s\" was already registered",name);
return;
}
if (!enumerations.exists(enumName))
{
enumerations.append(enumName, new Enumeration(enumName, enumerations.getSize()));
}
enumeratedOutputSymbols.append(name,new EnumeratedOutputSymbol(name, enumerations[enumName], pSetFunction, pGetFunction, enumeratedOutputSymbols.getSize()));
}
void Symbols::resetOutputSymbols()
{
for (int i=0;i<decimalOutputSymbols.getSize();i++)
decimalOutputSymbols[i]->activeValueWasSet = false;
for (int i=0;i<booleanOutputSymbols.getSize();i++)
booleanOutputSymbols[i]->activeValueWasSet = false;
for (int i=0;i<enumeratedOutputSymbols.getSize();i++)
enumeratedOutputSymbols[i]->activeValueWasSet = false;
}
} // namespace

View File

@ -0,0 +1,635 @@
/**
* @file XabslSymbols.h
*
* Definition of class Symbols and helper classes
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslSymbols_h_
#define __XabslSymbols_h_
#include "XabslTools.h"
#include "XabslParameters.h"
namespace xabsl
{
/**
* @class EnumElement
* Represents an enum element that is part of an enumerated input or output symbol.
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class EnumElement : public NamedItem
{
public:
/**
* Constructor
* @param name The name of the enum element as specified in the XML formalization
* @param value The value for the element from the software environment
*/
EnumElement(const char* name, int value)
: NamedItem(name), v(value) {};
/** The enum value from a function or variable in the software environment */
int v;
};
/**
* @class Enumeration
*
* Represents a list of enum elements
*/
class Enumeration : public NamedItem
{
public:
/**
* Constructor
* @param name The name of the enumeration as specified in the XML formalization
* @param index Index of the enumeration in array enumerations in corresponding engine
*/
Enumeration(const char* name, int index) : NamedItem(name), index(index) {};
/** Destructor. Deletes the enum elements */
~Enumeration();
/**
* Assigns an enum value from a function or variable in the software environment
* to the enum-element string in the XML formalization.
*/
NamedArray<EnumElement*> enumElements;
/** Index of the enumeration in array enumerations in corresponding engine */
int index;
};
/**
* A Template for the input symbol classes
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
template<class T> class InputSymbol : public NamedItem
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
InputSymbol(const char* name, const T* pVariable, ErrorHandler& errorHandler, int index)
: NamedItem(name), parameters(errorHandler), pV(pVariable), pF(0), pParametersChanged(0), index(index), lastValue(0)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param pFunction A pointer to a boolean returning function in the software environment
* @param index Index of the symbol in array in corresponding engine
*/
InputSymbol(const char* name,
T (*pFunction)(),
ErrorHandler& errorHandler, int index)
: NamedItem(name), parameters(errorHandler), pV(0), pF(pFunction), pParametersChanged(0), index(index), lastValue(0) {};
/** returns the value of the symbol */
T getValue()
{ if (pF!=0) return lastValue = (*pF)(); else return lastValue = *pV; }
/** Notify the software environment about a parameter change */
void parametersChanged() const
{ if (pParametersChanged!=0) (*pParametersChanged)(); }
/** The parameters of the input symbol*/
Parameters parameters;
/** A Pointer to a parameter change notification function in the software environment */
void (*pParametersChanged)();
/** Index of the symbol in array in corresponding engine */
int index;
/** Last queried value of the input symbol */
T lastValue;
private:
/** A pointer to a variable in the software environment */
const T* pV;
/** A pointer to a T returning function in the software environment */
T (*pF)();
};
/**
* @class DecimalInputSymbol
*
* Represents a decimal input symbol of the Engine
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class DecimalInputSymbol : public InputSymbol<double>
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
DecimalInputSymbol(const char* name, const double* pVariable, ErrorHandler& errorHandler, int index)
: InputSymbol<double>(name, pVariable, errorHandler, index)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param pFunction A pointer to a double returning function in the software environment
* @param index Index of the symbol in array in corresponding engine
*/
DecimalInputSymbol(const char* name,
double (*pFunction)(),
ErrorHandler& errorHandler, int index)
: InputSymbol<double>(name, pFunction, errorHandler, index) {};
};
/**
* @class BooleanInputSymbol
*
* Represents a boolean input symbol of the Engine
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class BooleanInputSymbol : public InputSymbol<bool>
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
BooleanInputSymbol(const char* name, const bool* pVariable, ErrorHandler& errorHandler, int index)
: InputSymbol<bool>(name, pVariable, errorHandler, index)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param pFunction A pointer to a boolean returning function in the software environment
* @param index Index of the symbol in array in corresponding engine
*/
BooleanInputSymbol(const char* name,
bool (*pFunction)(),
ErrorHandler& errorHandler, int index)
: InputSymbol<bool>(name, pFunction, errorHandler, index) {};
};
/**
* @class EnumeratedInputSymbol
*
* Represents a enumerated input symbol of the Engine
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class EnumeratedInputSymbol : public InputSymbol<int>
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
EnumeratedInputSymbol(const char* name, Enumeration* enumeration, const int* pVariable,
ErrorHandler& errorHandler, int index)
: InputSymbol<int>(name, pVariable, errorHandler, index), enumeration(enumeration)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param enumeration Pointer to the list of enumeration elements
* @param pFunction A pointer to an int returning function in the software environment
* @param index Index of the symbol in array in corresponding engine
*/
EnumeratedInputSymbol(const char* name, Enumeration* enumeration,
int (*pFunction)(),
ErrorHandler& errorHandler, int index)
: InputSymbol<int>(name, pFunction, errorHandler, index), enumeration(enumeration) {};
/** Pointer to the list of enumeration elements */
Enumeration* enumeration;
};
/**
* @class OutputSymbol
*
* A Template for the output symbol classes
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
template<class T> class OutputSymbol : public NamedItem
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
OutputSymbol(const char* name, T* pVariable, int index)
: NamedItem(name), activeValueWasSet(false), pV(pVariable), pSetF(0), pGetF(0), index(index), lastValue(0)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param pSetFunction A pointer to a boolean accepting function in the software environment
* @param pGetFunction A pointer to a boolean returning function in the software environment
* @param index Index of the symbol in array in corresponding engine
*/
OutputSymbol(const char* name,
void (*pSetFunction)(T),
T (*pGetFunction)(), int index)
: NamedItem(name), activeValueWasSet(false), pV(0), pSetF(pSetFunction), pGetF(pGetFunction), index(index), lastValue(0)
{};
/** Set the value of the symbol. */
void setValue(T value)
{
if (pSetF!=0)
{
(*pSetF)(value);
}
else
{
*pV=value;
}
lastValue = value;
activeValueWasSet = true;
}
/** Returns the current value of the symbol. */
T getValue() const
{
if (pGetF!=0)
{
return (*pGetF)();
}
else
{
return *pV;
}
}
/** If true, the value was set during the last execution of the option graph. */
bool activeValueWasSet;
/** Index of the symbol in array in corresponding engine */
int index;
/** Last set value of the output symbol */
T lastValue;
private:
/** A pointer to a variable in the software environment */
T* pV;
/** A pointer to a function that sets the value of the symbol in the software environment */
void (*pSetF)(T);
/** A pointer to a function that gets the value of the symbol from the software environment */
T (*pGetF)();
};
/**
* @class DecimalOutputSymbol
*
* Represents a decimal output symbol of the Engine
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class DecimalOutputSymbol : public OutputSymbol<double>
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
DecimalOutputSymbol(const char* name, double* pVariable, int index)
: OutputSymbol<double>(name, pVariable, index)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param pSetFunction A pointer to a function in the software environment that sets the value of the symbol
* @param pGetFunction A pointer to a function in the software environment that returns the value of the symbol
* @param index Index of the symbol in array in corresponding engine
*/
DecimalOutputSymbol(const char* name,
void (*pSetFunction)(double),
double (*pGetFunction)(), int index)
: OutputSymbol<double>(name, pSetFunction, pGetFunction, index)
{};
};
/**
* @class BooleanOutputSymbol
*
* Represents a boolean output symbol of the Engine
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*
*/
class BooleanOutputSymbol : public OutputSymbol<bool>
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
BooleanOutputSymbol(const char* name, bool* pVariable, int index)
: OutputSymbol<bool>(name, pVariable, index)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param pSetFunction A pointer to a function in the software environment that sets the value of the symbol
* @param pGetFunction A pointer to a function in the software environment that returns the value of the symbol
* @param index Index of the symbol in array in corresponding engine
*/
BooleanOutputSymbol(const char* name,
void (*pSetFunction)(bool),
bool (*pGetFunction)(), int index)
: OutputSymbol<bool>(name, pSetFunction, pGetFunction, index)
{};
};
/**
* @class EnumeratedOutputSymbol
*
* Represents a enumerated output symbol of the Engine
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
class EnumeratedOutputSymbol : public OutputSymbol<int>
{
public:
/**
* Constructor
* @param name The name of the symbol, for debugging purposes
* @param enumeration Pointer to the list of enumeration elements
* @param pVariable A pointer to the variable that the symbol stands for
* @param index Index of the symbol in array in corresponding engine
*/
EnumeratedOutputSymbol(const char* name, Enumeration* enumeration, int* pVariable, int index)
: OutputSymbol<int>(name, pVariable, index), enumeration(enumeration)
{};
/** Constructor
* @param name The name of the symbol, for debugging purposes
* @param enumeration Pointer to the list of enumeration elements
* @param pSetFunction A pointer to a function in the software environment that sets the value of the symbol
* @param pGetFunction A pointer to a function in the software environment that returns the value of the symbol
* @param index Index of the symbol in array in corresponding engine
*/
EnumeratedOutputSymbol(const char* name, Enumeration* enumeration,
void (*pSetFunction)(int),
int (*pGetFunction)(), int index)
: OutputSymbol<int>(name, pSetFunction, pGetFunction, index), enumeration(enumeration)
{};
/** Pointer to the list of enumeration elements */
Enumeration* enumeration;
};
/**
* @class Symbols
*
* Handles the symbols of the Engine.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class Symbols
{
public:
/**
* Constructor.
* @param errorHandler Is invoked when errors occur
*/
Symbols(ErrorHandler& errorHandler)
: errorHandler(errorHandler) {};
/** Destructor */
virtual ~Symbols();
/**
* Registers an enum element for an enumeration.
* @param enumName The name of the enumeration
* @param name The name of the enum element
* @param value The value of the element
*/
void registerEnumElement(const char* enumName,
const char* name, int value);
/**
* Registers the address of a variable for a decimal input symbol.
* @param name The name of the symbol
* @param pVariable A pointer to a variable in the software environment
*/
void registerDecimalInputSymbol(const char* name, const double* pVariable);
/**
* Registers the address of a function for a decimal input symbol.
* @param name The name of the symbol
* @param pFunction A pointer to a function that calculates a value for the symbol
*/
void registerDecimalInputSymbol(const char* name,
double (*pFunction)());
/**
* Registers the address of a function for parameter change notification for a decimal input symbol.
* @param name The name of the symbol
* @param pFunction A pointer to the parameter change notification function
*/
void registerDecimalInputSymbolParametersChanged(const char* name,
void (*pFunction)());
/**
* Registers a parameter of a parameterized decimal input symbol.
* @param symbolName The name of the symbol
* @param name The name of the parameter
* @param pParam A pointer to the parameter
*/
void registerDecimalInputSymbolDecimalParameter(const char* symbolName,
const char* name, double* pParam);
void registerDecimalInputSymbolBooleanParameter(const char* symbolName,
const char* name, bool* pParam);
void registerDecimalInputSymbolEnumeratedParameter(const char* symbolName,
const char* name, const char* enumName, int* pParam);
/**
* Registers the address of a variable for a boolean input symbol.
* @param name The name of the symbol
* @param pVariable A pointer to a variable in the software environment
*/
void registerBooleanInputSymbol(const char* name, const bool* pVariable);
/**
* Registers the address of a function for a boolean input symbol.
* @param name The name of the symbol
* @param pFunction A pointer to a function that calculates a value for the symbol
*/
void registerBooleanInputSymbol(const char* name,
bool (*pFunction)());
/**
* Registers the address of a function for parameter change notification for a boolean input symbol.
* @param name The name of the symbol
* @param pFunction A pointer to the parameter change notification function
*/
void registerBooleanInputSymbolParametersChanged(const char* name,
void (*pFunction)());
/**
* Registers a parameter of a parameterized boolean input symbol.
* @param symbolName The name of the symbol
* @param name The name of the parameter
* @param pParam A pointer to the parameter
*/
void registerBooleanInputSymbolDecimalParameter(const char* symbolName,
const char* name, double* pParam);
void registerBooleanInputSymbolBooleanParameter(const char* symbolName,
const char* name, bool* pParam);
void registerBooleanInputSymbolEnumeratedParameter(const char* symbolName,
const char* name, const char* enumName, int* pParam);
/**
* Registers the address of a variable for a enumerated input symbol.
* @param name The name of the symbol
* @param enumName The name of the associated enumeration
* @param pVariable A pointer to a variable in the software environment
*/
void registerEnumeratedInputSymbol(const char* name, const char* enumName, const int* pVariable);
/**
* Registers the address of a function for a enumerated input symbol.
* @param name The name of the symbol
* @param enumName The name of the associated enumeration
* @param pFunction A pointer to a function that calculates a value for the symbol
*/
void registerEnumeratedInputSymbol(const char* name, const char* enumName,
int (*pFunction)());
/**
* Registers the address of a function for parameter change notification for an enumerated input symbol.
* @param name The name of the symbol
* @param pFunction A pointer to the parameter change notification function
*/
void registerEnumeratedInputSymbolParametersChanged(const char* name,
void (*pFunction)());
/**
* Registers a parameter of an enumerated input symbol.
* @param symbolName The name of the symbol
* @param name The name of the parameter
* @param pParam A pointer to the parameter
*/
void registerEnumeratedInputSymbolDecimalParameter(const char* symbolName,
const char* name, double* pParam);
void registerEnumeratedInputSymbolBooleanParameter(const char* symbolName,
const char* name, bool* pParam);
void registerEnumeratedInputSymbolEnumeratedParameter(const char* symbolName,
const char* name, const char* enumName, int* pParam);
/**
* Registers the address of a variable for a decimal output symbol.
* @param name The name of the symbol
* @param pVariable A pointer to a variable in the software environment
*/
void registerDecimalOutputSymbol(const char* name, double* pVariable);
/**
* Registers the address of a function for a decimal output symbol.
* @param name The name of the symbol
* @param pSetFunction A pointer to a function that sets a value for the symbol
* @param pGetFunction A pointer to a function that returns a value for the symbol
*/
void registerDecimalOutputSymbol(const char* name,
void (*pSetFunction)(double),
double (*pGetFunction)()
);
/**
* Registers the address of a variable for a boolean output symbol.
* @param name The name of the symbol
* @param pVariable A pointer to a variable in the software environment
*/
void registerBooleanOutputSymbol(const char* name, bool* pVariable);
/**
* Registers the address of a function for a boolean output symbol.
* @param name The name of the symbol
* @param pSetFunction A pointer to a function that sets a value for the symbol
* @param pGetFunction A pointer to a function that returns a value for the symbol
*/
void registerBooleanOutputSymbol(const char* name,
void (*pSetFunction)(bool),
bool (*pGetFunction)()
);
/**
* Registers the address of a variable for a enumerated output symbol.
* @param name The name of the symbol
* @param enumName The name of the associated enumeration
* @param pVariable A pointer to a variable in the software environment
*/
void registerEnumeratedOutputSymbol(const char* name, const char* enumName, int* pVariable);
/**
* Registers the address of a function for a enumerated output symbol.
* @param name The name of the symbol
* @param enumName The name of the associated enumeration
* @param pSetFunction A pointer to a function that sets a value for the symbol
* @param pGetFunction A pointer to a function that returns a value for the symbol
*/
void registerEnumeratedOutputSymbol(const char* name, const char* enumName,
void (*pSetFunction)(int),
int (*pGetFunction)()
);
/** Sets all output symbols to unset */
void resetOutputSymbols();
/** The enumerations */
NamedArray<Enumeration*> enumerations;
/** The decimal input symbols */
NamedArray<DecimalInputSymbol*> decimalInputSymbols;
/** The boolean input symbols */
NamedArray<BooleanInputSymbol*> booleanInputSymbols;
/** The enumerated input symbols */
NamedArray<EnumeratedInputSymbol*> enumeratedInputSymbols;
/** The decimal output symbols */
NamedArray<DecimalOutputSymbol*> decimalOutputSymbols;
/** The boolean output symbols */
NamedArray<BooleanOutputSymbol*> booleanOutputSymbols;
/** The enumerated output symbols */
NamedArray<EnumeratedOutputSymbol*> enumeratedOutputSymbols;
private:
/** Is invoked when errors occur */
ErrorHandler& errorHandler;
};
} // namespace
#endif //__XabslSymbols_h_

View File

@ -0,0 +1,56 @@
/**
* @file XabslTeamMessage.h
*
* Definition of class TeamMessage
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
#ifndef __XabslTeamMessage_h_
#define __XabslTeamMessage_h_
#include "XabslArray.h"
namespace xabsl
{
/**
* @class TeamMessage
*
* Represents an incoming or outgoing message transmitted from/to other cooperating agents
*
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
*/
class TeamMessage
{
public:
/**
* Constructor.
*/
TeamMessage() : agentPriority(0)
{};
/** An array containing indexes of currently executed cooperative states */
Array<int> coopStatesExecuted;
/** An array containing indexes of cooperative states, currently trying to be executed but blocked due to cooperating agents */
Array<int> coopStatesEntering;
/** An array containing indexes of cooperative states, whose corresponding option is being executed */
Array<int> coopStatesOptionExecuted;
/** Priority value of the agent, used for solving conflicts in cooperative state assignment */
int agentPriority;
/** Reset the content of the message */
void reset()
{
coopStatesExecuted.clear();
coopStatesEntering.clear();
coopStatesOptionExecuted.clear();
}
};
} // namespace
#endif //__XabslTeamMessage_h_

View File

@ -0,0 +1,49 @@
/**
* @file XabslTools.cpp
*
* Implementation of several helper classes for the Engine.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
*/
#include "XabslTools.h"
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
namespace xabsl
{
void ErrorHandler::error(const char* format, ...)
{
// get the argument list
va_list args;
va_start(args,format);
// print the expression to the buffer
vsprintf(messageBuffer,format,args);
printError(messageBuffer);
// delete the argument list
va_end(args);
errorsOccurred = true;
}
void ErrorHandler::message(const char* format, ...)
{
// get the argument list
va_list args;
va_start(args,format);
// print the expression to the buffer
vsprintf(messageBuffer,format,args);
printMessage(messageBuffer);
// delete the argument list
va_end(args);
}
} // namespace

View File

@ -0,0 +1,110 @@
/**
* @file XabslTools.h
*
* Definition of several helper classes for the Engine.
*
* @author <a href="http://www.martin-loetzsch.de">Martin Loetzsch</a>
* @author <a href="http://www.sim.informatik.tu-darmstadt.de/pers/card/risler.html">Max Risler</a>
* @author <a href="http://www.informatik.hu-berlin.de/~juengel">Matthias Juengel</a>
*/
#ifndef __XabslTools_h_
#define __XabslTools_h_
#include "XabslArray.h"
namespace xabsl
{
/**
* A Engine helper class for reading input data from files or from memory.
*/
class InputSource
{
public:
/** Virtual destructor */
virtual ~InputSource() {}
/** opens the source that contains the intermediate code */
virtual bool open() = 0;
/** closes the source */
virtual void close() = 0;
/** reads a numeric value from the input source */
virtual double readValue() = 0;
/**
* reads a string from the input source
* @param destination The position where to write the string
* @param maxLength the maximum length of the string
* @return if the read succeded
*/
virtual bool readString(char* destination, int maxLength) = 0;
};
/**
* A Engine helper class for handling errors and debug messages
*/
class ErrorHandler
{
public:
/** constructor */
ErrorHandler() : errorsOccurred(false) {};
/** virtual destructor */
virtual ~ErrorHandler() {}
/**
* Prints out an error
* @param text The text to display
*/
virtual void printError(const char* text) = 0;
/**
* Prints out a message
* @param text The text to display
*/
virtual void printMessage(const char* text) = 0;
/**
* Formats a error message and calls the printError() function.
* @param format Format string as used by printf defined in stdio.h.
* @param ... See printf in stdio.h.
*/
void error(const char* format, ...);
/**
* Formats a message and calls the printMessage() function
* @param format Format string as used by printf defined in stdio.h.
* @param ... See printf in stdio.h.
*/
void message(const char* format, ...);
/** if errors occurred */
bool errorsOccurred;
private:
/** a buffer for errors and debug messages */
char messageBuffer[300];
};
/**
* @typedef TimeFunction
* A pointer to a function that returns the current system time.
*/
typedef unsigned (*TimeFunction)();
// If that macro is defined, the engine prints a lot of debug messages during initialization
//#define _DO_DEBUG_INIT
/** Expressions inside that macro are only executed if XABSL_DEBUG_INIT is defined */
#ifdef _DO_DEBUG_INIT
#define XABSL_DEBUG_INIT(expression) expression
#else
#define XABSL_DEBUG_INIT(expression) /**/
#endif
} // namespace
#endif //__XabslTools_h_

View File

@ -0,0 +1,230 @@
# XabslMakefile
#
# Generates the documentation and intermediate code for a Xabsl project.
#
# author: Martin Loetzsch, Max Risler
#
# This Makefile should be included into a custom Makefile inside the directory, where the Xabsl sources are.
# Inside this custom Makefile these Variables have to be set:
# All paths are relative to the source files and the custom Makefile.
#
# AGENTS_FILE: File containing agent definitions
# SOURCES: List of all XABSL source files
#
# XABSL_OUTPUT_DIR: Directory where the intermediate code shall be generated
# XABSL_TEMP_DIR: Directory where XABSL compiler will store temporary files
# INTERMEDIATE_CODE: The filename of the intermediate code to be generated
# DEBUG_SYMBOLS: The filename of the debug symbols to be generated
# XML_OUTPUT_DIR: Directory where the xml files should be generated
# DOC_OUTPUT_DIR: Directory for the documentation output
#
# XABSL_COMPILER_DIR: Directory which contains the Xabsl compiler
# XABSL_COMPILER_OPTIONS: Additional optional parameters for the XABSL compiler
#
# XSLT: An XSLT processor that can process XInclude statements (with necessary parameters)
# DOT: Path of the dot tool
# DOTML_DIR: Directory that contains the DotML Schemas and XSLT stylesheets
# XABSL_XSL_DIR: Directory which contains the Xabsl XSLT Stylesheets
# General documentation output files
DOC_INDEX_HTML = $(DOC_OUTPUT_DIR)/index.html
DOC_AGENTS_HTML = $(DOC_OUTPUT_DIR)/agents.html
DOC_SYMBOLS_INDEX_HTML = $(DOC_OUTPUT_DIR)/symbols.html
DOC_OPTION_INDEX_HTML = $(DOC_OUTPUT_DIR)/options.html
DOC_BASIC_BEHAVIOR_INDEX_HTML = $(DOC_OUTPUT_DIR)/basic-behaviors.html
DOC_STYLES_CSS = $(DOC_OUTPUT_DIR)/styles.css
# Documentation XSLT Stylesheets
DOC_INDEX_XSL = $(XABSL_XSL_DIR)/generate-documentation.index.xsl
DOC_MENU_XSL = $(XABSL_XSL_DIR)/generate-documentation.menu.xsl
DOC_SYMBOLS_XSL = $(XABSL_XSL_DIR)/generate-documentation.symbols.xsl
DOC_SYMBOLS_INDEX_XSL = $(XABSL_XSL_DIR)/generate-documentation.symbols-index.xsl
DOC_AGENTS_XSL = $(XABSL_XSL_DIR)/generate-documentation.agents.xsl
DOC_BASIC_BEHAVIORS_XSL = $(XABSL_XSL_DIR)/generate-documentation.basic-behaviors.xsl
DOC_BASIC_BEHAVIOR_INDEX_XSL = $(XABSL_XSL_DIR)/generate-documentation.basic-behavior-index.xsl
DOC_OPTION_XSL = $(XABSL_XSL_DIR)/generate-documentation.option.xsl
DOC_OPTION_INDEX_XSL = $(XABSL_XSL_DIR)/generate-documentation.option-index.xsl
DOC_OPTION_TREE_XSL = $(XABSL_XSL_DIR)/generate-documentation.option-tree.xsl
DOC_PSEUDO_CODE_XSL = $(XABSL_XSL_DIR)/generate-documentation.pseudo-code.xsl
DOC_PARAMETERS_XSL = $(XABSL_XSL_DIR)/generate-documentation.parameters.xsl
REMOVE_COMMENTS_XSL = $(XABSL_XSL_DIR)/remove-comments.xsl
# XSLT Stylesheet for debug symbols
DEBUG_SYMBOLS_XSL = $(XABSL_XSL_DIR)/generate-debug-symbols.xsl
# XML output files
XML_SYMBOL_FILES := $(shell bash -c "shopt -s nullglob;echo $(XML_OUTPUT_DIR)/Symbols/*.xml")
XML_BASIC_BEHAVIOR_FILES := $(shell bash -c "shopt -s nullglob;echo $(XML_OUTPUT_DIR)/BasicBehaviors/*.xml")
XML_OPTION_FILES := $(shell bash -c "shopt -s nullglob;echo $(XML_OUTPUT_DIR)/Options/*.xml")
XML_FILES = $(XML_OUTPUT_DIR)/agents.xml $(XML_OUTPUT_DIR)/options.xml $(XML_OUTPUT_DIR)/symbol-and-basic-behavior-files.dtd $(XML_SYMBOL_FILES) $(XML_BASIC_BEHAVIOR_FILES) $(XML_OPTION_FILES)
# Documentation output files
DOC_SYMBOL_FILES = $(shell echo $(XML_SYMBOL_FILES) |sed "s%[^ ]*/%%g;s%\([^ ]*\)\.xml%$(DOC_OUTPUT_DIR)/symbols.\1.html%g")
DOC_BASIC_BEHAVIOR_FILES = $(shell echo $(XML_BASIC_BEHAVIOR_FILES) |sed "s%[^ ]*/%%g;s%\([^ ]*\)\.xml%$(DOC_OUTPUT_DIR)/basic-behaviors.\1.html%g")
DOC_OPTION_FILES = $(shell echo $(XML_OPTION_FILES) |sed "s%[^ ]*/%%g;s%\([^ ]*\)\.xml%$(DOC_OUTPUT_DIR)/option.\1.html%g")
# Generate intermediate code, documentation
all: $(XABSL_OUTPUT_DIR)/$(INTERMEDIATE_CODE) DOCUMENTATION DS
# Some shortcuts for common targets:
DOC: DOCUMENTATION
rebuild: clean
@make all
# Removes the documentation output directory, the intermediate code, the xml output directory and temp directory.
clean:
@rm -f $(XABSL_TEMP_DIR)/xabsl.*.dump
@rm -f $(XABSL_OUTPUT_DIR)/$(INTERMEDIATE_CODE)
@rm -f $(XABSL_OUTPUT_DIR)/$(DEBUG_SYMBOLS)
@rm -rf $(XML_OUTPUT_DIR)
@rm -rf $(DOC_OUTPUT_DIR)
# Shortcuts for intermediate code and debug symbols
IC : $(XABSL_OUTPUT_DIR)/$(INTERMEDIATE_CODE)
DS :
@make -s XML
@make -s $(XABSL_OUTPUT_DIR)/$(DEBUG_SYMBOLS)
# Generate intermediate code
$(XABSL_OUTPUT_DIR)/$(INTERMEDIATE_CODE) : $(SOURCES)
@echo compiling to intermediate code $(XABSL_OUTPUT_DIR)/$(INTERMEDIATE_CODE)
@make -s -C $(XABSL_COMPILER_DIR)
@ruby $(XABSL_COMPILER_DIR)/xabsl.rb $(XABSL_COMPILER_OPTIONS) -I $(XABSL_TEMP_DIR) -i $(XABSL_OUTPUT_DIR)/$(INTERMEDIATE_CODE) $(AGENTS_FILE)
# Call xabsl compiler for generating xml code
# Since there is an unknown number of source files this step is always done
XML : $(SOURCES)
@echo compiling to xml output in $(XML_OUTPUT_DIR)
@make -s -C $(XABSL_COMPILER_DIR)
@ruby $(XABSL_COMPILER_DIR)/xabsl.rb $(XABSL_COMPILER_OPTIONS) -I $(XABSL_TEMP_DIR) -x $(XABSL_TEMP_DIR)/new $(AGENTS_FILE)
@mkdir -p $(XML_OUTPUT_DIR)/Symbols
@mkdir -p $(XML_OUTPUT_DIR)/Options
@mkdir -p $(XML_OUTPUT_DIR)/BasicBehaviors
@for xmlfile in `find $(XABSL_TEMP_DIR)/new -type f -printf %P\\\\n`; do \
if test -f $(XML_OUTPUT_DIR)/$$xmlfile; then \
if test -n "$$(diff $(XABSL_TEMP_DIR)/new/$$xmlfile $(XML_OUTPUT_DIR)/$$xmlfile)"; then \
mv -f $(XABSL_TEMP_DIR)/new/$$xmlfile $(XML_OUTPUT_DIR)/$$xmlfile; \
fi; \
else \
mv $(XABSL_TEMP_DIR)/new/$$xmlfile $(XML_OUTPUT_DIR)/$$xmlfile; \
fi; \
done
@rm -rf $(XABSL_TEMP_DIR)/new
$(XML_OUTPUT_DIR)/agents.xinclude-processed.xml: $(XML_FILES) \
$(REMOVE_COMMENTS_XSL)
@if test -f $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml; then rm -f $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml; fi
@echo generating `pwd`/$(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@$(XSLT) -o $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml $(REMOVE_COMMENTS_XSL) $(XML_OUTPUT_DIR)/agents.xml
# Generates a intermediate xml file for the option trees of all options
$(XML_OUTPUT_DIR)/option-tree.xml: $(DOC_OPTION_TREE_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@echo generating $@
@$(XSLT) -o $(XABSL_TEMP_DIR)/new/option-tree.xml $(DOC_OPTION_TREE_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@if test -f $(XML_OUTPUT_DIR)/option-tree.xml; then \
if test -n "$$(diff $(XABSL_TEMP_DIR)/new/option-tree.xml $(XML_OUTPUT_DIR)/option-tree.xml)"; then \
mv -f $(XABSL_TEMP_DIR)/new/option-tree.xml $(XML_OUTPUT_DIR)/option-tree.xml; \
fi; \
else \
mv $(XABSL_TEMP_DIR)/new/option-tree.xml $(XML_OUTPUT_DIR)/option-tree.xml; \
fi
@rm -rf $(XABSL_TEMP_DIR)/new
# Generate documentation in two steps, first generate xml output, next generate html files
# Building in separate steps is necessary since first step generates files needed by second
DOCUMENTATION:
@make -s XML
@make -s HTML
# Documenation needs and output directory, the .css file, and index pages and a page for each symbols, basic-behaviors, and options file.
HTML: $(DOC_OUTPUT_DIR) \
$(DOC_OUTPUT_DIR)/svg \
$(XML_OUTPUT_DIR)/option-tree.xml \
$(DOC_STYLES_CSS) \
$(DOC_INDEX_HTML) \
$(DOC_SYMBOLS_INDEX_HTML) \
$(DOC_BASIC_BEHAVIOR_INDEX_HTML) \
$(DOC_OPTION_INDEX_HTML) \
$(DOC_AGENTS_HTML) \
$(DOC_SYMBOL_FILES) \
$(DOC_BASIC_BEHAVIOR_FILES) \
$(DOC_OPTION_FILES)
# Generic rule for symbol documentation
$(DOC_OUTPUT_DIR)/symbols.%.html: $(XML_OUTPUT_DIR)/Symbols/%.xml $(DOC_MENU_XSL) $(DOC_SYMBOLS_XSL)
@echo generating $@
@$(XSLT) -o $@ $(DOC_SYMBOLS_XSL) $<
# Generic rule for option documentation
$(DOC_OUTPUT_DIR)/option.%.html: $(XML_OUTPUT_DIR)/Options/%.xml $(XML_OUTPUT_DIR)/option-tree.xml $(DOC_OPTION_XSL) $(DOC_PSEUDO_CODE_XSL) $(DOC_PARAMETERS_XSL) $(DOC_MENU_XSL)
@echo generating $@
@$(XSLT) --path $(XML_OUTPUT_DIR) --stringparam option-tree-xml option-tree.xml -o $@.temp $(DOC_OPTION_XSL) $<
@$(XSLT) -o $@ $(DOTML_DIR)/embed-svg-graphics.xsl $@.temp
@DOTML_DIR=$(DOTML_DIR) DOT=$(DOT) DOTML_XSLT="$(XSLT) (XSL) (INPUT)" $(DOTML_DIR)/generate-svg-graphics.bash $@.temp $(DOC_OUTPUT_DIR)
@rm $@.temp
# Generic rule for basic behavior documentation
$(DOC_OUTPUT_DIR)/basic-behaviors.%.html: $(XML_OUTPUT_DIR)/BasicBehaviors/%.xml $(DOC_MENU_XSL) $(DOC_BASIC_BEHAVIORS_XSL) $(DOC_PARAMETERS_XSL)
@echo generating $@
@$(XSLT) -o $@ $(DOC_BASIC_BEHAVIORS_XSL) $<
# Generates the index page
$(DOC_INDEX_HTML): $(DOC_MENU_XSL) $(DOC_INDEX_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@echo generating $@
@$(XSLT) -o $(DOC_INDEX_HTML) $(DOC_INDEX_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
# Generates the option index page
$(DOC_OPTION_INDEX_HTML): $(XML_OUTPUT_DIR)/option-tree.xml $(XML_OUTPUT_DIR)/options.xml $(DOC_OPTION_INDEX_XSL) $(DOC_MENU_XSL)
@echo generating $@
@$(XSLT) --path $(XML_OUTPUT_DIR) --stringparam option-tree-xml option-tree.xml -o $@.temp $(DOC_OPTION_INDEX_XSL) $(XML_OUTPUT_DIR)/options.xml
@$(XSLT) -o $@ $(DOTML_DIR)/embed-svg-graphics.xsl $@.temp
@DOTML_DIR=$(DOTML_DIR) DOT=$(DOT) DOTML_XSLT="$(XSLT) (XSL) (INPUT)" $(DOTML_DIR)/generate-svg-graphics.bash $@.temp $(DOC_OUTPUT_DIR)
@rm $@.temp
# Generates the agent index page
$(DOC_AGENTS_HTML): $(DOC_AGENTS_XSL) $(DOC_MENU_XSL) $(XML_OUTPUT_DIR)/option-tree.xml $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@echo generating $@
@$(XSLT) --path $(XML_OUTPUT_DIR) --stringparam option-tree-xml option-tree.xml -o $@.temp $(DOC_AGENTS_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@$(XSLT) -o $@ $(DOTML_DIR)/embed-svg-graphics.xsl $@.temp
@DOTML_DIR=$(DOTML_DIR) DOT=$(DOT) DOTML_XSLT="$(XSLT) (XSL) (INPUT)" $(DOTML_DIR)/generate-svg-graphics.bash $@.temp $(DOC_OUTPUT_DIR)
@rm $@.temp
# Generates the basic behavior index page
$(DOC_BASIC_BEHAVIOR_INDEX_HTML): $(DOC_BASIC_BEHAVIOR_INDEX_XSL) $(DOC_MENU_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@echo generating $@
@$(XSLT) -o $(DOC_BASIC_BEHAVIOR_INDEX_HTML) $(DOC_BASIC_BEHAVIOR_INDEX_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
# Generates the symbols index page
$(DOC_SYMBOLS_INDEX_HTML): $(DOC_SYMBOLS_INDEX_XSL) $(DOC_MENU_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@echo generating $@
@$(XSLT) -o $(DOC_SYMBOLS_INDEX_HTML) $(DOC_SYMBOLS_INDEX_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
# Generates the debug symbols
$(XABSL_OUTPUT_DIR)/$(DEBUG_SYMBOLS): $(DEBUG_SYMBOLS_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
@echo generating $@
@$(XSLT) -o $(XABSL_OUTPUT_DIR)/$(DEBUG_SYMBOLS) $(DEBUG_SYMBOLS_XSL) $(XML_OUTPUT_DIR)/agents.xinclude-processed.xml
# Copies documentation.css to the documentation output directory
$(DOC_STYLES_CSS): $(XABSL_XSL_DIR)/documentation.css
@cp $(XABSL_XSL_DIR)/documentation.css $(DOC_OUTPUT_DIR)/styles.css
# Generates the output directory for intermediate code
$(XABSL_OUTPUT_DIR):
@mkdir -p $(XABSL_OUTPUT_DIR)
# Generates the output directory for xml code
$(XML_OUTPUT_DIR):
@mkdir -p $(XML_OUTPUT_DIR)
# Generates the output directory for documentation
$(DOC_OUTPUT_DIR):
@mkdir -p $(DOC_OUTPUT_DIR)
# The path where the SVG graphics generated for the documentation of options and agents are stored.
$(DOC_OUTPUT_DIR)/svg:
@mkdir -p $(DOC_OUTPUT_DIR)/svg

View File

@ -0,0 +1,28 @@
SOURCES=constants.rb \
errors.rb \
language_elements.rb \
symbol_table.rb \
symbols.rb \
syntax_tree_builder.rb \
tokenizer.rb \
translator.rb \
translator_base.rb \
xml_parser.rb \
xabsl.rb \
vcproj.rb
.PHONY: parser clean
all: parser timestamp
timestamp: $(SOURCES) Makefile
@touch timestamp
parser: xabsl_parser.tab.rb
xabsl_parser.tab.rb: xabsl_parser.y.rb
@ruby racc/racc -v xabsl_parser.y.rb
clean:
@rm -f xabsl_parser.output xabsl_parser.tab.rb
@rm -f timestamp

View File

@ -0,0 +1,152 @@
module Translator
VERBOSE = false
PARANOIA = true
ENDL = "\r\n"
#tag for parsing an option file
TAG_OPTION = 'option'
TAG_STATE = 'state'
TAG_SBB = 'subsequent-basic-behavior'
TAG_SP = 'set-parameter'
TAG_SEOS = 'set-enumerated-output-symbol'
TAG_SDOS = 'set-decimal-output-symbol'
TAG_SBOS = 'set-boolean-output-symbol'
TAG_SO = 'subsequent-option'
TAG_DT = 'decision-tree'
TAG_OPR = 'option-parameter-ref'
TAG_DV = 'decimal-value'
TAG_BV = 'boolean-value'
TAG_IF = 'if'
TAG_ELSE = 'else'
TAG_COND = 'condition'
TAG_TTS = 'transition-to-state'
TAG_GT = 'greater-than'
TAG_LT = 'less-than'
TAG_GTEQ = 'greater-than-or-equal-to'
TAG_LTEQ = 'less-than-or-equal-to'
TAG_EQ = 'equal-to'
TAG_NEQ = 'not-equal-to'
TAG_PLUS = 'plus'
TAG_MINUS = 'minus'
TAG_DISR = 'decimal-input-symbol-ref'
TAG_BISR = 'boolean-input-symbol-ref'
TAG_EISR = 'enumerated-input-symbol-ref'
TAG_DOSR = 'decimal-output-symbol-ref'
TAG_BOSR = 'boolean-output-symbol-ref'
TAG_EOSR = 'enumerated-output-symbol-ref'
TAG_AND = 'and'
TAG_OR = 'or'
TAG_WP = 'with-parameter'
TAG_EISC = 'enumerated-input-symbol-comparison'
TAG_CDT = 'common-decision-tree'
TAG_COMMON_ACTION = 'common-action'
TAG_CR = 'constant-ref'
TAG_TOSX = 'time-of-state-execution'
TAG_TOOX = 'time-of-option-execution'
TAG_NOT = 'not'
TAG_SORTS = 'subsequent-option-reached-target-state'
TAG_CONFLICT = 'conflict'
TAG_MPL = 'multiply'
TAG_DIV = 'divide'
TAG_MOD = 'mod'
TAG_CE = 'conditional-expression'
TAG_EX1 = 'expression1'
TAG_EX2 = 'expression2'
TAG_EV = 'enum-element-ref'
#tags for parsing an option-defintions file
TAG_ODS = 'option-definitions'
TAG_OD = 'option-definition'
TAG_DPARA = 'decimal-parameter'
TAG_BPARA = 'boolean-parameter'
TAG_EPARA = 'enumerated-parameter'
#tags for symbol files
TAG_BASIC_BEHAVIORS = 'basic-behaviors'
TAG_SYMBOLS = 'symbols'
TAG_DIS = 'decimal-input-symbol'
TAG_DOS = 'decimal-output-symbol'
TAG_E = 'enumeration'
TAG_ENUM = 'enum-element'
TAG_EIS = 'enumerated-input-symbol'
TAG_EOS = 'enumerated-output-symbol'
TAG_BIS = 'boolean-input-symbol'
TAG_BOS = 'boolean-output-symbol'
TAG_CONST = 'constant'
TAG_BBS = 'basic-behaviors'
TAG_BB = 'basic-behavior'
#Tags for agent files
TAG_AGENT_COLLECTION = 'agent-collection'
TAG_AGENT = 'agent'
TAG_TITLE = 'title'
TAG_SOFTWARE_ENVIRONMENT = 'software-environment'
TAG_PLATFORM = 'platform'
TAG_OPTIONS = 'options'
TAG_XINCLUDE = 'xi:include'
#tokens for parsing a xtc file
TOKEN_TRUE = 'true'
TOKEN_FALSE = 'false'
TOKEN_OPTION = 'option'
TOKEN_INITIAL = 'initial'
TOKEN_TARGET = 'target'
TOKEN_STATE = 'state'
TOKEN_COMMON = 'common'
TOKEN_DECISION = 'decision'
TOKEN_ACTION = 'action'
TOKEN_STAY = 'stay'
TOKEN_TTS = 'goto'
TOKEN_IF = 'if'
TOKEN_ELSE = 'else'
TOKEN_TOSX = 'state_time'
TOKEN_TOOX = 'option_time'
TOKEN_SORTS = 'action_done'
TOKEN_AGENT = 'agent'
TOKEN_FUNCTION = 'function'
TOKEN_ENUM = 'enum'
TOKEN_INPUT = 'input'
TOKEN_OUTPUT = 'output'
TOKEN_BOOL = 'bool'
TOKEN_FLOAT = 'float'
TOKEN_CONST = 'const'
TOKEN_NAMESPACE = 'namespace'
TOKEN_BEHAVIOR = 'behavior'
TOKEN_INCLUDE = 'include'
TOKEN_INTERNAL = 'internal'
TOKEN_CAPACITY = 'capacity'
TOKEN_SYNCHRONIZED = 'synchronized'
TOKEN_CONFLICT = 'conflict'
#Attributes
ATTR_NAME = 'name'
ATTR_MEASURE = 'measure'
ATTR_RANGE = 'range'
ATTR_DESCRIPTION = 'description'
ATTR_REF = 'ref'
ATTR_VALUE = 'value'
ATTR_IS_TARGET_STATE = 'is-target-state'
ATTR_INITIAL_STATE = 'initial-state'
ATTR_TITLE = 'title'
ATTR_ID = 'id'
ATTR_ROOT_OPTION = 'root-option'
ATTR_ENUM = 'enumeration'
ATTR_INTERNAL = 'internal'
ATTR_CAPACITY = 'capacity'
ATTR_SYNCHRONIZED = 'synchronized'
ATTR_XMLNS = 'xmlns'
ATTR_XMLNS_XSI = 'xmlns:xsi'
ATTR_XSI_SCHEMALOCATION = 'xsi:schemaLocation'
ATTR_XMLNS_XI = 'xmlns:xi'
ATTR_HREF = 'href'
#filenames
OPTION_DEFINITIONS_FILE = 'options.xml'
OPTION_DEFINITIONS_ENTITY = 'options'
DTD_INCLUDE_FILE = 'symbol-and-basic-behavior-files.dtd'
DTD_INCLUDE_ENTITY = 'symbol-and-basic-behavior-files'
AGENT_COLLECTION_FILE = 'agents.xml'
TIMESTAMP_FILE = File.join(File.expand_path(File.dirname(__FILE__)), 'timestamp')
end

View File

@ -0,0 +1,396 @@
module Translator
class ErrorHandler < CompilerContextWorker
attr_reader :messages
def initialize(compiler_context)
super
@messages = []
end
def error(message)
#suppress output of following messages
unless [ParameterMissing, NamingWarning].include?(message.class)
messages << message
#$stderr.puts visual_studio_format(message)
end
end
def visual_studio_format(message)
type_string = ''
if (message.class <= CompilerWarning)
type_string = "warning"
elsif(message.class <= CompilerError || message.class <= RuntimeError)
type_string = "error"
else
type_string = "warning"
end
filename = File.expand_path(cc.cu.src_fullname)
filename.sub!(/\A\/cygdrive\/([a-zA-Z])/) do |match|
"#{$1.upcase}:"
end
filename.gsub!(/\//, '\\')
if message.respond_to?(:line_nr) && !message.line_nr.nil?
line = "(#{message.line_nr})"
else
line = '(0)'
end
result = "#{filename}#{line} : #{type_string} X#{message.errno}: #{message.message}" << ENDL
if message.respond_to?(:token) && !message.token.nil?
cc.tz.get_code_context(message.token, 100).each do |string|
result += string << ENDL
end
end
#if message.respond_to?(:backtrace)
# $stderr.puts message.backtrace
#end
return result
end
def format(message)
type_string = ''
if (message.class <= CompilerWarning)
type_string = "WARNING "
elsif(message.class <= CompilerError || message.class <= RuntimeError)
type_string = "ERROR "
else
type_string = "MESSAGE "
end
result = "#{type_string} X#{message.errno} "
result += "#{File.basename(cc.cu.src_filename)}"
result += ":#{message.line_nr}" if message.respond_to?(:line_nr) && !message.line_nr.nil?
result += ENDL
result += " #{message.class.name}" << ENDL if LOG.info?
result += " #{message.message}" << ENDL unless message.message.nil? || message.message.empty?
if !message.token.nil?
cols = ENV['COLUMNS'].to_i
cols = 80 if cols <= 80
cc.tz.get_code_context(message.token, cols - 3).each do |string|
result += " #{string}" << ENDL
end
elsif !message.sample.nil?
result += " #{message.sample}" << ENDL
elsif !message.line_nr.nil?
result += " #{cc.tz.get_code_line(message.line_nr)}" << ENDL
end
result += ENDL
return result
end
end
class CompilerMessage < RuntimeError
attr_accessor :line_nr
attr_accessor :sample
attr_accessor :message
attr_reader :token
attr_reader :error
attr_reader :errno
def initialize(compiler_context)
@cc = compiler_context
end
def token=(token)
if token.nil?
$stderr.puts "token information not available"
else
@token = token
@line_nr = @token.line_nr
end
end
end
#fatal errors stop the compiling process almost at once
class CompilerFatal < CompilerMessage
end
class InternalError < CompilerMessage
def initialize(message = 'internal error')
super
@errno = 2357
end
end
class CompilerWarning < CompilerMessage
end
class CompilerError < CompilerMessage
end
class DoubleIncludeError < CompilerError
def initialize(compiler_context, filename)
super(compiler_context)
self.message = "File '#{filename}' is included more than once"
@errno = 9001
end
end
class FileOpenError < CompilerError
def initialize(compiler_context, filename)
super(compiler_context)
self.message = "unable to open file '#{filename}'"
@errno = 2375
end
end
class FileTypeError < CompilerError
def initialize(compiler_context, filename)
super(compiler_context)
self.message = "File '#{filename}' doesn't have extension .xabsl"
@errno = 7253
end
end
class SyntaxError < CompilerFatal
def initialize(compiler_context)
super(compiler_context)
self.message = "syntax error."
@errno = 2537
end
end
class SemanticWarning < CompilerWarning
end
class SemanticError < CompilerError
end
class UnexpectedEndOfFile < SyntaxError
def initialize(compiler_context)
super(compiler_context)
self.message = "unexpected end of file."
@errno = 2555
end
end
class TokenizerError < SyntaxError
def initialize(compiler_context, line_nr, sample)
super(compiler_context)
self.line_nr = line_nr
self.sample = sample
self.message = "illegal characters encountered."
@errno = 2573
end
end
class UnevenStringDelimiterError < SyntaxError
def initialize(compiler_context, delimiter)
super(compiler_context)
self.line_nr = line_nr
self.sample = sample
self.message = "uneven count of string delimiters '#{delimiter}' encountered."
@errno = 2735
end
end
class ParenthesisError < SyntaxError
def initialize(compiler_context, left_string, left_count, right_string, right_count)
super(compiler_context)
self.message = "counted #{left_count} left parenthesis '#{left_string}' and #{right_count} right parenthesis."
@errno = 2753
end
end
class ClosingCommentError < SyntaxError
def initialize(compiler_context, line_nr)
super(compiler_context)
self.line_nr = line_nr
self.message = "misplaced end-of-comment detected"
@errno = 3257
end
end
class ClosingCommentMissingError < SyntaxError
def initialize(compiler_context, line_nr)
super(compiler_context)
self.line_nr = line_nr
self.message = "end-of-comment missing."
@errno = 3275
end
end
class NamespaceSeparation < SemanticError
def initialize(compiler_context, token, symbol)
super(compiler_context)
self.token = token
self.message = "namespace '#{compiler_context.sc.to_code(symbol)}' can contain either symbols or behaviors. offending declaration is '#{token}'."
@errno = 3527
end
end
class EmptyNamespaceWarning < SemanticWarning
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "namespace '#{token.to_s}' is empty."
@errno = 3572
end
end
class ParameterMultipleSetting < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "parameter '#{token.to_s}' is set more than once."
@errno = 3725
end
end
class ParameterMissing < SemanticWarning
def initialize(compiler_context, call_token, missing_symbol)
super(compiler_context)
self.token = call_token
self.message = "parameter '#{compiler_context.sc.to_code(missing_symbol)}' is missing in call to '#{call_token.to_s}'."
@errno = 3752
end
end
class DomainSymbolExpected < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "domain symbol expected instead of '#{token.to_s}'."
@errno = 5237
end
end
class MismatchingDomain < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "'#{token.to_s}' has mismatching domain."
@errno = 5255
end
end
class InitialStateMissing < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "initial state is missing on option '#{token.to_s}'."
@errno = 5273
end
end
class InitialStateMultipleDefinition < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "multiple initial state definitions, '#{token.to_s}'."
@errno = 5327
end
end
class MultipleDefinitions < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "'#{token.to_s}' is defined more than once."
@errno = 5372
end
end
class TypeMismatch < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "type mismatch on '#{token.to_s}'."
@errno = 5525
end
end
class EnumTypeMismatch < SemanticError
def initialize(compiler_context, token, enum1, enum2)
super(compiler_context)
self.token = token
self.message = "enumeration mismatch on '#{token.to_s}' expected '#{enum1.identifier}' found '#{enum2.identifier}'."
@errno = 5526
end
end
class NoMatchingSymbolFound < SemanticError
def initialize(compiler_context, token, domain_symbol, symbol_classes)
super(compiler_context)
self.token = token
self.message = "no matching symbol found for '#{token.to_s}' "
self.message += "with domain '#{compiler_context.sc.to_code(domain_symbol)}' " unless domain_symbol.nil?
self.message += "and symbol class in #{symbol_classes.inspect}."
@errno = 5552
end
end
class MultipleMatchingSymbolsFound < SemanticError
def initialize(compiler_context, token, domain_symbol, symbol_classes, symbols)
super(compiler_context)
self.token = token
self.message = "multiple matching symbol found for '#{token.to_s}' "
self.message += "with domain '#{compiler_context.sc.to_code(domain_symbol)}' " unless domain_symbol.nil?
self.message += "and symbol class in #{symbol_classes.inspect}: "
symbols.each do |symbol|
self.message += "#{symbol.class.name}"
self.message += " with domain '#{compiler_context.sc.to_code(symbol.domain_symbol)}'" if symbol.class <= DomainValueSymbol && !symbol.domain_symbol.nil?
self.message += ", "
end
@errno = 5723
end
end
class UnexpectedLE < SemanticError
def initialize(compiler_context, token, le, parent)
super(compiler_context)
self.token = token
self.message = "unexpected language element '#{le.tag}' for '#{parent.tag}'"
@errno = 5732
end
end
class NamingWarning < SemanticWarning
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "file should be named like option or namespace"
@errno = 7235
end
end
class DecisionTreeMustStartWithElse < SemanticWarning
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "decision tree has to start with else when the option has a common decision tree"
@errno = 7325
end
end
class DecisionTreeMustNotStartWithElse < SemanticError
def initialize(compiler_context, token)
super(compiler_context)
self.token = token
self.message = "decision tree must not start with else when the option has no common decision tree"
@errno = 7352
end
end
#unused errnos
#7523
#7532
end

View File

@ -0,0 +1,30 @@
#
# compat.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
unless [].respond_to?(:map!)
class Array
if [].respond_to?(:collect!)
alias map! collect!
else
alias map! filter
end
end
end
unless [].respond_to?(:map)
module Enumerable
alias map collect
end
end
def bug!( msg )
raise '[Racc BUG] ' + msg
end

View File

@ -0,0 +1,112 @@
#
# compiler.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
require 'racc/compat'
require 'racc/grammarfileparser'
require 'racc/grammar'
require 'racc/state'
require 'racc/output'
module Racc
class Compiler
attr_reader :filename
attr_reader :parser
attr_reader :ruletable
attr_reader :symboltable
attr_reader :statetable
attr_reader :formatter
attr_accessor :debug_parser
attr_accessor :convert_line
attr_accessor :omit_action
attr_accessor :result_var
def verbose=( f )
@verbose = f
end
attr_accessor :debug
attr_accessor :d_parse
attr_accessor :d_rule
attr_accessor :d_token
attr_accessor :d_state
attr_accessor :d_la
attr_accessor :d_prec
def initialize
@debug_parser = false
@verbose = false
@convert_line = true
@omit_action = true
@result_var = true
@debug = false
@d_parse = false
@d_rule = false
@d_token = false
@d_state = false
@d_la = false
@d_prec = false
end
def parse( str, fname = '-' )
$stderr.puts 'parsing grammar file...' if @verbose
# must be this order
@symboltable = SymbolTable.new(self)
@ruletable = RuleTable.new(self)
@parser = GrammarFileParser.new(self)
@filename = fname
@parser.parse(str)
end
def compile
nfa
dfa
end
def nfa
$stderr.puts 'initializing state machine...' if @verbose
@statetable = StateTable.new(self)
@ruletable.init
@statetable.init
end
def dfa
if @verbose
$stderr.puts "resolving #{@statetable.size} states..."
b = Process.times.utime
end
@statetable.determine
if @verbose
e = Process.times.utime
$stderr.puts "all resolved in #{e - b} sec"
end
end
def source( f )
$stderr.puts 'creating table file...' if @verbose
CodeGenerator.new(self).output f
end
def output( f )
$stderr.puts 'creating .output file...' if @verbose
VerboseOutputter.new(self).output f
end
end
end # module Racc

View File

@ -0,0 +1,844 @@
#
# grammar.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
require 'racc/compat'
require 'racc/iset'
module Racc
class UserAction
def initialize( str, lineno )
@val = (str.strip.empty? ? nil : str)
@lineno = lineno
end
attr_reader :val
attr_reader :lineno
def name
'{action}'
end
alias inspect name
end
class OrMark
def initialize( lineno )
@lineno = lineno
end
def name
'|'
end
alias inspect name
attr_reader :lineno
end
class Prec
def initialize( tok, lineno )
@val = tok
@lineno = lineno
end
def name
'='
end
alias inspect name
attr_reader :val
attr_reader :lineno
end
#########################################################################
########################### ################################
########################### rule ################################
########################### ################################
#########################################################################
#
# RuleTable
#
# stands grammar. Each items of @rules are Rule object.
#
class RuleTable
def initialize( racc )
@racc = racc
@symboltable = racc.symboltable
@d_token = racc.d_token
@d_rule = racc.d_rule
@d_state = racc.d_state
@rules = []
@hashval = 4 # size of dummy rule
@start = nil
@sprec = nil
@emb = 1
@expect = nil
@end_rule = false
end
###
### register
###
def register_rule_from_array( arr )
sym = arr.shift
case sym
when OrMark, UserAction, Prec
raise ParseError, "#{sym.lineno}: unexpected token #{sym.name}"
end
new = []
arr.each do |i|
case i
when OrMark
register_rule sym, new
new = []
when Prec
raise ParseError, "'=<prec>' used twice in one rule" if @sprec
@sprec = i.val
else
new.push i
end
end
register_rule sym, new
end
def register_rule( targ, list )
if targ
@prev_target = targ
else
targ = @prev_target
end
if UserAction === list[-1]
act = list.pop
else
act = UserAction.new('', 0)
end
list.map! {|t| (UserAction === t) ? embed_symbol(t) : t }
reg_rule targ, list, act
@start ||= targ
@sprec = nil
end
def reg_rule( targ, list, act )
@rules.push Rule.new(targ, list, act, @rules.size + 1, @hashval, @sprec)
@hashval += (list.size + 1)
end
def embed_symbol( act )
sym = @symboltable.get("@#{@emb}".intern, true)
@emb += 1
reg_rule sym, [], act
sym
end
def end_register_rule
@end_rule = true
raise RaccError, 'no rule in input' if @rules.empty?
end
def register_start( tok )
raise ParseError, "'start' defined twice'" if @start
@start = tok
end
def register_option( option )
case option.sub(/\Ano_/, '')
when 'omit_action_call'
@racc.omit_action = ((/\Ano_/ === option) ? false : true)
when 'result_var'
@racc.result_var = ((/\Ano_/ === option) ? false : true)
else
raise ParseError, "unknown option '#{option}'"
end
end
def expect( n = nil )
return @expect unless n
raise ParseError, "'expect' exist twice" if @expect
@expect = n
end
###
### accessor
###
attr_reader :start
def []( x )
@rules[x]
end
def each_rule( &block )
@rules.each(&block)
end
alias each each_rule
def each_index( &block )
@rules.each_index(&block)
end
def each_with_index( &block )
@rules.each_with_index(&block)
end
def size
@rules.size
end
def to_s
"<Racc::RuleTable>"
end
###
### process
###
def init
#
# add dummy rule
#
tmp = Rule.new(@symboltable.dummy,
[ @start, @symboltable.anchor, @symboltable.anchor ],
UserAction.new('', 0),
0, 0, nil)
# id hash prec
@rules.unshift tmp
@rules.freeze
rule = ptr = tmp = tok = t = nil
#
# t.heads
#
@rules.each do |rule|
rule.target.heads.push rule.ptrs[0]
end
#
# t.terminal?, self_null?
#
@symboltable.each do |t|
t.term = t.heads.empty?
if t.terminal?
t.snull = false
next
end
tmp = false
t.heads.each do |ptr|
if ptr.reduce?
tmp = true
break
end
end
t.snull = tmp
end
@symboltable.fix
#
# t.locate
#
@rules.each do |rule|
tmp = nil
rule.ptrs.each do |ptr|
unless ptr.reduce?
tok = ptr.dereference
tok.locate.push ptr
tmp = tok if tok.terminal?
end
end
rule.set_prec tmp
end
#
# t.expand
#
@symboltable.each_nonterm {|t| compute_expand t }
#
# t.nullable?, rule.nullable?
#
compute_nullable
#
# t.useless?, rule.useless?
#
compute_useless
end
def compute_expand( t )
puts "expand> #{t.to_s}" if @d_token
t.expand = _compute_expand(t, ISet.new, [])
puts "expand< #{t.to_s}: #{t.expand.to_s}" if @d_token
end
def _compute_expand( t, ret, lock )
if tmp = t.expand
ret.update tmp
return ret
end
tok = h = nil
ret.update_a t.heads
t.heads.each do |ptr|
tok = ptr.dereference
if tok and tok.nonterminal?
unless lock[tok.ident]
lock[tok.ident] = true
_compute_expand tok, ret, lock
end
end
end
ret
end
def compute_nullable
@rules.each {|r| r.null = false }
@symboltable.each {|t| t.null = false }
r = @rules.dup
s = @symboltable.nonterminals
begin
rs = r.size
ss = s.size
check_r_nullable r
check_s_nullable s
end until rs == r.size and ss == s.size
end
def check_r_nullable( r )
r.delete_if do |rl|
rl.null = true
rl.symbols.each do |t|
unless t.nullable?
rl.null = false
break
end
end
rl.nullable?
end
end
def check_s_nullable( s )
s.delete_if do |t|
t.heads.each do |ptr|
if ptr.rule.nullable?
t.null = true
break
end
end
t.nullable?
end
end
###
### WHAT IS "USELESS"?
###
def compute_useless
t = del = save = nil
@symboltable.each_terminal {|t| t.useless = false }
@symboltable.each_nonterm {|t| t.useless = true }
@rules.each {|r| r.useless = true }
r = @rules.dup
s = @symboltable.nonterminals
begin
rs = r.size
ss = s.size
check_r_useless r
check_s_useless s
end until r.size == rs and s.size == ss
end
def check_r_useless( r )
t = rule = nil
r.delete_if do |rule|
rule.useless = false
rule.symbols.each do |t|
if t.useless?
rule.useless = true
break
end
end
not rule.useless?
end
end
def check_s_useless( s )
t = ptr = nil
s.delete_if do |t|
t.heads.each do |ptr|
unless ptr.rule.useless?
t.useless = false
break
end
end
not t.useless?
end
end
end # class RuleTable
#
# Rule
#
# stands one rule of grammar.
#
class Rule
def initialize( targ, syms, act, rid, hval, prec )
@target = targ
@symbols = syms
@action = act.val
@lineno = act.lineno
@ident = rid
@hash = hval
@prec = @specified_prec = prec
@null = nil
@useless = nil
@ptrs = tmp = []
syms.each_with_index do |t,i|
tmp.push LocationPointer.new(self, i, t)
end
tmp.push LocationPointer.new(self, syms.size, nil)
end
attr_reader :target
attr_reader :symbols
attr_reader :action
attr_reader :lineno
attr_reader :ident
attr_reader :hash
attr_reader :ptrs
attr_reader :prec
attr_reader :specified_prec
def set_prec( t )
@prec ||= t
end
def nullable?() @null end
def null=(n) @null = n end
def useless?() @useless end
def useless=(u) @useless = u end
def inspect
"#<rule #{@ident} (#{@target})>"
end
def ==( other )
Rule === other and @ident == other.ident
end
def []( idx )
@symbols[idx]
end
def size
@symbols.size
end
def empty?
@symbols.empty?
end
def to_s
'#<rule#{@ident}>'
end
def accept?
if tok = @symbols[-1]
tok.anchor?
else
false
end
end
def each( &block )
@symbols.each(&block)
end
end # class Rule
#
# LocationPointer
#
# set of rule and position in it's rhs.
# note that number of pointer is more than rule's rhs array,
# because pointer points right of last symbol when reducing.
#
class LocationPointer
def initialize( rule, i, sym )
@rule = rule
@index = i
@symbol = sym
@ident = @rule.hash + i
@reduce = sym.nil?
end
attr_reader :rule
attr_reader :index
attr_reader :symbol
alias dereference symbol
attr_reader :ident
alias hash ident
attr_reader :reduce
alias reduce? reduce
def to_s
sprintf('(%d,%d %s)',
@rule.ident, @index, (reduce?() ? '#' : @symbol.to_s))
end
alias inspect to_s
def eql?( ot )
@hash == ot.hash
end
alias == eql?
def head?
@index == 0
end
def next
@rule.ptrs[@index + 1] or ptr_bug!
end
alias increment next
def before( len )
@rule.ptrs[@index - len] or ptr_bug!
end
private
def ptr_bug!
bug! "pointer not exist: self: #{to_s}"
end
end # class LocationPointer
#########################################################################
########################### ################################
########################### symbol ################################
########################### ################################
#########################################################################
#
# SymbolTable
#
# the table of symbols.
# each items of @symbols are Sym
#
class SymbolTable
include Enumerable
def initialize( racc )
@chk = {}
@symbols = []
@token_list = nil
@prec_table = []
@end_conv = false
@end_prec = false
@dummy = get(:$start, true)
@anchor = get(:$end, true) # ID 0
@error = get(:error, false) # ID 1
@anchor.conv = 'false'
@error.conv = 'Object.new'
end
attr_reader :dummy
attr_reader :anchor
attr_reader :error
def get( val, dummy = false )
unless ret = @chk[val]
@chk[val] = ret = Sym.new(val, dummy)
@symbols.push ret
end
ret
end
def register_token( toks )
@token_list ||= []
@token_list.concat toks
end
def register_prec( assoc, toks )
if @end_prec
raise ParseError, "'prec' block is defined twice"
end
toks.push assoc
@prec_table.push toks
end
def end_register_prec( rev )
@end_prec = true
return if @prec_table.empty?
top = @prec_table.size - 1
@prec_table.each_with_index do |toks, idx|
ass = toks.pop
toks.each do |tok|
tok.assoc = ass
if rev
tok.prec = top - idx
else
tok.prec = idx
end
end
end
end
def register_conv( tok, str )
if @end_conv
raise ParseError, "'convert' block is defined twice"
end
tok.conv = str
end
def end_register_conv
@end_conv = true
end
def fix
#
# initialize table
#
term = []
nt = []
t = i = nil
@symbols.each do |t|
(t.terminal? ? term : nt).push t
end
@symbols = term + nt
@nt_base = term.size
@terms = terminals
@nterms = nonterminals
@symbols.each_with_index do |t, i|
t.ident = i
end
return unless @token_list
#
# check if decleared symbols are really terminal
#
toks = @symbols[2, @nt_base - 2]
@token_list.uniq!
@token_list.each do |t|
unless toks.delete t
$stderr.puts "racc warning: terminal #{t} decleared but not used"
end
end
toks.each do |t|
unless String === t.value
$stderr.puts "racc warning: terminal #{t} used but not decleared"
end
end
end
def []( id )
@symbols[id]
end
attr_reader :nt_base
def nt_max
@symbols.size
end
def each( &block )
@symbols.each(&block)
end
def terminals( &block )
@symbols[0, @nt_base]
end
def each_terminal( &block )
@terms.each(&block)
end
def nonterminals
@symbols[@nt_base, @symbols.size - @nt_base]
end
def each_nonterm( &block )
@nterms.each(&block)
end
end
#
# Sym
#
# stands symbol (terminal and nonterminal).
# This class is not named Symbol because there is
# a class 'Symbol' after ruby 1.5.
#
class Sym
def initialize( val, dummy )
@ident = nil
@value = val
@dummy = dummy
@term = nil
@nterm = nil
@conv = nil
@prec = nil
@heads = []
@locate = []
@snull = nil
@null = nil
@expand = nil
@useless = nil
# for human
@to_s = if @value.respond_to?(:id2name)
then @value.id2name
else @value.to_s.inspect
end
# for ruby source
@uneval = if @value.respond_to?(:id2name)
then ':' + @value.id2name
else @value.to_s.inspect
end
end
class << self
def once_writer( nm )
nm = nm.id2name
module_eval(<<-EOS)
def #{nm}=( v )
bug! unless @#{nm}.nil?
@#{nm} = v
end
EOS
end
end
#
# attributes
#
once_writer :ident
attr_reader :ident
alias hash ident
attr_reader :value
def dummy?() @dummy end
def terminal?() @term end
def nonterminal?() @nterm end
def term=( t )
bug! unless @term.nil?
@term = t
@nterm = !t
end
def conv=( str ) @conv = @uneval = str end
attr_reader :conv
attr_accessor :prec
attr_accessor :assoc
def to_s() @to_s.dup end
def uneval() @uneval.dup end
alias inspect to_s
#
# computed
#
attr_reader :heads
attr_reader :locate
once_writer :snull
def self_null?() @snull end
def nullable?() @null end
def null=(n) @null = n end
once_writer :expand
attr_reader :expand
def useless=(f) @useless = f end
def useless?() @useless end
end # class Sym
end # module Racc

View File

@ -0,0 +1,521 @@
#
# This file is automatically generated. DO NOT MODIFY!!
#
# grammerfileparser.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
require 'racc/compat'
require 'racc/parser'
require 'racc/grammarfilescanner'
require 'racc/usercodeparser'
module Racc
class GrammarFileParser < Parser
def initialize( racc )
@yydebug = racc.d_parse && Racc_debug_parser
@ruletable = racc.ruletable
@symboltable = racc.symboltable
@class_name = nil
@super_class = nil
end
attr_reader :class_name
attr_reader :super_class
def parse( str )
@scanner = GrammarFileScanner.new(str)
@scanner.debug = @yydebug
do_parse
end
private
def next_token
@scanner.scan
end
def on_error( tok, val, _values )
if val.respond_to?(:id2name)
v = val.id2name
elsif String === val
v = val
else
v = val.inspect
end
raise ParseError, "#{@scanner.lineno}: unexpected token '#{v}'"
end
##### racc 1.4.4 generates ###
racc_reduce_table = [
0, 0, :racc_error,
6, 25, :_reduce_1,
1, 26, :_reduce_2,
3, 26, :_reduce_3,
1, 30, :_reduce_4,
4, 30, :_reduce_5,
0, 27, :_reduce_none,
2, 27, :_reduce_none,
3, 31, :_reduce_8,
1, 31, :_reduce_none,
2, 31, :_reduce_10,
2, 31, :_reduce_11,
2, 31, :_reduce_12,
2, 31, :_reduce_13,
2, 32, :_reduce_14,
3, 32, :_reduce_15,
3, 33, :_reduce_16,
3, 33, :_reduce_17,
1, 37, :_reduce_none,
2, 37, :_reduce_none,
2, 38, :_reduce_20,
2, 38, :_reduce_21,
2, 38, :_reduce_22,
1, 35, :_reduce_23,
2, 35, :_reduce_24,
2, 35, :_reduce_none,
1, 34, :_reduce_26,
1, 34, :_reduce_27,
1, 28, :_reduce_28,
0, 28, :_reduce_none,
1, 39, :_reduce_30,
2, 39, :_reduce_31,
2, 39, :_reduce_32,
2, 39, :_reduce_33,
1, 40, :_reduce_none,
1, 40, :_reduce_35,
2, 40, :_reduce_36,
1, 40, :_reduce_37,
1, 36, :_reduce_38,
2, 36, :_reduce_39,
1, 29, :_reduce_none,
0, 29, :_reduce_none ]
racc_reduce_n = 42
racc_shift_n = 66
racc_action_table = [
28, 47, 28, 42, 28, 28, 33, 34, 35, 27,
43, 27, 28, 27, 27, 49, 50, 44, 45, 63,
63, 27, 28, 33, 34, 35, 14, 63, 52, 9,
17, 27, 18, 20, 11, 13, 28, 63, 15, 16,
28, 28, 28, 61, 28, 27, 28, 28, 28, 27,
27, 27, 8, 27, 9, 27, 27, 27, 58, 25,
33, 34, 35, 54, 33, 34, 35, 24, 59, 22,
4, 10, 1, 6, 4, 65 ]
racc_action_check = [
29, 29, 44, 22, 57, 56, 16, 16, 16, 29,
23, 44, 41, 57, 56, 29, 29, 29, 29, 57,
56, 41, 55, 15, 15, 15, 7, 41, 30, 21,
7, 55, 7, 7, 7, 7, 33, 55, 7, 7,
38, 35, 18, 38, 34, 33, 20, 17, 14, 38,
35, 18, 5, 34, 5, 20, 17, 14, 36, 13,
36, 36, 36, 31, 31, 31, 31, 11, 37, 9,
8, 6, 0, 2, 1, 60 ]
racc_action_pointer = [
70, 69, 73, nil, nil, 48, 71, 23, 65, 63,
nil, 62, nil, 46, 43, 6, -11, 42, 37, nil,
41, 23, -2, 5, nil, nil, nil, nil, nil, -5,
20, 47, nil, 31, 39, 36, 43, 54, 35, nil,
nil, 7, nil, nil, -3, nil, nil, nil, nil, nil,
nil, nil, nil, nil, nil, 17, 0, -1, nil, nil,
61, nil, nil, nil, nil, nil ]
racc_action_default = [
-42, -42, -42, -6, -4, -2, -42, -42, -42, -42,
66, -42, -9, -42, -29, -42, -42, -42, -42, -7,
-42, -3, -42, -12, -38, -13, -30, -27, -26, -28,
-41, -42, -18, -42, -42, -42, -42, -42, -42, -10,
-23, -11, -5, -39, -42, -37, -34, -33, -31, -35,
-32, -1, -40, -19, -16, -20, -21, -22, -17, -14,
-42, -8, -24, -25, -36, -15 ]
racc_goto_table = [
26, 5, 53, 37, 39, 41, 12, 53, 21, 31,
36, 19, 38, 2, 51, 46, 30, 23, 55, 56,
57, 7, 3, 29, 60, 48, nil, 62, nil, nil,
64, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, 62, 62, 62 ]
racc_goto_check = [
10, 6, 14, 10, 10, 11, 9, 14, 6, 13,
13, 7, 8, 1, 5, 10, 4, 12, 11, 11,
11, 3, 2, 15, 10, 16, nil, 10, nil, nil,
10, nil, nil, nil, nil, nil, nil, nil, nil, nil,
nil, 10, 10, 10 ]
racc_goto_pointer = [
nil, 13, 21, 18, 2, -16, 0, 4, -5, -1,
-14, -15, 6, -6, -29, 9, -4 ]
racc_goto_default = [
nil, nil, nil, nil, nil, nil, nil, nil, nil, nil,
40, nil, nil, nil, 32, nil, nil ]
racc_token_table = {
false => 0,
Object.new => 1,
:XCLASS => 2,
:XRULE => 3,
"<" => 4,
:XSYMBOL => 5,
":" => 6,
:XCONV => 7,
:XEND => 8,
:XSTART => 9,
:XTOKEN => 10,
:XOPTION => 11,
:XEXPECT => 12,
:DIGIT => 13,
:STRING => 14,
:XPRECHIGH => 15,
:XPRECLOW => 16,
:XLEFT => 17,
:XRIGHT => 18,
:XNONASSOC => 19,
"|" => 20,
";" => 21,
"=" => 22,
:ACTION => 23 }
racc_use_result_var = true
racc_nt_base = 24
Racc_arg = [
racc_action_table,
racc_action_check,
racc_action_default,
racc_action_pointer,
racc_goto_table,
racc_goto_check,
racc_goto_default,
racc_goto_pointer,
racc_nt_base,
racc_reduce_table,
racc_token_table,
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
Racc_token_to_s_table = [
'$end',
'error',
'XCLASS',
'XRULE',
'"<"',
'XSYMBOL',
'":"',
'XCONV',
'XEND',
'XSTART',
'XTOKEN',
'XOPTION',
'XEXPECT',
'DIGIT',
'STRING',
'XPRECHIGH',
'XPRECLOW',
'XLEFT',
'XRIGHT',
'XNONASSOC',
'"|"',
'";"',
'"="',
'ACTION',
'$start',
'xclass',
'class',
'params',
'rules',
'opt_end',
'rubyconst',
'param_seg',
'convdefs',
'xprec',
'symbol',
'symbol_list',
'bare_symlist',
'preclines',
'precline',
'rules_core',
'rule_item']
Racc_debug_parser = false
##### racc system variables end #####
# reduce 0 omitted
module_eval <<'.,.,', '(boot.rb)', 88
def _reduce_1( val, _values, result )
@ruletable.end_register_rule
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 93
def _reduce_2( val, _values, result )
@class_name = val[0]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 98
def _reduce_3( val, _values, result )
@class_name = val[0]
@super_class = val[2]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 103
def _reduce_4( val, _values, result )
result = result.id2name
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 107
def _reduce_5( val, _values, result )
result << '::' << val[3].id2name
result
end
.,.,
# reduce 6 omitted
# reduce 7 omitted
module_eval <<'.,.,', '(boot.rb)', 115
def _reduce_8( val, _values, result )
@symboltable.end_register_conv
result
end
.,.,
# reduce 9 omitted
module_eval <<'.,.,', '(boot.rb)', 120
def _reduce_10( val, _values, result )
@ruletable.register_start val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 124
def _reduce_11( val, _values, result )
@symboltable.register_token val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 130
def _reduce_12( val, _values, result )
val[1].each do |s|
@ruletable.register_option s.to_s
end
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 134
def _reduce_13( val, _values, result )
@ruletable.expect val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 139
def _reduce_14( val, _values, result )
@symboltable.register_conv val[0], val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 143
def _reduce_15( val, _values, result )
@symboltable.register_conv val[1], val[2]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 148
def _reduce_16( val, _values, result )
@symboltable.end_register_prec true
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 152
def _reduce_17( val, _values, result )
@symboltable.end_register_prec false
result
end
.,.,
# reduce 18 omitted
# reduce 19 omitted
module_eval <<'.,.,', '(boot.rb)', 160
def _reduce_20( val, _values, result )
@symboltable.register_prec :Left, val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 164
def _reduce_21( val, _values, result )
@symboltable.register_prec :Right, val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 168
def _reduce_22( val, _values, result )
@symboltable.register_prec :Nonassoc, val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 173
def _reduce_23( val, _values, result )
result = val
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 177
def _reduce_24( val, _values, result )
result.push val[1]
result
end
.,.,
# reduce 25 omitted
module_eval <<'.,.,', '(boot.rb)', 183
def _reduce_26( val, _values, result )
result = @symboltable.get(result)
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 187
def _reduce_27( val, _values, result )
result = @symboltable.get(eval(%Q<"#{result}">))
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 194
def _reduce_28( val, _values, result )
unless result.empty?
@ruletable.register_rule_from_array result
end
result
end
.,.,
# reduce 29 omitted
module_eval <<'.,.,', '(boot.rb)', 200
def _reduce_30( val, _values, result )
result = val
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 204
def _reduce_31( val, _values, result )
result.push val[1]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 211
def _reduce_32( val, _values, result )
unless result.empty?
@ruletable.register_rule_from_array result
end
result.clear
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 219
def _reduce_33( val, _values, result )
pre = result.pop
unless result.empty?
@ruletable.register_rule_from_array result
end
result = [pre]
result
end
.,.,
# reduce 34 omitted
module_eval <<'.,.,', '(boot.rb)', 225
def _reduce_35( val, _values, result )
result = OrMark.new(@scanner.lineno)
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 229
def _reduce_36( val, _values, result )
result = Prec.new(val[1], @scanner.lineno)
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 233
def _reduce_37( val, _values, result )
result = UserAction.new(*result)
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 238
def _reduce_38( val, _values, result )
result = [ result.id2name ]
result
end
.,.,
module_eval <<'.,.,', '(boot.rb)', 242
def _reduce_39( val, _values, result )
result.push val[1].id2name
result
end
.,.,
# reduce 40 omitted
# reduce 41 omitted
def _reduce_none( val, _values, result )
result
end
end
end # module Racc

View File

@ -0,0 +1,300 @@
#
# grammarfilescanner.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
module Racc
class ScanError < StandardError; end
class GrammarFileScanner
def initialize( str )
@lines = str.split(/\n|\r\n|\r/)
@lineno = -1
@line_head = true
@in_rule_blk = false
@in_conv_blk = false
@in_block = nil
@debug = false
next_line
end
def lineno
@lineno + 1
end
attr_accessor :debug
def scan
result = do_scan()
if @debug
$stderr.printf "%7d %-10s %s\n",
lineno(), result[0].inspect, result[1].inspect
end
result
end
def do_scan
begin
until @line.empty?
@line.sub!(/\A\s+/, '')
if /\A\#/ === @line
break
elsif /\A\/\*/ === @line
skip_comment
elsif s = reads(/\A[a-zA-Z_]\w*/)
return check_atom(s)
elsif s = reads(/\A\d+/)
return :DIGIT, s.to_i
elsif ch = reads(/\A./)
case ch
when '"', "'"
return :STRING, eval(scan_quoted(ch))
when '{'
return :ACTION, [scan_action(), lineno()]
else
if ch == '|'
@line_head = false
end
return ch, ch
end
else
;
end
end
end while next_line()
return false, '$'
end
private
def next_line
@lineno += 1
@line = @lines[@lineno]
if not @line or /\A----/ === @line
@lines.clear
@line = nil
if @in_block
@lineno -= 1
scan_error! sprintf('unterminated %s', @in_block)
end
false
else
@line.sub!(/(?:\n|\r\n|\r)\z/, '')
@line_head = true
true
end
end
ReservedWord = {
'right' => :XRIGHT,
'left' => :XLEFT,
'nonassoc' => :XNONASSOC,
'preclow' => :XPRECLOW,
'prechigh' => :XPRECHIGH,
'token' => :XTOKEN,
'convert' => :XCONV,
'options' => :XOPTION,
'start' => :XSTART,
'expect' => :XEXPECT,
'class' => :XCLASS,
'rule' => :XRULE,
'end' => :XEND
}
def check_atom( cur )
if cur == 'end'
symbol = :XEND
@in_conv_blk = false
@in_rule_blk = false
else
if @line_head and not @in_conv_blk and not @in_rule_blk
symbol = ReservedWord[cur] || :XSYMBOL
else
symbol = :XSYMBOL
end
case symbol
when :XRULE then @in_rule_blk = true
when :XCONV then @in_conv_blk = true
end
end
@line_head = false
[symbol, cur.intern]
end
def skip_comment
@in_block = 'comment'
until m = /\*\//.match(@line)
next_line
end
@line = m.post_match
@in_block = nil
end
def scan_action
buf = ''
nest = 1
pre = nil
@in_block = 'action'
begin
pre = nil
if s = reads(/\A\s+/)
# does not set 'pre'
buf << s
end
until @line.empty?
if s = reads(/\A[^'"`{}%#\/\$]+/)
buf << (pre = s)
next
end
case ch = read(1)
when '{'
nest += 1
buf << (pre = ch)
when '}'
nest -= 1
if nest == 0
@in_block = nil
return buf
end
buf << (pre = ch)
when '#' # comment
buf << ch << @line
break
when "'", '"', '`'
buf << (pre = scan_quoted(ch))
when '%'
if literal_head? pre, @line
# % string, regexp, array
buf << ch
case ch = read(1)
when /[qQx]/n
buf << ch << (pre = scan_quoted(read(1), '%string'))
when /wW/n
buf << ch << (pre = scan_quoted(read(1), '%array'))
when /s/n
buf << ch << (pre = scan_quoted(read(1), '%symbol'))
when /r/n
buf << ch << (pre = scan_quoted(read(1), '%regexp'))
when /[a-zA-Z0-9= ]/n # does not include "_"
scan_error! "unknown type of % literal '%#{ch}'"
else
buf << (pre = scan_quoted(ch, '%string'))
end
else
# operator
buf << '||op->' if $raccs_print_type
buf << (pre = ch)
end
when '/'
if literal_head? pre, @line
# regexp
buf << (pre = scan_quoted(ch, 'regexp'))
else
# operator
buf << '||op->' if $raccs_print_type
buf << (pre = ch)
end
when '$' # gvar
buf << ch << (pre = read(1))
else
raise 'Racc FATAL: did not match'
end
end
buf << "\n"
end while next_line()
raise 'Racc FATAL: scan finished before parse finished'
end
def literal_head?( pre, post )
(not pre or not /[a-zA-Z_0-9]/n === pre[-1,1]) and
not post.empty? and not /\A[\s\=]/n === post
end
def read( len )
s = @line[0, len]
@line = @line[len .. -1]
s
end
def reads( re )
m = re.match(@line) or return nil
@line = m.post_match
m[0]
end
def scan_quoted( left, tag = 'string' )
buf = left.dup
buf = "||#{tag}->" + buf if $raccs_print_type
re = get_quoted_re(left)
sv, @in_block = @in_block, tag
begin
if s = reads(re)
buf << s
break
else
buf << @line
end
end while next_line()
@in_block = sv
buf << "<-#{tag}||" if $raccs_print_type
buf
end
LEFT_TO_RIGHT = {
'(' => ')',
'{' => '}',
'[' => ']',
'<' => '>'
}
CACHE = {}
def get_quoted_re( left )
term = Regexp.quote(LEFT_TO_RIGHT[left] || left)
CACHE[left] ||= /\A[^#{term}\\]*(?:\\.[^\\#{term}]*)*#{term}/
end
def scan_error!( msg )
raise ScanError, "#{lineno()}: #{msg}"
end
$raccs_print_type = false
end
end # module Racc

View File

@ -0,0 +1,15 @@
#
# info.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
module Racc
Version = '1.4.4'
Copyright = 'Copyright (c) 1999-2003 Minero Aoki'
end

View File

@ -0,0 +1,98 @@
#
# iset.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
module Racc
#
# ISet
#
# indexed set.
# all items must respond to :ident
#
class ISet
def initialize( a = [] )
@set = a
end
attr_reader :set
def add( i )
@set[i.ident] = i
end
def []( key )
@set[key.ident]
end
def []=( key, val )
@set[key.ident] = val
end
alias include? []
alias key? []
def update( other )
s = @set
o = other.set
o.each_index do |idx|
if t = o[idx]
s[idx] = t
end
end
end
def update_a( a )
s = @set
i = nil
a.each {|i| s[i.ident] = i }
end
def delete( key )
i = @set[key.ident]
@set[key.ident] = nil
i
end
def each( &block )
@set.compact.each(&block)
end
def to_a
@set.compact
end
def to_s
"[#{@set.compact.join(' ')}]"
end
alias inspect to_s
def size
@set.nitems
end
def empty?
@set.nitems == 0
end
def clear
@set.clear
end
def dup
ISet.new(@set.dup)
end
end # class ISet
end # module Racc

View File

@ -0,0 +1,645 @@
#
# output.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
require 'racc/compat'
module Racc
class Formatter
def initialize( racc )
@ruletable = racc.ruletable
@symboltable = racc.symboltable
@statetable = racc.statetable
@actions = racc.statetable.actions
@fname = racc.filename
@debug = racc.debug ? true : false
@dsrc = racc.debug_parser ? true : false
@line = racc.convert_line ? true : false
@omit = racc.omit_action ? true : false
@result = racc.result_var ? true : false
@showall = racc.d_la || racc.d_state
end
end
class CodeGenerator < Formatter
def output( out )
out.print "\n##### racc #{Racc::Version} generates ###\n\n"
output_reduce_table out
output_action_table out
output_goto_table out
output_token_table out
output_other out
out.puts '##### racc system variables end #####'
output_actions out
end
private
def output_reduce_table( out )
out << "racc_reduce_table = [\n"
out << " 0, 0, :racc_error,"
sep = "\n"
sep_rest = ",\n"
@ruletable.each_with_index do |rl, i|
next if i == 0
out.print sep; sep = sep_rest
out.printf ' %d, %d, :_reduce_%s',
rl.size,
rl.target.ident,
(@omit and not rl.action) ? 'none' : i.to_s
end
out << " ]\n\n"
out << "racc_reduce_n = #{@actions.reduce_n}\n\n"
out << "racc_shift_n = #{@actions.shift_n}\n\n"
end
def output_action_table( out )
tbl = [] # yytable
chk = [] # yycheck
defa = [] # yydefact
ptr = [] # yypact
state = tmp = min = max = i = nil
e1 = []
e2 = []
@statetable.each do |state|
defa.push act2actid(state.defact)
if state.action.empty?
ptr.push nil
next
end
tmp = []
state.action.each do |tok, act|
tmp[tok.ident] = act2actid(act)
end
addent e1, e2, tmp, state.ident, ptr
end
set_table e1, e2, tbl, chk, ptr
output_table out, tbl, 'racc_action_table'
output_table out, chk, 'racc_action_check'
output_table out, ptr, 'racc_action_pointer'
output_table out, defa, 'racc_action_default'
end
def output_goto_table( out )
tbl = [] # yytable (2)
chk = [] # yycheck (2)
ptr = [] # yypgoto
defg = [] # yydefgoto
state = dflt = tmp = freq = min = max = i = nil
e1 = []
e2 = []
@symboltable.each_nonterm do |tok|
tmp = []
#
# decide default
#
freq = Array.new(@statetable.size, 0)
@statetable.each do |state|
st = state.goto_table[tok]
if st
st = st.ident
freq[st] += 1
end
tmp[state.ident] = st
end
max = freq.max
if max > 1
dflt = freq.index( max )
tmp.map! {|i| dflt == i ? nil : i }
else
dflt = nil
end
# default
defg.push dflt
#
# delete default value
#
tmp.pop until tmp[-1] or tmp.empty?
if tmp.compact.empty?
# only default
ptr.push nil
next
end
addent e1, e2, tmp, (tok.ident - @symboltable.nt_base), ptr
end
set_table e1, e2, tbl, chk, ptr
output_table out, tbl, 'racc_goto_table'
output_table out, chk, 'racc_goto_check'
output_table out, ptr, 'racc_goto_pointer'
output_table out, defg, 'racc_goto_default'
end
def addent( all, dummy, arr, chkval, ptr )
max = arr.size
min = nil
item = idx = nil
arr.each_with_index do |item,idx|
if item
min ||= idx
end
end
ptr.push(-7777) # mark
arr = arr[min...max]
ent = [ arr, chkval, mkmapexp(arr), min, ptr.size - 1 ]
all.push ent
end
unless defined? RegexpError
RegexpError = RegxpError
end
begin
tmp = 2 ** 16
begin
Regexp.new("a{#{tmp}}")
RE_DUP_MAX = tmp
rescue RegexpError
tmp /= 2
retry
end
raise ArgumentError, 'dummy error to clear ruby_errinfo'
rescue ArgumentError
;
end
def mkmapexp( arr )
i = ii = 0
as = arr.size
map = ''
maxdup = RE_DUP_MAX
curr = nil
while i < as
ii = i + 1
if arr[i]
ii += 1 while ii < as and arr[ii]
curr = '-'
else
ii += 1 while ii < as and not arr[ii]
curr = '.'
end
offset = ii - i
if offset == 1
map << curr
else
while offset > maxdup
map << "#{curr}{#{maxdup}}"
offset -= maxdup
end
map << "#{curr}{#{offset}}" if offset > 1
end
i = ii
end
Regexp.compile(map, 'n')
end
def set_table( entries, dummy, tbl, chk, ptr )
upper = 0
map = '-' * 10240
# sort long to short
entries.sort! {|a,b| b[0].size <=> a[0].size }
entries.each do |arr, chkval, expr, min, ptri|
if upper + arr.size > map.size
map << '-' * (arr.size + 1024)
end
idx = map.index(expr)
ptr[ptri] = idx - min
arr.each_with_index do |item, i|
if item
i += idx
tbl[i] = item
chk[i] = chkval
map[i] = ?o
end
end
upper = idx + arr.size
end
end
def act2actid( act )
case act
when Shift then act.goto_id
when Reduce then -act.ruleid
when Accept then @actions.shift_n
when Error then @actions.reduce_n * -1
else
raise "Racc FATAL: wrong act type #{act.class} in action table"
end
end
def output_table( out, tab, label )
if tab.size > 2000
#
# compressed table
#
output_table_c out, tab, label
else
#
# normal array
#
output_table_s out, tab, label
end
end
def output_table_c( out, tab, label )
sep = "\n"
nsep = ",\n"
buf = ''
com = ''
ncom = ','
co = com
out.print 'clist = ['
tab.each do |i|
buf << co << i.to_s; co = ncom
if buf.size > 66
out.print sep; sep = nsep
out.print "'", buf, "'"
buf = ''
co = com
end
end
unless buf.empty?
out.print sep
out.print "'", buf, "'"
end
out.puts ' ]'
out.print(<<EOS)
#{label} = arr = Array.new(#{tab.size}, nil)
str = a = i = nil
idx = 0
clist.each do |str|
str.split(',', -1).each do |i|
arr[idx] = i.to_i unless i.empty?
idx += 1
end
end
EOS
end
def output_table_s( out, tab, label )
sep = ''
nsep = ','
buf = ''
i = 0
out.puts "#{label} = ["
tab.each do |t|
buf << sep ; sep = nsep
if i == 10
i = 0
buf << "\n"
out << buf
buf = ''
end
buf << (t ? sprintf('%6d', t) : ' nil')
i += 1
end
out << buf unless buf.empty?
out.print " ]\n\n"
end
def output_token_table( out )
sep = "\n"
sep_rest = ",\n"
out << "racc_token_table = {"
@symboltable.each do |tok|
if tok.terminal?
out.print sep; sep = sep_rest
out.printf " %s => %d", tok.uneval, tok.ident
end
end
out << " }\n\n"
end
def output_other( out )
out << "racc_use_result_var = #{@result}\n\n"
out.print(<<EOS)
racc_nt_base = #{@symboltable.nt_base}
Racc_arg = [
racc_action_table,
racc_action_check,
racc_action_default,
racc_action_pointer,
racc_goto_table,
racc_goto_check,
racc_goto_default,
racc_goto_pointer,
racc_nt_base,
racc_reduce_table,
racc_token_table,
racc_shift_n,
racc_reduce_n,
racc_use_result_var ]
EOS
out << "Racc_token_to_s_table = [\n"
out << @symboltable.map {|tok|
"'" + tok.to_s.gsub(/'/, '\\\'') + "'" }.join(",\n")
out << "]\n\n"
out << "Racc_debug_parser = #{@dsrc}\n\n"
end
def output_actions( out )
rl = act = nil
if @result
result1 = ', result '
result2 = "\n result"
defact = ''
else
result1 = result2 = ''
defact = ' val[0]'
end
result = @result ? ', result ' : ''
if @line
src = <<'--'
module_eval <<'.,.,', '%s', %d
def _reduce_%d( val, _values%s)
%s%s
end
%s
--
else
src = <<'--'
def _reduce_%d( val, _values%s)
%s%s
end
--
end
@ruletable.each_rule do |rl|
act = rl.action
if not act and @omit
out.printf "\n # reduce %d omitted\n",
rl.ident
else
act ||= defact
act.sub!(/\s+\z/, '')
if @line
i = rl.lineno
while m = /\A[ \t\f]*(?:\n|\r\n|\r)/.match(act)
act = m.post_match
i += 1
end
delim = '.,.,'
while act.index(delim)
delim *= 2
end
out.printf src, @fname, i - 1, rl.ident,
result1, act, result2, delim
else
act.sub!(/\A\s*(?:\n|\r\n|\r)/, '')
out.printf src, rl.ident,
result1, act, result2
end
end
end
out.printf <<'--', result, (@result ? 'result' : 'val[0]')
def _reduce_none( val, _values%s)
%s
end
--
out.puts
end
end # class CodeGenerator
###
###
###
class VerboseOutputter < Formatter
def output( out )
output_conflict out; out.puts
output_useless out; out.puts
output_rule out; out.puts
output_token out; out.puts
output_state out
end
#
# Warnings
#
def output_conflict( out )
@statetable.each do |state|
if state.srconf
out.printf "state %d contains %d shift/reduce conflicts\n",
state.stateid, state.srconf.size
end
if state.rrconf
out.printf "state %d contains %d reduce/reduce conflicts\n",
state.stateid, state.rrconf.size
end
end
end
def output_useless( out )
rl = t = nil
used = []
@ruletable.each do |rl|
if rl.useless?
out.printf "rule %d (%s) never reduced\n",
rl.ident, rl.target.to_s
end
end
@symboltable.each_nonterm do |t|
if t.useless?
out.printf "useless nonterminal %s\n", t.to_s
end
end
end
#
# States
#
def output_state( out )
ptr = nil
out << "--------- State ---------\n"
@statetable.each do |state|
out << "\nstate #{state.ident}\n\n"
(@showall ? state.closure : state.core).each do |ptr|
pointer_out(out, ptr) if ptr.rule.ident != 0 or @showall
end
out << "\n"
action_out out, state
end
end
def pointer_out( out, ptr )
buf = sprintf("%4d) %s :", ptr.rule.ident, ptr.rule.target.to_s)
ptr.rule.symbols.each_with_index do |tok, idx|
buf << ' _' if idx == ptr.index
buf << ' ' << tok.to_s
end
buf << ' _' if ptr.reduce?
out.puts buf
end
def action_out( f, state )
r = ''
e = ''
sr = state.srconf && state.srconf.dup
rr = state.rrconf && state.rrconf.dup
acts = state.action
keys = acts.keys
keys.sort! {|a,b| a.ident <=> b.ident }
[ Shift, Reduce, Error, Accept ].each do |type|
keys.delete_if do |tok|
act = acts[tok]
if type === act
outact f, tok, act
if sr and c = sr.delete(tok)
outsrconf f, c
end
if rr and c = rr.delete(tok)
outrrconf f, c
end
true
else
false
end
end
end
sr.each {|tok, c| outsrconf f, c } if sr
rr.each {|tok, c| outrrconf f, c } if rr
act = state.defact
if not Error === act or @debug
outact f, '$default', act
end
f.puts
state.goto_table.each do |t, st|
if t.nonterminal?
f.printf " %-12s go to state %d\n", t.to_s, st.ident
end
end
end
def outact( f, t, act )
case act
when Shift
f.printf " %-12s shift, and go to state %d\n",
t.to_s, act.goto_id
when Reduce
f.printf " %-12s reduce using rule %d (%s)\n",
t.to_s, act.ruleid, act.rule.target.to_s
when Accept
f.printf " %-12s accept\n", t.to_s
when Error
f.printf " %-12s error\n", t.to_s
else
raise "Racc FATAL: wrong act for outact: act=#{act}(#{act.class})"
end
end
def outsrconf( f, confs )
confs.each do |c|
r = c.reduce
f.printf " %-12s [reduce using rule %d (%s)]\n",
c.shift.to_s, r.ident, r.target.to_s
end
end
def outrrconf( f, confs )
confs.each do |c|
r = c.low_prec
f.printf " %-12s [reduce using rule %d (%s)]\n",
c.token.to_s, r.ident, r.target.to_s
end
end
#
# Rules
#
def output_rule( out )
out.print "-------- Grammar --------\n\n"
@ruletable.each_rule do |rl|
if @debug or rl.ident != 0
out.printf "rule %d %s: %s\n",
rl.ident, rl.target.to_s, rl.symbols.join(' ')
end
end
end
#
# Tokens
#
def output_token( out )
out.print "------- Symbols -------\n\n"
out.print "**Nonterminals, with rules where they appear\n\n"
@symboltable.each_nonterm do |t|
tmp = <<SRC
%s (%d)
on right: %s
on left : %s
SRC
out.printf tmp, t.to_s, t.ident,
locatestr(t.locate), locatestr(t.heads)
end
out.print "\n**Terminals, with rules where they appear\n\n"
@symboltable.each_terminal do |t|
out.printf " %s (%d) %s\n",
t.to_s, t.ident, locatestr(t.locate)
end
end
def locatestr( ptrs )
list = ptrs.map {|ptr|
i = ptr.rule.ident
(i == 0) ? nil : i
}
list.compact!
list.uniq!
list.join(' ')
end
end # class VerboseOutputter
end

View File

@ -0,0 +1,468 @@
#
# parser.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the same terms of ruby.
#
# As a special exception, when this code is copied by Racc
# into a Racc output file, you may use that output file
# without restriction.
#
# $Id: parser.rb,v 1.1 2003/10/12 06:10:49 aamine Exp $
#
unless defined?(NotImplementedError)
NotImplementedError = NotImplementError
end
module Racc
class ParseError < StandardError; end
end
unless defined?(::ParseError)
ParseError = Racc::ParseError
end
module Racc
unless defined?(Racc_No_Extentions)
Racc_No_Extentions = false
end
class Parser
Racc_Runtime_Version = '1.4.3'
Racc_Runtime_Revision = '$Revision: 1.1 $'.split(/\s+/)[1]
Racc_Runtime_Core_Version_R = '1.4.3'
Racc_Runtime_Core_Revision_R = '$Revision: 1.1 $'.split(/\s+/)[1]
begin
require 'racc/cparse'
# Racc_Runtime_Core_Version_C = (defined in extention)
Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split(/\s+/)[2]
unless new.respond_to?(:_racc_do_parse_c, true)
raise LoadError, 'old cparse.so'
end
if Racc_No_Extentions
raise LoadError, 'selecting ruby version of racc runtime core'
end
Racc_Main_Parsing_Routine = :_racc_do_parse_c
Racc_YY_Parse_Method = :_racc_yyparse_c
Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C
Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C
Racc_Runtime_Type = 'c'
rescue LoadError
Racc_Main_Parsing_Routine = :_racc_do_parse_rb
Racc_YY_Parse_Method = :_racc_yyparse_rb
Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R
Racc_Runtime_Type = 'ruby'
end
def Parser.racc_runtime_type
Racc_Runtime_Type
end
private
def _racc_setup
@yydebug = false unless self.class::Racc_debug_parser
@yydebug = false unless defined? @yydebug
if @yydebug
@racc_debug_out = $stderr unless defined? @racc_debug_out
@racc_debug_out ||= $stderr
end
arg = self.class::Racc_arg
arg[13] = true if arg.size < 14
arg
end
def _racc_init_sysvars
@racc_state = [0]
@racc_tstack = []
@racc_vstack = []
@racc_t = nil
@racc_val = nil
@racc_read_next = true
@racc_user_yyerror = false
@racc_error_status = 0
end
###
### do_parse
###
def do_parse
__send__ Racc_Main_Parsing_Routine, _racc_setup(), false
end
def next_token
raise NotImplementedError, "#{self.class}\#next_token is not defined"
end
def _racc_do_parse_rb( arg, in_debug )
action_table, action_check, action_default, action_pointer,
goto_table, goto_check, goto_default, goto_pointer,
nt_base, reduce_table, token_table, shift_n,
reduce_n, use_result, * = arg
_racc_init_sysvars
tok = act = i = nil
nerr = 0
catch(:racc_end_parse) {
while true
if i = action_pointer[@racc_state[-1]]
if @racc_read_next
if @racc_t != 0 # not EOF
tok, @racc_val = next_token()
unless tok # EOF
@racc_t = 0
else
@racc_t = (token_table[tok] or 1) # error token
end
racc_read_token(@racc_t, tok, @racc_val) if @yydebug
@racc_read_next = false
end
end
i += @racc_t
if i >= 0 and
act = action_table[i] and
action_check[i] == @racc_state[-1]
;
else
act = action_default[@racc_state[-1]]
end
else
act = action_default[@racc_state[-1]]
end
while act = _racc_evalact(act, arg)
end
end
}
end
###
### yyparse
###
def yyparse( recv, mid )
__send__ Racc_YY_Parse_Method, recv, mid, _racc_setup(), true
end
def _racc_yyparse_rb( recv, mid, arg, c_debug )
action_table, action_check, action_default, action_pointer,
goto_table, goto_check, goto_default, goto_pointer,
nt_base, reduce_table, token_table, shift_n,
reduce_n, use_result, * = arg
_racc_init_sysvars
tok = nil
act = nil
i = nil
nerr = 0
catch(:racc_end_parse) {
until i = action_pointer[@racc_state[-1]]
while act = _racc_evalact(action_default[@racc_state[-1]], arg)
end
end
recv.__send__(mid) do |tok, val|
# $stderr.puts "rd: tok=#{tok}, val=#{val}"
unless tok
@racc_t = 0
else
@racc_t = (token_table[tok] or 1) # error token
end
@racc_val = val
@racc_read_next = false
i += @racc_t
if i >= 0 and
act = action_table[i] and
action_check[i] == @racc_state[-1]
;
# $stderr.puts "01: act=#{act}"
else
act = action_default[@racc_state[-1]]
# $stderr.puts "02: act=#{act}"
# $stderr.puts "curstate=#{@racc_state[-1]}"
end
while act = _racc_evalact(act, arg)
end
while not (i = action_pointer[@racc_state[-1]]) or
not @racc_read_next or
@racc_t == 0 # $
if i and i += @racc_t and
i >= 0 and
act = action_table[i] and
action_check[i] == @racc_state[-1]
;
# $stderr.puts "03: act=#{act}"
else
# $stderr.puts "04: act=#{act}"
act = action_default[@racc_state[-1]]
end
while act = _racc_evalact(act, arg)
end
end
end
}
end
###
### common
###
def _racc_evalact( act, arg )
# $stderr.puts "ea: act=#{act}"
action_table, action_check, action_default, action_pointer,
goto_table, goto_check, goto_default, goto_pointer,
nt_base, reduce_table, token_table, shift_n,
reduce_n, use_result, * = arg
nerr = 0 # tmp
if act > 0 and act < shift_n
#
# shift
#
if @racc_error_status > 0
@racc_error_status -= 1 unless @racc_t == 1 # error token
end
@racc_vstack.push @racc_val
@racc_state.push act
@racc_read_next = true
if @yydebug
@racc_tstack.push @racc_t
racc_shift @racc_t, @racc_tstack, @racc_vstack
end
elsif act < 0 and act > -reduce_n
#
# reduce
#
code = catch(:racc_jump) {
@racc_state.push _racc_do_reduce(arg, act)
false
}
if code
case code
when 1 # yyerror
@racc_user_yyerror = true # user_yyerror
return -reduce_n
when 2 # yyaccept
return shift_n
else
raise RuntimeError, '[Racc Bug] unknown jump code'
end
end
elsif act == shift_n
#
# accept
#
racc_accept if @yydebug
throw :racc_end_parse, @racc_vstack[0]
elsif act == -reduce_n
#
# error
#
case @racc_error_status
when 0
unless arg[21] # user_yyerror
nerr += 1
on_error @racc_t, @racc_val, @racc_vstack
end
when 3
if @racc_t == 0 # is $
throw :racc_end_parse, nil
end
@racc_read_next = true
end
@racc_user_yyerror = false
@racc_error_status = 3
while true
if i = action_pointer[@racc_state[-1]]
i += 1 # error token
if i >= 0 and
(act = action_table[i]) and
action_check[i] == @racc_state[-1]
break
end
end
throw :racc_end_parse, nil if @racc_state.size < 2
@racc_state.pop
@racc_vstack.pop
if @yydebug
@racc_tstack.pop
racc_e_pop @racc_state, @racc_tstack, @racc_vstack
end
end
return act
else
raise RuntimeError, "[Racc Bug] unknown action #{act.inspect}"
end
racc_next_state(@racc_state[-1], @racc_state) if @yydebug
nil
end
def _racc_do_reduce( arg, act )
action_table, action_check, action_default, action_pointer,
goto_table, goto_check, goto_default, goto_pointer,
nt_base, reduce_table, token_table, shift_n,
reduce_n, use_result, * = arg
state = @racc_state
vstack = @racc_vstack
tstack = @racc_tstack
i = act * -3
len = reduce_table[i]
reduce_to = reduce_table[i+1]
method_id = reduce_table[i+2]
void_array = []
tmp_t = tstack[-len, len] if @yydebug
tmp_v = vstack[-len, len]
tstack[-len, len] = void_array if @yydebug
vstack[-len, len] = void_array
state[-len, len] = void_array
# tstack must be updated AFTER method call
if use_result
vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
else
vstack.push __send__(method_id, tmp_v, vstack)
end
tstack.push reduce_to
racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
k1 = reduce_to - nt_base
if i = goto_pointer[k1]
i += state[-1]
if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
return curstate
end
end
goto_default[k1]
end
def on_error( t, val, vstack )
raise ParseError, sprintf("\nparse error on value %s (%s)",
val.inspect, token_to_str(t) || '?')
end
def yyerror
throw :racc_jump, 1
end
def yyaccept
throw :racc_jump, 2
end
def yyerrok
@racc_error_status = 0
end
# for debugging output
def racc_read_token( t, tok, val )
@racc_debug_out.print 'read '
@racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
@racc_debug_out.puts val.inspect
@racc_debug_out.puts
end
def racc_shift( tok, tstack, vstack )
@racc_debug_out.puts "shift #{racc_token2str tok}"
racc_print_stacks tstack, vstack
@racc_debug_out.puts
end
def racc_reduce( toks, sim, tstack, vstack )
out = @racc_debug_out
out.print 'reduce '
if toks.empty?
out.print ' <none>'
else
toks.each {|t| out.print ' ', racc_token2str(t) }
end
out.puts " --> #{racc_token2str(sim)}"
racc_print_stacks tstack, vstack
@racc_debug_out.puts
end
def racc_accept
@racc_debug_out.puts 'accept'
@racc_debug_out.puts
end
def racc_e_pop( state, tstack, vstack )
@racc_debug_out.puts 'error recovering mode: pop token'
racc_print_states state
racc_print_stacks tstack, vstack
@racc_debug_out.puts
end
def racc_next_state( curstate, state )
@racc_debug_out.puts "goto #{curstate}"
racc_print_states state
@racc_debug_out.puts
end
def racc_print_stacks( t, v )
out = @racc_debug_out
out.print ' ['
t.each_index do |i|
out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
end
out.puts ' ]'
end
def racc_print_states( s )
out = @racc_debug_out
out.print ' ['
s.each {|st| out.print ' ', st }
out.puts ' ]'
end
def racc_token2str( tok )
self.class::Racc_token_to_s_table[tok] or
raise RuntimeError, "[Racc Bug] can't convert token #{tok} to string"
end
def token_to_str( t )
self.class::Racc_token_to_s_table[t]
end
end
end

View File

@ -0,0 +1,631 @@
#!/usr/bin/ruby
#
# racc
#
# Copyright (c) 1999-2002 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU Lesser General Public License version 2 or later.
#
##### main -----------------------------------------------------
def racc_main
opt = get_options()
require opt['-R'] || 'racc/compiler'
srcfn = ARGV[0]
racc = Racc::Compiler.new
begin
racc_main0 racc, srcfn, opt
rescue Racc::ParseError, Racc::ScanError, Racc::RaccError, Errno::ENOENT
raise if racc.debug
msg = $!.to_s
unless /\A\d/ === msg
msg[0,0] = ' '
end
$stderr.puts "#{File.basename $0}:#{srcfn}:" + msg
exit 1
end
end
def racc_main0( racc, srcfn, opt )
srcstr = nil
File.open(srcfn, 'r') {|f| srcstr = f.read }
set_flags__before_parse racc, opt
if opt['-P']
prof = pcompile(racc, srcstr, srcfn) {
set_flags__after_parse racc, opt
}
else
racc.parse srcstr, srcfn
if opt['--check-only']
$stderr.puts 'syntax ok'
exit 0
end
set_flags__after_parse racc, opt
racc.compile
end
write_table_file racc, srcfn, opt
if prof
report_profile prof
end
if opt['--verbose']
output_fn = opt['--log-file'] ||
make_filename(opt['--output'] || srcfn, '.output')
File.open(output_fn, 'w') {|f|
racc.output f
}
end
report_conflict racc, opt
report_useless racc, opt
end
##### parse arg ------------------------------------------------
require 'getoptlong'
require 'racc/info'
Racc_Options = <<S
o -g --debug - output parser for user level debugging
o -o --output-file <outfile> file name of output [<fname>.tab.rb]
o -e --executable <rubypath> insert #! line in output ('ruby' to default)
o -E --embedded - output file which don't need runtime
o -l --no-line-convert - never convert line numbers (for ruby<=1.4.3)
o -c --line-convert-all - convert line numbers also header and footer
x -s --super <super> use <super> instead of Racc::Parser
x -r --runtime <file> use <file> instead of 'racc/parser'
o -a --no-omit-actions - never omit actions
o -v --verbose - create <filename>.output file
o -O --log-file <fname> file name of verbose output [<fname>.output]
o -C --check-only - syntax check only
o -S --output-status - output status time to time
o - --no-extentions - run without any ruby extentions
o -h --help - print this message and quit
o - --version - print version and quit
o - --runtime-version - print runtime version and quit
o - --copyright - print copyright and quit
x -P - - report profile
x -R - <req> require <req> instead of 'racc/libracc'
x -D - <flags> set (racc's) debug flags
S
module Racc
end
def get_options
tmp = Racc_Options.collect {|line|
next if /\A\s*\z/ === line
disp, sopt, lopt, takearg, doc = line.strip.split(/\s+/, 5)
a = []
a.push lopt unless lopt == '-'
a.push sopt unless sopt == '-'
a.push takearg == '-' ?
GetoptLong::NO_ARGUMENT : GetoptLong::REQUIRED_ARGUMENT
a
}
getopt = GetoptLong.new(*tmp.compact)
getopt.quiet = true
opt = {}
begin
getopt.each do |name, arg|
raise GetoptLong::InvalidOption,
"#{File.basename $0}: #{name} given twice" if opt.key? name
opt[name] = arg.empty? ? true : arg
end
rescue GetoptLong::AmbigousOption, GetoptLong::InvalidOption,
GetoptLong::MissingArgument, GetoptLong::NeedlessArgument
usage 1, $!.message
end
usage 0 if opt['--help']
if opt['--version']
puts "racc version #{Racc::Version}"
exit 0
end
Racc.const_set :Racc_No_Extentions, opt['--no-extentions']
if opt['--runtime-version']
require 'racc/parser'
printf "racc runtime version %s (rev. %s); %s\n",
Racc::Parser::Racc_Runtime_Version,
Racc::Parser::Racc_Runtime_Revision,
if Racc::Parser.racc_runtime_type == 'ruby'
sprintf('ruby core version %s (rev. %s)',
Racc::Parser::Racc_Runtime_Core_Version_R,
Racc::Parser::Racc_Runtime_Core_Revision_R)
else
sprintf('c core version %s (rev. %s)',
Racc::Parser::Racc_Runtime_Core_Version_C,
Racc::Parser::Racc_Runtime_Core_Revision_C)
end
exit 0
end
if opt['--copyright']
puts "racc version #{Racc::Version}"
puts "#{Racc::Copyright} <aamine@loveruby.net>"
exit 0
end
usage(1, 'no grammar file given') if ARGV.empty?
usage(1, 'too many grammar files given') if ARGV.size > 1
opt['--line-convert'] = true
if opt['--no-line-convert']
opt['--line-convert'] = opt['--line-convert-all'] = false
end
opt['--omit-action'] = true
if opt['--no-omit-action']
opt['--omit-action'] = false
end
opt
end
def usage( status, msg = nil )
f = (status == 0 ? $stdout : $stderr)
f.puts "#{File.basename $0}: #{msg}" if msg
f.print(<<EOS)
Usage: racc [options] <grammar file>
Options:
EOS
Racc_Options.each do |line|
if /\A\s*\z/ === line
f.puts
next
end
disp, sopt, lopt, takearg, doc = line.strip.split(/\s+/, 5)
if disp == 'o'
sopt = nil if sopt == '-'
lopt = nil if lopt == '-'
opt = [sopt, lopt].compact.join(',')
takearg = nil if takearg == '-'
opt = [opt, takearg].compact.join(' ')
f.printf "%-27s %s\n", opt, doc
end
end
exit status
end
##### compile ----------------------------------------------
def set_flags__before_parse( racc, opt )
racc.verbose = opt['--output-status']
if opt['-D'] and /p/ === opt['-D']
racc.d_parse = true
end
end
def set_flags__after_parse( racc, opt )
# overwrite source's
racc.debug_parser = opt['--debug']
racc.convert_line = opt['--line-convert']
racc.omit_action = opt['--omit-action']
if opt['-D'] or $DEBUG
optd = opt['-D'] || ''
$stdout.sync = true
racc.debug = true
racc.d_rule = true if /r/ === optd
racc.d_token = true if /t/ === optd
racc.d_state = true if /s/ === optd
racc.d_la = true if /l/ === optd
racc.d_prec = true if /c/ === optd
end
end
##### profile
def pcompile( racc, srcstr, srcfn )
times = []
times.push [ 'parse', get_lap{ racc.parse(srcstr, srcfn) } ]
yield
times.push [ 'state', get_lap{ racc.nfa } ]
times.push [ 'resolve', get_lap{ racc.dfa } ]
times
end
def get_lap
begt = Time.times.utime
yield
endt = Time.times.utime
endt - begt
end
def report_profile( prof )
out = $stderr
whole = 0
prof.each do |arr|
whole += arr[1]
end
whole = 0.01 if whole == 0
out.puts '--task-----------+--sec------+---%-'
prof.each do |arr|
name, time = arr
out.printf("%-19s %s %3d%%\n",
name, pjust(time,4,4), (time/whole * 100).to_i)
end
out.puts '-----------------+-----------+-----'
out.printf("%-20s%s\n",
'total', pjust(whole,4,4))
end
def pjust( num, i, j )
m = /(\d+)(\.\d+)?/.match(num.to_s)
str = m[1].rjust(i)
if m[2]
str << m[2].ljust(j+1)[0,j+1]
end
str
end
##### output -----------------------------------------------
require 'racc/rubyloader'
def write_table_file( racc, srcfn, opt )
tabfn = opt['--output-file'] || make_filename(srcfn, '.tab.rb')
RaccTableFile.new(tabfn, srcfn, opt['--line-convert']) {|f|
f.shebang opt['--executable'] if opt['--executable']
f.notice
f.require opt['--embedded'], opt['--runtime'] || 'racc/parser'
f.header opt['--line-convert-all']
f.parser_class(racc.parser.class_name,
opt['--super'] || racc.parser.super_class || 'Racc::Parser') {
f.inner
racc.source f.file
}
f.footer opt['--line-convert-all']
}
if opt['--executable']
File.chmod 0755, tabfn
else
File.chmod 0644, tabfn
end
end
def make_filename( fname, suffix )
fname.sub(/(?:\..*?)?\z/, suffix)
end
class RaccTableFile
def initialize( tabfn, srcfn, c )
@tabfn = tabfn
@srcfn = srcfn
@convline = c
@header_labels = %w( header prepare )
@inner_labels = %w( inner )
@footer_labels = %w( footer driver )
@is_top = false
@uniq = {}
init_user_code
File.open(tabfn, 'w') {|f|
@f = f
yield self
}
end
def file
@f
end
RUBY_PATH = ::Config::CONFIG['bindir'] + '/' +
::Config::CONFIG['ruby_install_name']
def shebang( path )
@f.print "#!#{path == 'ruby' ? RUBY_PATH : path}\n"
end
def notice
@f.print <<EOS
#
# DO NOT MODIFY!!!!
# This file is automatically generated by racc #{Racc::Version}
# from racc grammer file "#{@srcfn}".
#
EOS
end
def require( embed_p, parser_rb )
if embed_p
@f.print <<EOS
#
# #{@tabfn}: generated by racc (runtime embedded)
#
EOS
is_top {
embed 'racc/parser.rb'
}
@f.puts
else
@f.puts
@f.puts "require '#{parser_rb}'"
@f.puts
end
end
def parser_class( classname, superclass )
@f.puts
mods = classname.split('::')
real = mods.pop
mods.each_with_index do |m,i|
@f.puts "#{' ' * i}module #{m}"
@f.puts
end
@f.puts "#{' ' * mods.size}class #{real} < #{superclass}"
yield
@f.puts "#{' ' * mods.size}end \# class #{real}"
mods.reverse.each_with_index do |m,i|
@f.puts
@f.puts "#{' ' * (mods.size - i - 1)}end \# module #{m}"
end
end
def header( conv )
is_top {
add_part conv, @header_labels
}
end
def inner
add_part @convline, @inner_labels
end
def footer( conv )
is_top {
add_part conv, @footer_labels
}
end
private
###
### init
###
def init_user_code
@usercode = Racc::GrammarFileParser.get_usercode(@srcfn)
check_dup_ucode
end
def check_dup_ucode
[ @header_labels, @inner_labels, @footer_labels ].each do |names|
a = names.select {|n| @usercode[n] }
if a.size > 1
raise Racc::RaccError,
"'#{a.join %<' and '>}' used at same time; must be only one"
end
end
end
###
### embed
###
def embed( rbfile )
@f.print <<EOS
###### #{rbfile}
unless $".index '#{rbfile}'
$".push '#{rbfile}'
EOS
add_file RubyLoader.find_feature(rbfile)
@f.puts "end # end of #{rbfile}"
end
###
### part
###
def add_part( convp, names )
str, lineno, fnames = getent(names)
convert_line(convp) {
add str, @srcfn, lineno if str and not str.strip.empty?
}
fnames.each {|n| add_file n } if fnames
end
def getent( names )
names.each do |n|
return @usercode[n] if @usercode[n]
end
nil
end
def convert_line( b )
save, @convline = @convline, b
yield
@convline = save
end
###
### low level code
###
def add_file( fname )
File.open(fname) {|f|
add f.read, fname, 1
}
end
def add( str, fn, lineno )
@f.puts
if @convline
surrounding_by_eval(fn, str, lineno) {
@f.puts str
}
else
@f.puts str
end
end
def surrounding_by_eval( nm, str, lineno )
sep = makesep(nm, str)
@f.print 'self.class.' if toplevel?
@f.puts "module_eval <<'#{sep}', '#{nm}', #{lineno}"
yield
@f.puts sep
end
def is_top
@is_top = true
yield
@is_top = false
end
def toplevel?
@is_top
end
def makesep( nm, str )
sep = uniqlabel(nm)
sep *= 2 while str.index(sep)
sep
end
def uniqlabel( nm )
ret = "..end #{nm} modeval..id"
srand
5.times do
ret << sprintf('%02x', rand(255))
end
ret << sprintf('%02x', rand(255)) while @uniq[ret]
@uniq[ret] = true
ret
end
end # class RaccTableFile
##### report -----------------------------------------------
def report_conflict( racc, opt )
sr = 0
rr = 0
racc.statetable.each do |st|
sr += st.srconf.size if st.srconf
rr += st.rrconf.size if st.rrconf
end
if opt['-D'] and /o/ === opt['-D']
debugout {|f|
f.print "ex#{racc.ruletable.expect}\n"
f.print "sr#{sr}\n" if sr > 0
f.print "rr#{rr}\n" if rr > 0
}
return
end
ex = racc.ruletable.expect
if (sr > 0 or ex) and sr != ex
$stderr.puts "#{sr} shift/reduce conflicts"
end
if rr > 0
$stderr.puts "#{rr} reduce/reduce conflicts"
end
end
def report_useless( racc, opt )
nt = 0
rl = 0
racc.symboltable.each_nonterm do |t|
if t.useless?
nt += 1
end
end
racc.ruletable.each do |r|
if r.useless?
rl += 1
end
end
if opt['-D'] and /o/ === opt['-D']
debugout('a') {|f|
f.print "un#{nt}\n" if nt > 0
f.print "ur#{rl}\n" if rl > 0
}
return
end
if nt > 0 or rl > 0
$stderr.printf "%s%s%s\n",
nt > 0 ? "#{nt} useless nonterminals" : '',
((nt > 0) && (rl > 0)) ? ' and ' : '',
rl > 0 ? "#{rl} useless rules" : ''
end
if racc.ruletable.start.useless?
$stderr.puts 'fatal: start symbol does not derive any sentence'
end
end
def debugout( flag = 'w', &block )
File.open("log/#{File.basename(ARGV[0])}", flag, &block)
end
##### entry point ------------------------------------------
racc_main

View File

@ -0,0 +1,55 @@
#
# rubyloader.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
# $ amstd Id: rubyloader.rb,v 1.5 2003/05/26 14:14:57 aamine Exp $
#
require 'rbconfig'
module RubyLoader
module_function
def find_feature( feature )
with_ext(feature) do |fname|
$LOAD_PATH.each do |dir|
path = dir + '/' + fname
return path if File.file? path
end
end
nil
end
def provided?( feature )
with_ext(feature) do |filename|
return true if $".index(filename)
end
false
end
alias required? provided?
def provide( feature )
$".push feature
end
def with_ext( feature )
if /\.(?:rb|#{Config::CONFIG['DLEXT']})\z/o === feature
yield feature
else
[ 'rb', Config::CONFIG['DLEXT'] ].each do |ext|
yield feature + '.' + ext
end
end
end
end

View File

@ -0,0 +1,985 @@
#
# state.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
require 'racc/iset'
module Racc
class RaccError < StandardError; end
#
# StateTable
#
# the table of lalr states.
#
class StateTable
def initialize( racc )
@ruletable = racc.ruletable
@symboltable = racc.symboltable
@d_state = racc.d_state
@d_la = racc.d_la
@d_prec = racc.d_prec
@states = []
@statecache = {}
@actions = ActionTable.new(@ruletable, self)
end
attr_reader :actions
def size
@states.size
end
def inspect
'#<state table>'
end
alias to_s inspect
def []( i )
@states[i]
end
def each_state( &block )
@states.each(&block)
end
alias each each_state
def each_index( &block )
@states.each_index(&block)
end
###
### nfa
###
def init
# add state 0
core_to_state [ @ruletable[0].ptrs[0] ]
cur = 0
@gotos = []
while cur < @states.size
generate_states @states[cur] # state is added here
cur += 1
end
@actions.init
end
def generate_states( state )
puts "dstate: #{state}" if @d_state
table = {}
ptr = pt = s = g = nil
state.closure.each do |ptr|
if sym = ptr.dereference
addsym table, sym, ptr.next
end
end
table.each do |sym, core|
puts "dstate: sym=#{sym} ncore=#{core}" if @d_state
dest = core_to_state(core.to_a)
state.goto_table[sym] = dest
id = sym.nonterminal?() ? @gotos.size : nil
g = Goto.new(id, sym, state, dest)
@gotos.push g if sym.nonterminal?
state.gotos[sym] = g
puts "dstate: #{state.ident} --#{sym}--> #{dest.ident}" if @d_state
# check infinite recursion
if state.ident == dest.ident and state.closure.size == 1
raise RaccError, sprintf("Infinite recursion: state %d, with rule %d",
state.ident, state.ptrs[0].rule.ident)
end
end
end
def addsym( table, sym, ptr )
unless s = table[sym]
table[sym] = s = ISet.new
end
s.add ptr
end
def core_to_state( core )
#
# convert CORE to a State object.
# If matching state does not exist, create it and add to the table.
#
k = fingerprint(core)
unless dest = @statecache[k]
# not registered yet
dest = State.new(@states.size, core)
@states.push dest
@statecache[k] = dest
puts "core_to_state: create state ID #{dest.ident}" if @d_state
else
if @d_state
puts "core_to_state: dest is cached ID #{dest.ident}"
puts "core_to_state: dest core #{dest.core.join(' ')}"
end
end
dest
end
def fingerprint( arr )
arr.map {|i| i.ident }.pack('L*')
end
###
### dfa
###
def determine
la = lookahead
@states.each do |state|
state.set_la la
resolve state
end
set_accept
@states.each do |state|
pack state
end
check_useless
end
#
# lookahead
#
def lookahead
#
# lookahead algorithm ver.3 -- from bison 1.26
#
state = goto = arr = ptr = st = rl = i = a = t = g = nil
gotos = @gotos
if @d_la
puts "\n--- goto ---"
gotos.each_with_index {|g,i| print i, ' '; p g }
end
### initialize_LA()
### set_goto_map()
la_rules = []
@states.each do |state|
state.check_la la_rules
end
### initialize_F()
f = create_tmap(gotos.size)
reads = []
edge = []
gotos.each do |goto|
goto.to_state.goto_table.each do |t, st|
if t.terminal?
f[goto.ident] |= (1 << t.ident)
elsif t.nullable?
edge.push goto.to_state.gotos[t].ident
end
end
if edge.empty?
reads.push nil
else
reads.push edge
edge = []
end
end
digraph f, reads
if @d_la
puts "\n--- F1 (reads) ---"
print_tab gotos, reads, f
end
### build_relations()
### compute_FOLLOWS
path = nil
edge = []
lookback = Array.new(la_rules.size, nil)
includes = []
gotos.each do |goto|
goto.symbol.heads.each do |ptr|
path = record_path(goto.from_state, ptr.rule)
g = path[-1]
st = g ? g.to_state : goto.from_state
if st.conflict?
addrel lookback, st.rruleid(ptr.rule), goto
end
path.reverse_each do |g|
break if g.symbol.terminal?
edge.push g.ident
break unless g.symbol.nullable?
end
end
if edge.empty?
includes.push nil
else
includes.push edge
edge = []
end
end
includes = transpose(includes)
digraph f, includes
if @d_la
puts "\n--- F2 (includes) ---"
print_tab gotos, includes, f
end
### compute_lookaheads
la = create_tmap(la_rules.size)
lookback.each_with_index do |arr, i|
if arr
arr.each do |g|
la[i] |= f[g.ident]
end
end
end
if @d_la
puts "\n--- LA (lookback) ---"
print_tab la_rules, lookback, la
end
la
end
def create_tmap( size )
Array.new(size, 0) # use Integer as bitmap
end
def addrel( tbl, i, item )
if a = tbl[i]
a.push item
else
tbl[i] = [item]
end
end
def record_path( begst, rule )
st = begst
path = []
rule.symbols.each do |t|
goto = st.gotos[t]
path.push goto
st = goto.to_state
end
path
end
def transpose( rel )
new = Array.new(rel.size, nil)
rel.each_with_index do |arr, idx|
if arr
arr.each do |i|
addrel new, i, idx
end
end
end
new
end
def digraph( map, relation )
n = relation.size
index = Array.new(n, nil)
vertices = []
@infinity = n + 2
i = nil
index.each_index do |i|
if not index[i] and relation[i]
traverse i, index, vertices, map, relation
end
end
end
def traverse( i, index, vertices, map, relation )
vertices.push i
index[i] = height = vertices.size
proci = nil
if rp = relation[i]
rp.each do |proci|
unless index[proci]
traverse proci, index, vertices, map, relation
end
if index[i] > index[proci]
# circulative recursion !!!
index[i] = index[proci]
end
map[i] |= map[proci]
end
end
if index[i] == height
while true
proci = vertices.pop
index[proci] = @infinity
break if i == proci
map[proci] |= map[i]
end
end
end
###
# debug method
def print_atab( idx, tab )
tab.each_with_index do |i,ii|
printf '%-20s', idx[ii].inspect
p i
end
end
def print_tab( idx, rel, tab )
tab.each_with_index do |bin,i|
print i, ' ', idx[i].inspect, ' << '; p rel[i]
print ' '
each_t(@symboltable, bin) {|t| print ' ', t }
puts
end
end
# debug method
def print_tab_i( idx, rel, tab, i )
bin = tab[i]
print i, ' ', idx[i].inspect, ' << '; p rel[i]
print ' '
each_t(@symboltable, bin) {|t| print ' ', t }
end
# debug method
def printb( i )
each_t(@symboltable, i) do |t|
print t, ' '
end
puts
end
def each_t( tbl, set )
i = ii = idx = nil
0.upto( set.size ) do |i|
(0..7).each do |ii|
if set[idx = i * 8 + ii] == 1
yield tbl[idx]
end
end
end
end
#
# resolve
#
def resolve( state )
if state.conflict?
resolve_rr state, state.ritems
resolve_sr state, state.stokens
else
if state.rrules.empty?
# shift
state.stokens.each do |t|
state.action[t] = @actions.shift(state.goto_table[t])
end
else
# reduce
state.defact = @actions.reduce(state.rrules[0])
end
end
end
def resolve_rr( state, r )
pt = t = act = item = nil
r.each do |item|
item.each_la(@symboltable) do |t|
act = state.action[t]
if act
Reduce === act or raise "Racc FATAL: #{act.class} in action table"
#
# can't resolve R/R conflict (on t).
# reduce with upper rule as default
#
state.rr_conflict act.rule, item.rule, t
else
# not conflict
state.action[t] = @actions.reduce(item.rule)
end
end
end
end
def resolve_sr( state, s )
stok = rtok = goto = act = nil
s.each do |stok|
goto = state.goto_table[stok]
act = state.action[stok]
unless act
# no conflict
state.action[stok] = @actions.shift(goto)
else
unless Reduce === act
puts 'DEBUG -------------------------------'
p stok
p act
state.action.each do |k,v|
print k.inspect, ' ', v.inspect, "\n"
end
raise "Racc FATAL: #{act.class} in action table"
end
# conflict on stok
rtok = act.rule.prec
case do_resolve_sr(stok, rtok)
when :Reduce
# action is already set
when :Shift
# overwrite
act.decref
state.action[stok] = @actions.shift(goto)
when :Error
act.decref
state.action[stok] = @actions.error
when :CantResolve
# shift as default
act.decref
state.action[stok] = @actions.shift(goto)
state.sr_conflict stok, act.rule
end
end
end
end
ASSOC = {
:Left => :Reduce,
:Right => :Shift,
:Nonassoc => :Error
}
def do_resolve_sr( stok, rtok )
puts "resolve_sr: s/r conflict: rtok=#{rtok}, stok=#{stok}" if @d_prec
unless rtok and rtok.prec
puts "resolve_sr: no prec for #{rtok}(R)" if @d_prec
return :CantResolve
end
rprec = rtok.prec
unless stok and stok.prec
puts "resolve_sr: no prec for #{stok}(S)" if @d_prec
return :CantResolve
end
sprec = stok.prec
ret = if rprec == sprec
ASSOC[rtok.assoc] or
raise "Racc FATAL: #{rtok}.assoc is not Left/Right/Nonassoc"
else
(rprec > sprec) ? (:Reduce) : (:Shift)
end
puts "resolve_sr: resolved as #{ret.id2name}" if @d_prec
ret
end
#
# complete
#
def set_accept
anch = @symboltable.anchor
init_state = @states[0].goto_table[@ruletable.start]
targ_state = init_state.action[anch].goto_state
acc_state = targ_state.action[anch].goto_state
acc_state.action.clear
acc_state.goto_table.clear
acc_state.defact = @actions.accept
end
def pack( state )
### find most frequently used reduce rule
act = state.action
arr = Array.new(@ruletable.size, 0)
t = a = nil
act.each do |t,a|
if Reduce === a
arr[a.ruleid] += 1
end
end
i = arr.max
s = i>0 ? arr.index(i) : nil
### set & delete default action
if s
r = @actions.reduce(s)
if not state.defact or state.defact == r
act.delete_if {|t,a| a == r }
state.defact = r
end
else
state.defact ||= @actions.error
end
end
def check_useless
act = nil
used = []
@actions.each_reduce do |act|
if not act or act.refn == 0
act.rule.useless = true
else
t = act.rule.target
used[t.ident] = t
end
end
@symboltable.nt_base.upto(@symboltable.nt_max - 1) do |n|
unless used[n]
@symboltable[n].useless = true
end
end
end
end # class StateTable
#
# State
#
# represents a LALR state.
#
class State
def initialize( ident, core )
@ident = ident
@core = core
@goto_table = {}
@gotos = {}
@stokens = nil
@ritems = nil
@action = {}
@defact = nil
@rrconf = nil
@srconf = nil
###
@closure = make_closure(@core)
end
attr_reader :ident
alias stateid ident
alias hash ident
attr_reader :core
attr_reader :closure
attr_reader :goto_table
attr_reader :gotos
attr_reader :stokens
attr_reader :ritems
attr_reader :rrules
attr_reader :action
attr_accessor :defact # default action
attr_reader :rrconf
attr_reader :srconf
def inspect
"<state #{@ident}>"
end
alias to_s inspect
def ==( oth )
@ident == oth.ident
end
alias eql? ==
def make_closure( core )
set = ISet.new
core.each do |ptr|
set.add ptr
if t = ptr.dereference and t.nonterminal?
set.update_a t.expand
end
end
set.to_a
end
def check_la( la_rules )
@conflict = false
s = []
r = []
@closure.each do |ptr|
if t = ptr.dereference
if t.terminal?
s[t.ident] = t
if t.ident == 1 # $error
@conflict = true
end
end
else
r.push ptr.rule
end
end
unless r.empty?
if not s.empty? or r.size > 1
@conflict = true
end
end
s.compact!
@stokens = s
@rrules = r
if @conflict
@la_rules_i = la_rules.size
@la_rules = r.map {|i| i.ident }
la_rules.concat r
else
@la_rules_i = @la_rules = nil
end
end
def conflict?
@conflict
end
def rruleid( rule )
if i = @la_rules.index(rule.ident)
@la_rules_i + i
else
puts '/// rruleid'
p self
p rule
p @rrules
p @la_rules_i
raise 'Racc FATAL: cannot get reduce rule id'
end
end
def set_la( la )
return unless @conflict
i = @la_rules_i
@ritems = r = []
@rrules.each do |rule|
r.push Item.new(rule, la[i])
i += 1
end
end
def rr_conflict( high, low, ctok )
c = RRconflict.new(@ident, high, low, ctok)
@rrconf ||= {}
if a = @rrconf[ctok]
a.push c
else
@rrconf[ctok] = [c]
end
end
def sr_conflict( shift, reduce )
c = SRconflict.new(@ident, shift, reduce)
@srconf ||= {}
if a = @srconf[shift]
a.push c
else
@srconf[shift] = [c]
end
end
end # State
#
# Goto
#
# represents a transition on the grammar.
# REAL GOTO means transition by nonterminal,
# but this class treats also terminal's.
# If one is a terminal transition, .ident returns nil.
#
class Goto
def initialize( ident, sym, from, to )
@ident = ident
@symbol = sym
@from_state = from
@to_state = to
end
attr_reader :ident
attr_reader :symbol
attr_reader :from_state
attr_reader :to_state
def inspect
"(#{@from_state.ident}-#{@symbol}->#{@to_state.ident})"
end
end
#
# Item
#
# a LALR item. A set of rule and its lookahead tokens.
#
class Item
def initialize( rule, la )
@rule = rule
@la = la
end
attr_reader :rule
attr_reader :la
def each_la( tbl )
la = @la
i = ii = idx = nil
0.upto(la.size - 1) do |i|
(0..7).each do |ii|
if la[idx = i * 8 + ii] == 1
yield tbl[idx]
end
end
end
end
end
#
# ActionTable
#
# The table of LALR actions. Actions are either of
# Shift, Reduce, Accept and Error.
#
class ActionTable
def initialize( rt, st )
@ruletable = rt
@statetable = st
@reduce = []
@shift = []
@accept = nil
@error = nil
end
def init
@ruletable.each do |rule|
@reduce.push Reduce.new(rule)
end
@statetable.each do |state|
@shift.push Shift.new(state)
end
@accept = Accept.new
@error = Error.new
end
def reduce_n
@reduce.size
end
def reduce( i )
case i
when Rule then i = i.ident
when Integer then ;
else
raise "Racc FATAL: wrong class #{i.class} for reduce"
end
r = @reduce[i] or raise "Racc FATAL: reduce action #{i.inspect} not exist"
r.incref
r
end
def each_reduce( &block )
@reduce.each(&block)
end
def shift_n
@shift.size
end
def shift( i )
case i
when State then i = i.ident
when Integer then ;
else
raise "Racc FATAL: wrong class #{i.class} for shift"
end
@shift[i] or raise "Racc FATAL: shift action #{i} not exist"
end
def each_shift( &block )
@shift.each(&block)
end
attr_reader :accept
attr_reader :error
end
class Shift
def initialize( goto )
@goto_state = goto
end
attr_reader :goto_state
def goto_id
@goto_state.ident
end
def inspect
"<shift #{@goto_state.ident}>"
end
end
class Reduce
def initialize( rule )
@rule = rule
@refn = 0
end
attr_reader :rule
attr_reader :refn
def ruleid
@rule.ident
end
def inspect
"<reduce #{@rule.ident}>"
end
def incref
@refn += 1
end
def decref
@refn -= 1
bug! 'act.refn < 0' if @refn < 0
end
end
class Accept
def inspect
"<accept>"
end
end
class Error
def inspect
"<error>"
end
end
#
# Conflicts
#
class SRconflict
def initialize( sid, shift, reduce )
@stateid = sid
@shift = shift
@reduce = reduce
end
attr_reader :stateid
attr_reader :shift
attr_reader :reduce
def to_s
sprintf('state %d: S/R conflict rule %d reduce and shift %s',
@stateid, @reduce.ruleid, @shift.to_s)
end
end
class RRconflict
def initialize( sid, high, low, tok )
@stateid = sid
@high_prec = high
@low_prec = low
@token = tok
end
attr_reader :stateid
attr_reader :high_prec
attr_reader :low_prec
attr_reader :token
def to_s
sprintf('state %d: R/R conflict with rule %d and %d on %s',
@stateid, @high_prec.ident, @low_prec.ident, @token.to_s)
end
end
end

View File

@ -0,0 +1,40 @@
#
# usercodeparser.rb
#
# Copyright (c) 1999-2003 Minero Aoki <aamine@loveruby.net>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU LGPL, Lesser General Public License version 2.
# For details of the GNU LGPL, see the file "COPYING".
#
module Racc
class GrammarFileParser < Parser
def GrammarFileParser.get_usercode( fname )
ret = {}
re = /\A----+\s*(header|inner|footer|prepare|driver)\s*(=)?/i
str = nil
lineno = 0
File.foreach(fname) do |line|
lineno += 1
if m = re.match(line)
ret[m[1].downcase] = [
str = '',
lineno + 1,
(m[2] && !m[2].empty?) ? m.post_match.strip.split(/\s+/) : nil
]
else
str << line if str
end
end
ret
end
end
end

View File

@ -0,0 +1,595 @@
module Translator
class SymbolTable
def initialize
super
@prepared = false
@table = {}
@shortcuts = {}
end
def each(&block)
@table.each_value(&block)
end
def dump
@table.each { |key, symbol|
puts "#{symbol.inspect}"
}
end
#removes a symbol completely from symbol table
#used when compiling incremental
def remove(symbol)
check = @table.delete([symbol.identifier, symbol.class, symbol.scope])
throw InternalError.new unless check == symbol
@shortcuts[symbol.identifier] -= [symbol]
end
def get(identifier, symbol_class, scope = nil, &block)
symbol = @table[[identifier, symbol_class, scope]]
if symbol.nil? && !block.nil?
symbol = block.call
end
return symbol
end
def get_all_regexp(regexp)
result = []
@table.each { |key, value|
result << value if key[0] =~ regexp
}
return result
end
# function to intercept domain symbol information for shortcut generation.
def set_domain_symbol(symbol, domain_symbol)
raise InternalError.new unless symbol.class <= DomainValueSymbol
symbol.domain_symbol = domain_symbol
symbol.enum_domain = domain_symbol if symbol.class <= EnumTypeSymbol
shortcut = symbol.shortcut
symbols = @shortcuts[shortcut]
if symbols.nil?
@shortcuts[shortcut] = [symbol]
else
symbols << symbol unless symbols.include?(symbol)
end
end
# returns array of shortcut symbols for given identifier.
def get_shortcuts(identifier)
result = @shortcuts[identifier]
return [] if result.nil?
return Array.new(result)
end
# declares and returns a symbol with given identifier and requested class and scope.
# scope is (only) used to disabiguate state symbols and should be set to the corresponding option symbol.
# otherwise scope is nil.
# yields block on symbol redefinition
def declare(identifier, symbol_class, scope = nil, &block)
key = [identifier, symbol_class, scope]
symbol = @table[key]
if symbol.nil?
symbol = symbol_class.new(identifier, scope)
@table[key] = symbol
symbols = @shortcuts[identifier]
if symbols.nil?
@shortcuts[identifier] = [symbol]
else
symbols << symbol unless symbols.include?(symbol)
end
else
block.call unless block.nil?
end
return symbol
end
# checks symbol table and returns array of error messages.
def errors
result = []
@table.each do |key, symbol|
result << InternalError.new("no domain symbol set on #{key.inspect}") if symbol.class <= DomainValueSymbol && symbol.domain_symbol.nil?
end
return result
end
end
#uesd by SymbolContext to validate the function parameters in xtc code
class DomainParameterContext
attr_reader :domain_symbol
attr_reader :used_value_symbols
attr_reader :compiler_context
def initialize(domain_symbol, compiler_context)
super()
@domain_symbol = domain_symbol
@compiler_context = compiler_context
@used_value_symbols = []
end
def use_value_symbol(symbol, token)
if used_value_symbols.include?(symbol)
compiler_context.eh.error ParameterMultipleSetting.new(@compiler_context, token)
end
unless symbol.class <= DomainValueSymbol
compiler_context.eh.error DomainSymbolExpected.new(@compiler_context, token)
end
unless symbol.domain_symbol == domain_symbol
compiler_context.eh.error MismatchingDomain.new(@compiler_context, token)
end
# mark symbol as used for MissingParameter warning
@used_value_symbols << symbol
end
# issue a MissingParameter warning on unused domain value symbols.
def check_used_value_symbols(token)
if used_value_symbols.size < @domain_symbol.value_symbols.size
(@domain_symbol.value_symbols - used_value_symbols).each {|symbol|
compiler_context.eh.error ParameterMissing.new(compiler_context, token, symbol)
}
end
end
end
# class provides short access methods to members of compiler context.
class CompilerContextWorker
def initialize(compiler_context)
@compiler_context = compiler_context
end
def cc
return @compiler_context
end
def cu
return @compiler_context.compilation_unit
end
def st
return @compiler_context.symbol_table
end
def sc
return @compiler_context.symbol_context
end
def tz
return @compiler_context.tokenizer
end
def pc
return @compiler_context.parser_context
end
def bc
return @compiler_context.builder_context
end
def eh
return @compiler_context.error_handler
end
end
class CompilerContext < CompilerContextWorker
attr_reader :compilation_unit
attr_reader :symbol_table
attr_reader :tokenizer
attr_reader :parser_context
attr_reader :symbol_context
attr_reader :builder_context
attr_reader :error_handler
def initialize(compilation_unit, symbol_table)
super(self)
@compilation_unit = compilation_unit
@symbol_table = symbol_table
@tokenizer = Tokenizer.new(self)
@parser_context = ParserContext.new(self)
@symbol_context = SymbolContext.new(self)
@builder_context = BuilderContext.new(self)
@error_handler = ErrorHandler.new(self)
end
def id
return File.expand_path(@compilation_unit.src_filename)
end
def warnings?
eh.messages.each do |message|
return true if message.class <= CompilerWarning
end
return false
end
def errors?
eh.messages.each do |message|
return true if message.class <= CompilerError
end
return false
end
end
class CompilationUnit
attr_reader :src_fullname
attr_reader :src_filename
attr_reader :src_dir
attr_reader :src_mtime
attr_reader :dest_fullname
attr_reader :dest_filename
attr_reader :dest_dir
def initialize()
end
def set_src(working_directory, filename)
@src_filename = filename
@src_dir = working_directory
@src_fullname = File.join(@src_dir, @src_filename)
update_src_mtime
end
def update_src_mtime
@src_mtime = File.stat(@src_fullname).mtime
end
def set_dest(working_directory, filename = nil)
if filename.nil?
case @src_filename
when /^(.*)\.[xy]absl$/
@dest_filename = "#{$1}.xml"
when /^(.*)\.xml$/
@dest_filename = "#{$1}.xabsl"
else
raise InternalError.new
end
else
@dest_filename = filename
end
@dest_dir = working_directory unless working_directory.nil?
@dest_fullname = File.join(@dest_dir, @dest_filename)
end
end
class BuilderContext < CompilerContextWorker
def start_generate_code(le, out)
@stack = []
@out = out
generate_code(le)
end
def generate_code(le)
@stack.push le
le.to_code(cc, @out)
@stack.pop
end
#convinience method
def[](attribute_name)
return sc.to_code(@stack.last.attr[attribute_name])
end
end
class SymbolContext < CompilerContextWorker
attr_reader :from_code_declaration_count
attr_reader :from_code_usage_count
attr_reader :from_code_namespace_symbol_usage_count
def initialize(cc)
super
@from_code_declaration_count = Hash.new(0)
@from_code_usage_count = Hash.new(0)
@from_code_namespace_symbol_usage_count = Hash.new(0)
end
#transforms symbol to xtc identifier
def to_code(symbol, at_prefix_on_option_parameter = true)
return SymbolContext.to_code(symbol, at_prefix_on_option_parameter)
end
def SymbolContext.to_code(symbol, at_prefix_on_option_parameter = true)
identifier = symbol.identifier
if symbol.class <= DomainValueSymbol
if symbol.class == OptionParameterSymbol && at_prefix_on_option_parameter
subst = '@'
else
subst = ''
end
raise InternalError.new if symbol.domain_symbol.nil?
identifier = identifier.sub(/^#{Regexp.escape(symbol.domain_symbol.identifier)}\./ , subst) if symbol.qualified?
end
return identifier
end
def from_code_declare(token, symbol_class, domain_symbol = nil, identifier = nil, qualified = true)
raise InternalError.new if symbol_class <= DomainValueSymbol && domain_symbol.nil?
symbol = nil
identifier = token.to_s if identifier.nil?
#cut away the @prefix
if symbol_class == OptionParameterSymbol
raise InternalError.new if domain_symbol.nil?
#option parameter symbols *have* to be marked as qualified
raise InternalError.new unless qualified
identifier = identifier.sub(/^@/, "#{domain_symbol.identifier}.")
elsif [InputSymbolParameterSymbol, BasicBehaviorParameterSymbol].include?(symbol_class)
raise InternalError.new if domain_symbol.nil?
identifier = "#{domain_symbol.identifier}.#{identifier}" if qualified
elsif [EnumSymbolValueSymbol].include?(symbol_class)
raise InternalError.new if domain_symbol.nil?
identifier = "#{domain_symbol.identifier}.#{identifier}" if qualified
elsif symbol_class <= DomainValueSymbol
# this code does not yet support declaration of DomainValueSymbols,
# because of the prefix handling
# raise InternalError.new
raise InternalError.new if domain_symbol.nil?
identifier = "#{domain_symbol.identifier}.#{identifier}" if qualified
end
#StateSymbols get the option_symbol as scope
scope = nil
if symbol_class == StateSymbol
raise InternalError.new if pc.option_symbol.nil?
scope = pc.option_symbol
end
symbol = st.declare(identifier, symbol_class, scope) do
cc.eh.error MultipleDefinitions.new(cc, token)
end
unless domain_symbol.nil?
st.set_domain_symbol(symbol, domain_symbol)
end
#current symbol is declared within namespace
unless pc.namespace_symbol.nil?
symbol.namespace_symbol = pc.namespace_symbol
@from_code_namespace_symbol_usage_count[symbol.namespace_symbol] += 1
end
@from_code_usage_count[symbol] += 1
@from_code_declaration_count[symbol] += 1
if @from_code_declaration_count[symbol] > 1
eh.error MultipleDefinitions.new(cc, token)
end
return symbol
end
#used to track used namespace symbols for entity list generation
def used_namespace_symbols
return @from_code_namespace_symbol_usage_count.keys
end
#returns symbol from identifier
#
#returned symbol is subclasses of at least one element of symbol_classes
#if !domain_symbol.nil? the returned symbol is a DomainValueSymbol with this domain symbol
def from_code(token, symbol_classes, domain_symbol = nil, &block)
identifier = token.to_s
#separate-sausage for option parameters
if identifier =~ /^@/
raise InternalError.new if pc.option_symbol.nil?
identifier = identifier.sub(/^@/, "#{pc.option_symbol.identifier}.")
return st.get(identifier, OptionParameterSymbol) {
eh.error NoMatchingSymbolFound.new(cc, token, domain_symbol, symbol_classes)
from_code_declare(token, OptionParameterSymbol, pc.option_symbol, identifier)
}
end
symbol_classes = [symbol_classes] unless symbol_classes.class <= Array
symbols = get_fuzzy_fast(identifier, symbol_classes, domain_symbol)
#if we found exactly one symbol the world is in perfect order
#otherwise give error message
symbol = nil
case symbols.size
when 1:
symbol = symbols[0]
when 0:
if !block.nil?
return block.call
else
#declare symbol to prevent stopping the compile process
#SENSE?
eh.error NoMatchingSymbolFound.new(cc, token, domain_symbol, symbol_classes)
symbol = from_code_declare(token, symbol_classes[0], domain_symbol)
end
else
#return the first symbol to get on with compiling
#SENSE?
eh.error MultipleMatchingSymbolsFound.new(cc, token, domain_symbol, symbol_classes, symbols)
symbol = symbols[0]
end
@from_code_usage_count[symbol] += 1
@from_code_namespace_symbol_usage_count[symbol.namespace_symbol] += 1 unless symbol.namespace_symbol.nil?
symbol.usage_count += 1
return symbol
end
def get_fuzzy_fast(identifier, symbol_classes, domain_symbol)
symbols = st.get_shortcuts(identifier)
#delete symbols with wrong symbol class
symbols.delete_if { |symbol|
result = true
symbol_classes.each {|symbol_class|
if symbol.class <= symbol_class
result = false
end
}
result
}
#delete symbols out of scope
symbols.delete_if { |symbol|
!symbol.scope.nil? && symbol.scope != pc.option_symbol
}
#delete symbols with wrong domain_symbol
unless domain_symbol.nil?
symbols.delete_if {|symbol|
(not symbol.class <= DomainValueSymbol) || symbol.domain_symbol != domain_symbol
}
else
symbols.delete_if {|symbol|
symbol.class <= DomainValueSymbol
}
end
return symbols
end
#very imperformant due to regular expressions and speed >=O(#symbols)
def get_fuzzy(identifier, symbol_classes, domain_symbol)
regexp = /(^|\.)#{Regexp.escape(identifier)}$/
symbols = st.get_all_regexp(regexp)
#delete symbols with wrong symbol class
symbols.delete_if { |symbol|
result = true
symbol_classes.each {|symbol_class|
if symbol.class <= symbol_class
result = false
end
}
result
}
#delete symbols out of scope
symbols.delete_if { |symbol|
!symbol.scope.nil? && symbol.scope != pc.option_symbol
}
#delete symbols with wrong domain_symbol
unless domain_symbol.nil?
symbols.delete_if {|symbol|
symbol.domain_symbol != domain_symbol
}
end
#double check by domain_value substitution or identity
result = []
symbols.each {|symbol|
if symbol.identifier == identifier
result << symbol
elsif symbol.class <= DomainValueSymbol
result << symbol if symbol.identifier == "#{symbol.domain_symbol.identifier}.#{identifier}"
end
}
return result
end
end
# represents a the location in code where a symbol occurs
# and is used to resolve symbol abbrevs. and ambiguities
# performs semantic checking
class ParserContext < CompilerContextWorker
attr_accessor :option_root
attr_accessor :agent_collection_root
attr_accessor :namespace_root
attr_accessor :option_definitions_temp
attr_accessor :option_definitions_by_symbol
attr_accessor :option_symbol
attr_accessor :state_symbol
attr_accessor :input_symbol
attr_accessor :initial_state_symbol
attr_accessor :namespace_symbol
attr_accessor :behavior_symbol
attr_reader :function_dpcs
attr_reader :subsequent_dpc
attr_reader :subsequent_type
attr_reader :includes
attr_accessor :option_declared
attr_accessor :agent_declared
attr_accessor :namespace_declared
attr_accessor :enum_domains
attr_accessor :has_common_decision_tree
def initialize(compiler_context)
super
@function_dpcs = []
@enum_domains = []
@option_definitions_by_symbol = {}
@includes = []
@option_declared = false
@agent_declared = false
@namespace_declared = false
@has_common_decision_tree = false
end
def set_subsequent(dpc, type)
raise InternalError.new unless [:option, :behavior, nil].include?(type)
@subsequent_dpc = dpc
@subsequent_type = type
end
end
end

View File

@ -0,0 +1,158 @@
module Translator
#identifers are unique across one class of symbols
#with the exception of states
class Symbol
attr_reader :identifier
attr_reader :scope
attr_accessor :namespace_symbol
attr_accessor :usage_count
def initialize(identifier, scope)
super()
@identifier = identifier
@scope = scope
@usage_count = 0
throw "trying to instantiate an abstract class" if self.class == Symbol
end
def inspect
scope_identifier = ''
scope_identifier = ", @scope=#{@scope.identifier}>" unless @scope.nil?
return "#{self.class.name}<@identifier=#{@identifier}#{scope_identifier}>"
end
#for sorting by identifier
def <=>(symbol)
return self.identifier <=> symbol.identifier
end
end
class DomainValueSymbol < Symbol
attr_reader :domain_symbol
attr_reader :shortcut
def qualified?
return identifier != shortcut
end
def domain_symbol=(symbol)
return if symbol.nil?
return if @domain_symbol == symbol
if @domain_symbol.nil?
@domain_symbol = symbol
@domain_symbol.value_symbols << self
else
$stderr.puts "redeclaration mismatch on #{self.inspect}: old ds #{@domain_symbol.inspect} new ds #{symbol.inspect}"
raise InternalError.new
end
@shortcut = identifier.sub(/^#{Regexp.escape(@domain_symbol.identifier)}\./ , '')
end
end
class NamespaceSymbol < Symbol
attr_reader :namespace_type
#set the type of the namespace, allowed values for type are :symbols or :behaviors
def namespace_type=(type)
return if @namespace_type == type
raise InternalError.new unless @namespace_type.nil?
raise InternalError.new unless [:symbols, :behaviors].include?(type)
@namespace_type = type
end
end
class AgentSymbol < Symbol
end
class StateSymbol < Symbol
end
class DomainSymbol < Symbol
attr_reader :value_symbols
def initialize(identifier, scope)
super
@value_symbols = []
end
end
module EnumTypeSymbol
attr_accessor :enum_domain
end
class ParameterSymbol < DomainValueSymbol
attr_accessor :type
include EnumTypeSymbol
end
class DecimalInputSymbol < DomainSymbol
end
class InputSymbolParameterSymbol < ParameterSymbol
end
class BooleanInputSymbol < DomainSymbol
end
class ConstantSymbol < Symbol
attr_accessor :value
end
class EnumInputSymbol < DomainSymbol
include EnumTypeSymbol
end
class DecimalOutputSymbol < Symbol
attr_accessor :internal
end
class BooleanOutputSymbol < Symbol
attr_accessor :internal
end
class EnumOutputSymbol < Symbol
include EnumTypeSymbol
attr_accessor :internal
end
class EnumSymbol < DomainSymbol
attr_accessor :internal
end
class EnumSymbolValueSymbol < DomainValueSymbol
include EnumTypeSymbol
end
class OptionSymbol < DomainSymbol
end
class OptionParameterSymbol < ParameterSymbol
end
class BasicBehaviorSymbol < DomainSymbol
end
class BasicBehaviorParameterSymbol < ParameterSymbol
end
end

View File

@ -0,0 +1,303 @@
module Translator
class Token
attr_reader :token_type;
attr_reader :line_nr;
def initialize(token_type, token_string, line_nr)
@token_type = token_type
@token_string = token_string
@line_nr = line_nr
end
def raw_string
return @token_string
end
def to_s
#cut away inverted commas und square backets
if token_type == :STRING || token_type == :RANGE
return @token_string[1..-2]
end
return @token_string
end
end
class Tokenizer < CompilerContextWorker
attr_reader :keywords
@@keywords = nil
def Tokenizer.keywords
return @@keywords unless @@keywords.nil?
@@keywords = {}
@@keywords[TOKEN_TRUE] = :TRUE
@@keywords[TOKEN_FALSE] = :FALSE
@@keywords[TOKEN_OPTION] = :OPTION
@@keywords[TOKEN_ACTION] = :ACTION
@@keywords[TOKEN_INITIAL] = :INITIAL
@@keywords[TOKEN_TARGET] = :TARGET
@@keywords[TOKEN_STATE] = :STATE
@@keywords[TOKEN_COMMON] = :COMMON
@@keywords[TOKEN_DECISION] = :DECISION
@@keywords[TOKEN_TTS] = :TTS
@@keywords[TOKEN_IF] = :IF
@@keywords[TOKEN_ELSE] = :ELSE
@@keywords[TOKEN_TOOX] = :TOOX
@@keywords[TOKEN_TOSX] = :TOSX
@@keywords[TOKEN_SORTS] = :SORTS
@@keywords[TOKEN_AGENT] = :AGENT
@@keywords[TOKEN_FUNCTION] = :FUNCTION
@@keywords[TOKEN_ENUM] = :ENUM
@@keywords[TOKEN_INPUT] = :INPUT
@@keywords[TOKEN_OUTPUT] = :OUTPUT
@@keywords[TOKEN_BOOL] = :BOOL
@@keywords[TOKEN_FLOAT] = :FLOAT
@@keywords[TOKEN_CONST] = :CONST
@@keywords[TOKEN_NAMESPACE] = :NAMESPACE
@@keywords[TOKEN_BEHAVIOR] = :BEHAVIOR
@@keywords[TOKEN_INCLUDE] = :INCLUDE
@@keywords[TOKEN_STAY] = :STAY
@@keywords[TOKEN_INTERNAL] = :INTERNAL
@@keywords[TOKEN_CAPACITY] = :CAPACITY
@@keywords[TOKEN_SYNCHRONIZED] = :SYNCHRONIZED
@@keywords[TOKEN_CONFLICT] = :CONFLICT
return @@keywords
end
def initialize(compiler_context)
super
@token_index = 0
@token_counter = 0
end
def rewind
@token_index = 0
end
def next_token
token = @stream[@token_index]
@token_index += 1
return token
end
def dump
@stream.each do |token|
p token.raw_string
end
end
def get_code_line(line_nr)
return @lines[line_nr]
end
def get_code_context(token, size)
line_tokens = Array.new(@stream) #copy token stream
line_tokens.delete_if do |t|
t.line_nr != token.line_nr
end
index = line_tokens.index(token)
regexp = "("
(0..index-1).each do |i|
regexp += Regexp.escape(line_tokens[i].raw_string)
regexp += "\\s*(/\\*.*?\\*/\\s*)*"
end
regexp += ")(#{Regexp.escape(line_tokens[index].raw_string)})("
(index+1..line_tokens.size-1).each do |i|
regexp += "\\s*(/\\*.*?\\*/\\s*)*"
regexp += Regexp.escape(line_tokens[i].raw_string)
end
regexp += ")"
regexp = Regexp.new(regexp)
match = regexp.match(@lines[token.line_nr])
r = ''
m = ''
l = ''
unless match.nil?
l = match[1].to_s
r = match[index+3].to_s
m = match[index+2].to_s
end
#rest size for left and right part
size -= m.size
if(size <= 0)
l = ''
r = ''
else
if size > l.size
size -= l.size
r = r[0..[r.size, size].min - 1]
else
l = l[-size..-1]
r = ''
end
end
return ["#{l}#{m}#{r}","#{' '*l.length}#{'^'*m.length}#{' '*r.length}"]
end
def push(token_type, token_string)
token = Token.new(token_type, token_string, @line_nr)
@token_counter[token_type] += 1
@stream.push token
end
def pop
token = @stream.pop
@token_counter[token.token_type] -= 1
return token
end
def tokenized?
return !@stream.nil?
end
def tokenize( str )
comment_mode = :no_comment
@token_counter = Hash.new(0)
@stream = []
@lines = []
@line_nr = 1
until str.empty? do
#if we are within a comment...
unless comment_mode == :no_comment
case str
when /\A((.|\n|\r)*?)(\*\/)/
case comment_mode
when :doc_comment:
push(:DOC_COMMENT, $1.strip)
when :initial_comment:
push(:INITIAL_COMMENT, $1.strip)
end
str = $'
#count newlines
@line_nr += $1.count("\n")
if @lines[@line_nr].nil?
str =~ /^(.*)$/
@lines[@line_nr] = $1.chomp
end
comment_mode = :no_comment
else
raise ClosingCommentMissingError.new(cc, @line_nr)
end
else
#consume whitespaces between tokens until end-of-line
while str =~ /\A([\s]+|\/\/.*?[\r\n]|[\r\n])/
str = $'
@line_nr += $1.count("\n")
if @lines[@line_nr].nil?
str =~ /^(.*)$/
@lines[@line_nr] = $1.chomp
end
end
#check for keywords
if str =~ /\A[a-zA-Z_][a-zA-Z0-9_\.\-]*/
keyword_symbol = Tokenizer.keywords[$&]
unless keyword_symbol.nil?
token_match = $&
push(keyword_symbol, token_match)
str = $'
next
end
end
case str
when ''
#do nothing
when /\A[0-9]+(\.[0-9]*)?|^[1-9]\.[0-9]*E(\+|-)?[0-9]+/
push(:NUMBER, $&)
str = $'
when /\A[@]?[a-zA-Z_][a-zA-Z0-9_\.]*/
push(:IDENTIFIER, $&)
str = $'
when /\A("[^"]*")/
push(:STRING, $1.to_s)
str = $'
when /\A\/\*\*\*/
str = $'
comment_mode = :initial_comment
when /\A\/\*\*/
str = $'
comment_mode = :doc_comment
when /\A\/\*/
str = $'
comment_mode = :comment
when /\A(\[[^\]]*\])/
push(:RANGE, $1.to_s)
str = $'
when /\A\*\//
raise ClosingCommentError.new(cc, @line_nr)
else
b = str[0,2]
c = str[0,1]
case b
when '<='
push(:LE, b)
str = str[2..-1]
when '>='
push(:GE, b)
str = str[2..-1]
when '=='
push(:EQ, b)
str = str[2..-1]
when '!='
push(:NEQ, b)
str = str[2..-1]
when '&&'
push(:AND, b)
str = str[2..-1]
when '||'
push(:OR, b)
str = str[2..-1]
else
if '%!<>[]{}();|+-*/=,?:'.index(c)
push(c, c)
str = str[1..-1]
else
dump if LOG.debug?
raise TokenizerError.new(cc, @line_nr, str[0..[30, str.length].min])
end
end
end
end
end
#raise ParenthesisError.new(cc, '(', @token_counter['('], ')', @token_counter[')']) unless @token_counter['('] == @token_counter[')']
#raise ParenthesisError.new(cc, '{', @token_counter['{'], '}', @token_counter['}']) unless @token_counter['{'] == @token_counter['}']
#raise UnevenStringDelimiterError.new(cc, '"') unless (@token_counter['"'] % 2) == 0
end
end
end

View File

@ -0,0 +1,10 @@
require "rexml/document"
require "rexml/streamlistener"
require 'constants'
require 'translator_base'
require 'language_elements'
require 'xml_parser'
require 'symbols'
require 'symbol_table'
require 'tokenizer'
require 'errors'

View File

@ -0,0 +1,142 @@
require 'translator'
module Translator
def Translator.stopwatch(message)
LOG.info "#{message}"
start_time = Time.now
yield
elapsed_time = Time.now - start_time
LOG.info "#{message} [#{elapsed_time}s]"
return elapsed_time
end
class Profiler
attr_accessor :count
attr_reader :elapsed_time
def initialize(clazz, modulename, classname , methodname)
@count = 0
@elapsed_time = 0.0
@name = "#{clazz.name}.#{methodname}(...)"
clazz.class_eval "
def #{classname}.profiler
return @profiler
end
def #{classname}.profiler=(pr)
@profiler = pr
end
alias profiled_#{methodname} #{methodname}
def #{methodname}(*args, &block)
start_time = Time.now
result = self.profiled_#{methodname}(*args, &block)
#{classname}.profiler.add(Time.now - start_time)
result
end
"
clazz.profiler = self
end
def add(time)
@elapsed_time += time
@count += 1
end
def log
LOG.info "#{@name} #{@count} times called, #{@elapsed_time}s in total"
end
end
class Out
attr_accessor :indent_string
attr_accessor :verbose
def initialize(out)
@out = out
@indent = 0
@indent_string = " "
@verbose = false
end
#for printing indents
def pindent(delta = 0)
result = ''
@indent += delta if delta < 0
@indent.times {
result << @indent_string
}
@indent += delta if delta > 0
return result
end
def <<(something)
@out << something
return self
end
#suggested line break
#vaporware
def |(something)
self << ENDL << something
end
#print with indent
def %(something)
self << pindent << something
end
#print and increase indent
def >(something)
self << pindent(1) << something
end
#print and decrease indent
def <(something)
self << pindent(-1) << something
end
end
class RecodeOut < Out
def <<(something)
#recode utf8 strings to native charset
@out << something.unpack("U*").pack("C*")
return self
end
end
end
class << File
def relative_path(path, reference_path)
path = File.expand_path(path).sub(/^([A-Za-z]):/, '/cygdrive/\1').split(/[\\\/]+/)
reference_path = File.expand_path(reference_path).sub(/^([A-Za-z]):/, '/cygdrive/\1').split(/[\\\/]+/)
equal_index = 0
while(path[equal_index] == reference_path[equal_index])
equal_index += 1
end
relative_path = []
(reference_path.size - equal_index).times do
relative_path << ".."
end
((equal_index)..(path.size-1)).each do |index|
relative_path << path[index]
end
return File.join(*relative_path)
end
end

View File

@ -0,0 +1,133 @@
module Translator
class Node
attr_accessor :name
attr_reader :children
attr_accessor :type
attr_accessor :relative_name
def initialize
@children = []
@type = nil
end
def get_or_create(child_name)
@children.each do |child|
return child if child.name == child_name
end
new_child = Node.new
new_child.name = child_name
@children << new_child
return new_child
end
def sort!
@children.sort! do |a, b|
result = nil
result = 1 if a.type == :file && b.type == :folder
result = -1 if a.type == :folder && b.type == :file
if a.type == :file && b.type == :file
result = File.basename(a.relative_name).downcase <=> File.basename(b.relative_name).downcase
end
result = a.name.downcase <=> b.name.downcase if a.type == :folder && b.type == :folder
result
end
@children.each do |child|
child.sort!
end
end
def print(out)
case type
when :file
out << "<File RelativePath=\"#{relative_name.gsub(/\//,'\\')}\">\r\n"
out << "</File>\r\n"
when :folder
unless name.nil?
out << "<Filter\r\n"
out << "Name=\"#{name}\"\r\n"
out << "Filter=\"\">\r\n"
end
children.each do |child|
child.print(out)
end
out << "</Filter>\r\n" unless name.nil?
end
end
end
class VCProj
def VCProj.readMiddle(filename,root)
File.open(filename, 'ab')
input = IO.readlines(filename)
input.each do |line|
if (line =~ /RelativePath/)
line = line.gsub('\\','/')
path = line[line.index('/Src/')..line.rindex('l"')]
relative_name = path.sub(/^.*\/Src\//, '../Src/')
folder_names = path.sub(/^.*\/Modules\//, '').split('/')
current = root
while folder_names.size > 0
folder_name = folder_names.shift
current = current.get_or_create(folder_name)
if folder_names.size == 0 #was last
current.type = :file
current.relative_name = relative_name
else
current.type = :folder
end
end
end
end
end
def VCProj.generate_vcproj(filename, ccs)
FileUtils.mkdir_p(File.dirname(filename))
root = Node.new
root.type = :folder
VCProj.readMiddle(filename,root)
ccs.each do |cc|
path = File.expand_path(cc.cu.src_fullname)
if(path =~ /^.*\/Src\// && path =~ /^.*\/Modules\//)
relative_name = path.sub(/^.*\/Src\//, '../Src/')
folder_names = path.sub(/^.*\/Modules\//, '').split('/')
current = root
while folder_names.size > 0
folder_name = folder_names.shift
current = current.get_or_create(folder_name)
if folder_names.size == 0 #was last
current.type = :file
current.relative_name = relative_name
else
current.type = :folder
end
end
end
end
root.sort!
FileUtils.mkdir_p(File.dirname(filename))
File.open(filename, "w") do |file|
root.print(file)
end
end
end
end

View File

@ -0,0 +1,887 @@
#!/usr/bin/ruby
#make the script run from any location and workaround for cygwin ruby and windows style dirs
$LOAD_PATH << File.expand_path(File.dirname(__FILE__))
$LOAD_PATH << File.expand_path(File.dirname(__FILE__)).sub(/^([A-Za-z]):/, '/cygdrive/\1')
require 'logger'
require 'optparse'
require 'translator'
require 'xabsl_parser.tab'
require 'fileutils'
require 'vcproj'
require 'ftools'
module Translator
class XabslCompiler
def initialize
super
@fp_stb = FirstPassSyntaxTreeBuilder.new
@sp_stb = SecondPassSyntaxTreeBuilder.new
@tp_stb = ThirdPassSyntaxTreeBuilder.new
@parser = XabslParser.new
@errors = false
end
def prepare_cc(cc)
cc.pc.option_root = RootLanguageElement.new
cc.pc.option_root.doctype = "<!DOCTYPE #{DTD_INCLUDE_ENTITY} SYSTEM \"../#{DTD_INCLUDE_FILE}\">"
cc.pc.namespace_root = RootLanguageElement.new
cc.pc.option_definitions_temp = RootLanguageElement.new
ac_tag = AgentCollectionTag.new
ac_tag.attr[ATTR_XMLNS] = "http://www.xabsl.de"
ac_tag.attr[ATTR_XMLNS_XSI] = "http://www.w3.org/2001/XMLSchema-instance"
ac_tag.attr[ATTR_XMLNS_XI] = "http://www.w3.org/2003/XInclude"
ac_tag.add_child(TitleTag.new)
ac_tag.add_child(PlatformTag.new)
ac_tag.add_child(SoftwareEnvironmentTag.new)
cc.pc.agent_collection_root = RootLanguageElement.new
cc.pc.agent_collection_root.doctype = "<!DOCTYPE options [" << ENDL << " <!ENTITY #{OPTION_DEFINITIONS_ENTITY} SYSTEM \"#{OPTION_DEFINITIONS_FILE}\">" << ENDL << "]>"
cc.pc.agent_collection_root.add_child(ac_tag)
end
def pass(cc, stb)
begin
LOG.info "#{stb.class} #{cc.cu.src_filename}"
@parser.parse(cc, stb)
rescue InternalError => error
#if there are errors, the internal error is most likely caused by them
unless errors?
$stderr << cc.eh.visual_studio_format(error)
$stderr.print(error.class.name + ENDL)
error.backtrace.each do |trace|
$stderr.print trace
$stderr.print ENDL
end
exit 1
end
rescue CompilerFatal => message
$stderr << cc.eh.visual_studio_format(message)
exit 100
rescue CompilerMessage => message
cc.eh.error message
end
end
def write_xabsl(output_path, cc)
filename = File.join(output_path, cc.cu.dest_fullname)
if File.file?(filename) && File.stat(filename).mtime > cc.cu.src_mtime
return 0
end
#generate XML output
LOG.info "writing #{filename}"
FileUtils.mkdir_p(File.dirname(filename))
File.open(filename, 'wb') do |dest|
root = nil
if cc.pc.option_declared
root = cc.pc.option_root
elsif cc.pc.namespace_declared
root = cc.pc.namespace_root
elsif cc.pc.agent_declared
root = cc.pc.agent_collection_root
else
raise InternalError.new
end
root.to_xml Out.new(dest)
end
return 1
end
def write_intermediate_code(ccs, agent_cc, filename)
FileUtils.mkdir_p(File.dirname(filename))
LOG.info "writing #{filename}"
option_symbols_order = []
#gather option symbols from compilation contexts
#and remember order
ccs.each do |cc|
next unless cc.pc.option_declared
option_symbol = cc.pc.option_root.child(OptionTag).attr[ATTR_NAME]
option_symbols_order << [cc, option_symbol]
end
option_symbols_order.sort! do |a,b|
a[1].identifier.downcase <=> b[1].identifier.downcase
end
File.open(filename, 'wb') do |file|
out = Out.new(file)
title = agent_cc.pc.agent_collection_root.child(AgentCollectionTag).child(TitleTag).string
out << "// Intermediate code for the agents of #{title}" << ENDL
out << ENDL
#process internal symbols
internal_output_symbols = []
internal_enum_symbols = []
agent_cc.st.each do |symbol|
case symbol
when BooleanOutputSymbol, DecimalOutputSymbol, EnumOutputSymbol:
if symbol.internal
internal_output_symbols << symbol
end
when EnumSymbol:
if symbol.internal
internal_enum_symbols << symbol
end
end
end
out << "// number of internal enumerations:" << ENDL if out.verbose
out << "#{internal_enum_symbols.size}" << ENDL
out << "// (enumeration number-of-elements (element)*)+" << ENDL if out.verbose
internal_enum_symbols.sort! do |a,b|
a.identifier.downcase <=> b.identifier.downcase
end
internal_enum_symbols.each do |symbol|
out << "#{symbol.identifier}"
out << " #{symbol.value_symbols.size}"
symbol.value_symbols.each do |symbol|
out << " #{symbol.identifier}"
end
out << ENDL
end
out << "// number of internal output symbols" << ENDL if out.verbose
out << "#{internal_output_symbols.size}" << ENDL
out << "// (d decimal-input-symbol | b boolean-input-symbol | e enum enumerated-input-symbol)+" << ENDL if out.verbose
internal_output_symbols.sort! do |a,b|
a.identifier.downcase <=> b.identifier.downcase
end
internal_output_symbols.each do |symbol|
case symbol
when BooleanOutputSymbol:
out << "b "
when DecimalOutputSymbol:
out << "d "
when EnumOutputSymbol:
out << "e #{symbol.enum_domain.identifier} "
else
raise InternalError.new
end
out << "#{symbol.identifier}"
out << ENDL
end
out << ENDL
#process options
out << '// number of options' << ENDL if out.verbose
out << "#{option_symbols_order.size}" << ENDL
out << '// names, number of parameters, parameters for all options' << ENDL if out.verbose
option_symbols_order.each do |cc, option_symbol|
out << "#{option_symbol.identifier} #{option_symbol.value_symbols.size}"
option_symbol.value_symbols.each do |parameter_symbol|
case parameter_symbol.type
when :decimal:
out << " d"
when :boolean:
out << " b"
when :enum:
out << " e #{parameter_symbol.enum_domain.identifier}"
else
raise InternalError.new
end
out << " #{parameter_symbol.identifier}"
end
out << ENDL
end
out << ENDL
option_symbols_order.each do |cc, option_symbol|
cc.pc.option_root.child(OptionTag).to_ic(out)
end
#process agents
agent_tags = Array.new(agent_cc.pc.agent_collection_root.child(AgentCollectionTag).children)
agent_tags.delete_if do |tag|
tag.class != AgentTag
end
out << "// number of agents:" << ENDL if out.verbose
out << "#{agent_tags.size}" << ENDL
out << "// agents: (name initial-option)+" << ENDL if out.verbose
first = true
agent_tags.each do |tag|
out << " " unless first
out << "#{tag.attr[ATTR_ID].identifier} #{tag.attr[ATTR_ROOT_OPTION].identifier}"
first = false
end
out << ENDL
end
end
def gather_incremental(st, all_ccs)
changed_ccs = []
all_ccs.each do |cc|
unless FileTest.readable?(cc.cu.src_fullname)
LOG.info "file not readable #{cc.cu.src_filename}, switching to non-incremental mode"
throw :non_incremental
end
if cc.cu.src_mtime != File.stat(cc.cu.src_fullname).mtime
changed_ccs << cc
LOG.info "#{cc.cu.src_filename} modified"
end
end
if changed_ccs.empty?
LOG.info "nothing to do -- should proceed to output"
end
#now gather symbols defined in changed_ccs
symbols = []
changed_ccs.each do |cc|
symbols += cc.sc.from_code_declaration_count.keys
end
symbols.uniq!
symbols.each do |symbol|
LOG.info "uses symbol #{symbol.identifier}"
end
#now gather ccs again that use these symbols
all_ccs.each do |cc|
symbols.each do |symbol|
if cc.sc.from_code_usage_count[symbol] > 0
changed_ccs << cc
break
end
end
end
changed_ccs.uniq!
changed_ccs.each do |cc|
cc.sc.from_code_declaration_count.keys.each do |symbol|
symbols << symbol
end
LOG.info "used by #{cc.cu.src_filename}"
if cc.pc.includes.size > 0
LOG.info "includes detected: switching to non-incremental mode"
throw :non_incremental
end
end
symbols.uniq!
symbols.each do |symbol|
LOG.info "undeclaring symbol #{symbol.identifier}"
st.remove symbol
end
#generate new CompilerContexts for files that need recompiling
all_ccs = all_ccs - changed_ccs
ccs = []
changed_ccs.each do |cc|
ccs << CompilerContext.new(cc.cu, st)
cc.cu.update_src_mtime
end
all_ccs += ccs
return [all_ccs, ccs]
end
def errors?
@error_ccs.each do |cc|
return true if cc.errors?
end
return false
end
def translate(hash_value, compilation_units, write)
@error_ccs = []
dump_filename = File.join(write[:inc], "xabsl.#{hash_value}.dump") if write[:inc]
agent_cc = nil
message_count = Hash.new(0)
st = nil
marshalled_dump = nil
options_tag = OptionsTag.new
option_defintions_tag = ODSTag.new
ods_tag = ODSTag.new
ods_tag.attr[ATTR_XMLNS] = "http://www.xabsl.de"
ods_tag.attr[ATTR_XMLNS_XSI] = "http://www.w3.org/2001/XMLSchema-instance"
option_definitions_root = RootLanguageElement.new
option_definitions_root.add_child ods_tag
build_ccs = nil
all_ccs = nil
incremental = false
files_written = 0
if compilation_units.size > 1
$stderr.puts "please give only one filename on command line"
exit(1)
end
main_cu = compilation_units[0]
elapsed_time = Translator.stopwatch("whole compilation run") do
catch :non_incremental do
if write[:inc]
loaded = nil
unless FileTest.exists?(dump_filename)
LOG.info "no dump file: switching to non-incremental mode"
throw :non_incremental
end
idle_run = true
File.open(dump_filename, 'rb') do |file|
precheck_cus = nil
begin
precheck_cus = Marshal.load(file)
rescue EOFError
throw :non_incremental
end
begin
precheck_cus.each do |cu|
#here only input files are checked as (shared) output files can be generated more than once
idle_run = idle_run && (cu.src_mtime == File.stat(cu.src_fullname).mtime)
end
rescue Errno::ENOENT
idle_run = false
end
loaded = Marshal.load(file)
end
#just to be sure
if loaded[0] != hash_value
LOG.info "mismatching hash_value: switching to non-incremental mode"
throw :non_incremental
end
hash_value, st, ccs = loaded
#absolutely nothing changed
if idle_run
LOG.info "ultimate shortcut. none of the input files has changed."
(1..rand(4)+1).each do
$stdout.print "Z"
(2..rand(5)+2).each do
$stdout.print "z"
end
$stdout.print " "
end
$stdout.puts
all_ccs = ccs
build_ccs = []
else
all_ccs, build_ccs = gather_incremental(st, ccs)
end
incremental = true
end
end
#stuff for non-incremental use
unless incremental
# create symbol table
st = SymbolTable.new
#create compiler_contexts
build_ccs = []
all_ccs = []
compilation_units.each do |cu|
build_ccs << CompilerContext.new(cu, st)
end
end
@error_ccs = Array.new(build_ccs + all_ccs).uniq
#prepare and first pass
processed_ccs = {}
included_ccs = {}
double_include = false
while !build_ccs.empty?
cc = build_ccs.shift
processed_ccs[cc.cu.src_fullname] = cc
prepare_cc(cc)
next if cc.errors?
pass(cc, @fp_stb)
#keep in mind: if there are includes in the file, incremental build is disabled
processed_filenames = {}
cc.pc.includes.each do |filename|
src_fullname = File.join(File.dirname(cc.cu.src_fullname), filename)
dest_fullname = File.join(File.dirname(cc.cu.dest_fullname), filename)
matched = 0
cc.pc.includes.each do |filename2|
if filename == filename2
matched += 1
end
if matched > 1 && processed_filenames[filename].nil?
processed_filenames[filename] = filename2
cc.eh.error DoubleIncludeError.new(cc, src_fullname)
break
end
end
unless File.basename(src_fullname) =~ /^(.*)\.[xy]absl$/
cc.eh.error FileTypeError.new(cc, src_fullname)
next
end
if processed_ccs[src_fullname].nil? && included_ccs[src_fullname].nil?
if FileTest.file?(src_fullname)
cu_new = CompilationUnit.new
cu_new.set_src(File.dirname(src_fullname), File.basename(src_fullname))
# set default destination, for any file containing valid information this will be overwritten by SyntaxTreeBuilder
cu_new.set_dest(".")
cc_new = CompilerContext.new(cu_new, st)
included_ccs[src_fullname] = cc_new
build_ccs << cc_new
@error_ccs = Array.new(build_ccs + all_ccs).uniq
else
cc.eh.error FileOpenError.new(cc, src_fullname)
end
end
end
end
build_ccs = processed_ccs.values
all_ccs = (all_ccs + build_ccs).uniq
@error_ccs = Array.new(build_ccs + all_ccs).uniq
#dump .vcproj on command
if write[:vcproj]
VCProj.generate_vcproj(write[:vcproj], all_ccs)
files_written+=1
end
#second pass
build_ccs.each do |cc|
#unless cc.errors?
if (not cc.errors?) || write[:force]
pass(cc, @sp_stb)
end
end
#third pass
build_ccs.each do |cc|
#unless cc.errors?
if (not cc.errors?) || write[:force]
pass(cc, @tp_stb)
end
end
#generate messages for unused symbols
st.each do |symbol|
unless (symbol.class <= AgentSymbol || symbol.class <= NamespaceSymbol)
if (symbol.usage_count <= 1)
message = "#{symbol.class.name} '#{symbol.identifier}' "
message += "in #{symbol.domain_symbol.class.name} '#{symbol.domain_symbol.identifier}' " if symbol.class <= DomainValueSymbol
message += "(#{symbol.namespace_symbol.identifier}) " if symbol.namespace_symbol.class <= NamespaceSymbol
message += "is defined but never used"
LOG.info message
end
end
end
#postprocessing
build_ccs.each do |cc|
unless errors?
#postprocessing: generate entities for each fresh compiled option
if cc.pc.option_declared
cc.pc.option_root.child(OptionTag).entities += cc.sc.used_namespace_symbols
end
end
#misc: count errors and warnings
cc.eh.messages.each do |message|
message_count[CompilerError] +=1 if message.class <= CompilerError
message_count[CompilerWarning] +=1 if message.class <= CompilerWarning
end
end
#print and count errors from symbol table
st.errors.each do |message|
if write[:vs]
$stderr.puts cc.eh.visual_studio_format(message)
else
$stderr.puts cc.eh.format(message)
end
message_count[CompilerError] +=1 if message.class <= CompilerError
message_count[CompilerWarning] +=1 if message.class <= CompilerWarning
end
# marshal everything if there were no errors
# the trick to do this *here* is: we are going to modify the syntax trees below for output generation
# but we want unmodified trees for incremental compiling
if write[:inc] && message_count[CompilerError] == 0
marshalled_dump = Marshal.dump([hash_value, st, all_ccs])
end
#prepare options tag for agents tag, find agents_cc
file_entities = {}
unless errors?
all_ccs.each do |cc|
next if cc.errors?
root = nil
root_counter = 0
if cc.pc.option_declared
root_counter += 1
root = cc.pc.option_root
#add xincludes to options files
xinclude_tag = XIncludeTag.new
xinclude_tag.attr[ATTR_HREF] = File.relative_path(cc.cu.dest_fullname, main_cu.dest_dir)
options_tag.add_child(xinclude_tag)
raise InternalError.new if cc.pc.option_definitions_temp.children.size != 1
odTag = cc.pc.option_definitions_temp.child(ODTag)
cc.pc.option_definitions_temp.remove_child odTag
ods_tag.add_child(odTag)
option_symbol = cc.pc.option_root.child(OptionTag).attr[ATTR_NAME]
file_entities[option_symbol] = File.relative_path(cc.cu.dest_fullname, main_cu.dest_dir)
end
if cc.pc.namespace_declared
root_counter += 1
root = cc.pc.namespace_root
#get symbols oder basic-behaviors tag and the id of this tag
symbol = root.children[0].attr[ATTR_ID]
file_entities[symbol] = File.relative_path(cc.cu.dest_fullname, main_cu.dest_dir)
end
if cc.pc.agent_declared
root_counter += 1
root = cc.pc.agent_collection_root
#identified agent cc
raise InternalError.new('multiple agent files encountered. i cannot handle this.') unless agent_cc.nil?
agent_cc = cc
ac_tag = cc.pc.agent_collection_root.child(AgentCollectionTag)
ac_tag.child(TitleTag).string = ac_tag.title
ac_tag.child(PlatformTag).string = ac_tag.platform
ac_tag.child(SoftwareEnvironmentTag).string = ac_tag.software_environment
ac_tag.add_child(options_tag)
end
#check that other roots are really empty and the roots contain exactly 1 le
raise InternalError.new if root_counter != 1
raise InternalError.new if root.children.size != 1
end
raise InternalError.new('agent file is not on command line.') if agent_cc.nil?
#ab hier ist agents_cc != nil
#main__cu sollte das gleiche sein
end
all_ccs.each do |cc|
#print errors and warnings
cc.eh.messages.each_index do |index|
#break if index >= 1
message = cc.eh.messages[index]
if write[:vs]
$stderr.puts cc.eh.visual_studio_format(message)
else
$stderr.puts cc.eh.format(message)
end
end
end
if write[:xabsl]
all_ccs.each do |cc|
#generate a relative filename
dtd_relative_filename = File.relative_path(DTD_INCLUDE_FILE, cc.cu.dest_dir)
#set doctype for options (we don't care whether it's actually an option file)
cc.pc.option_root.doctype = "<!DOCTYPE #{DTD_INCLUDE_ENTITY} SYSTEM \"#{dtd_relative_filename}\">"
#only produce output if there were no errors
if (write[:force] ||(!agent_cc.nil? && message_count[CompilerError] == 0))
if cc == agent_cc
#sort agent option by filename
options_tag.children.sort! do |a,b|
a.attr[ATTR_HREF] =~ /^(.*)\.xml$/
x = $1.to_s
b.attr[ATTR_HREF] =~ /^(.*)\.xml$/
x <=> $1.to_s
end
end
files_written += write_xabsl(write[:xabsl], cc)
end
end
end
if message_count[CompilerError] == 0
if write[:xabsl]
#generate option-defintions-file
option_definitions_root.child(ODSTag).children.sort! do |a,b|
a.attr[ATTR_NAME] <=> b.attr[ATTR_NAME]
end
filename = File.join(write[:xabsl], OPTION_DEFINITIONS_FILE)
FileUtils.mkdir_p(File.dirname(filename))
LOG.info "writing #{filename}"
File.open(filename+".new", 'wb') do |dest|
option_definitions_root.to_xml Out.new(dest)
end
if File.file?(filename) && File.cmp(filename+".new",filename)
File.delete(filename+".new")
else
File.delete(filename) if File.file?(filename)
File.rename(filename+".new",filename)
files_written+=1
end
#generate dtd-file
file_entities[OPTION_DEFINITIONS_ENTITY] = OPTION_DEFINITIONS_FILE
filename = File.join(write[:xabsl], DTD_INCLUDE_FILE)
FileUtils.mkdir_p(File.dirname(filename))
LOG.info "writing #{filename}"
File.open(filename+".new", 'wb') do |dest|
DTDEntityWriter.new.write(file_entities, dest)
end
if File.file?(filename) && File.cmp(filename+".new",filename)
File.delete(filename+".new")
else
File.delete(filename) if File.file?(filename)
File.rename(filename+".new",filename)
files_written+=1
end
end
if write[:ic]
raise InternalError.new if agent_cc.nil?
write_intermediate_code(all_ccs, agent_cc, write[:ic]) if write[:ic]
files_written+=1
end
if write[:api]
filename = write[:api]
keywords = []
if FileTest.exists?(filename)
File.open(filename, 'rb') do |file|
file.each do |line|
keywords << line.chomp unless line =~ /^\s*$/ #keine leerzeilen
end
end
end
st.each do |symbol|
next if [AgentSymbol, NamespaceSymbol].include?(symbol.class)
if [DecimalInputSymbol, BooleanInputSymbol, EnumInputSymbol, OptionSymbol, BasicBehaviorSymbol].include?(symbol.class)
keyword = "#{SymbolContext.to_code(symbol, false)}("
first = true
symbol.value_symbols.each do |value_symbol|
keyword += ", " unless first
keyword += "#{SymbolContext.to_code(value_symbol, false)} = "
first = false
end
keyword += ")"
keywords << keyword
else
keywords << SymbolContext.to_code(symbol, false)
end
end
Tokenizer.keywords.each do |key, value|
keywords << key
end
keywords.uniq!
keywords.sort! do |x,y|
x.downcase <=> y.downcase
end
LOG.info "writing #{filename}"
FileUtils.mkdir_p(File.dirname(filename))
File.open(filename, 'wb') do |file|
keywords.each do |keyword|
file.puts keyword
end
end
files_written+=1
end
#dump updated cus here
if write[:inc]
FileUtils.mkdir_p(File.dirname(dump_filename))
File.open(dump_filename, 'wb') do |file|
dump_cus = []
all_ccs.each do |cc|
dump_cus << cc.cu
end
file.write Marshal.dump(dump_cus)
file.write marshalled_dump
end
end
end
end
$stdout.puts "#{build_ccs.size} compiled, #{files_written} written, #{message_count[CompilerError]} error(s), #{message_count[CompilerWarning]} warning(s), elapsed time #{elapsed_time}s"
$stdout.puts
end
end
##################################################
#profiler = Translator::Profiler.new(Translator::SymbolContext, "Translator", "SymbolContext", "from_code")
LOG = Logger.new(STDOUT)
LOG.datetime_format = ""
LOG.level = Logger::WARN
help = false
output_path = nil
write = Hash.new(false)
opts = OptionParser.new do |opts|
opts.banner = "XABSL compiler" << ENDL << ENDL
opts.banner += "usage: #{opts.program_name} [options] file(s)"
opts.separator ""
opts.separator "options:"
opts.on("-q", "--quiet", "suppresses almost any output") do
LOG.level = Logger::FATAL
end
opts.on("-v", "--verbose", "run verbosely") do
case LOG.level
when Logger::INFO
LOG.level = Logger::DEBUG
when Logger::WARN
LOG.level = Logger::INFO
else
LOG.level = Logger::WARN
end
end
opts.on("-x", "--xml path", "generate xml at <path>") do |path|
write[:xabsl] = File.expand_path(path)
end
opts.on("-i", "--intermediate-code filename", "generate intermediate code") do |filename|
write[:ic] = filename
end
opts.on("-a", "--api-file filename", "create .api file and copy it to scite/VisualStudio locations") do |filename|
write[:api] = filename
end
opts.on("-m", "--vcproj filename", "create .vcproj middle file") do |filename|
write[:vcproj] = filename
end
opts.on("-I", "--incremental directory", "incremental compiling, put dumpfiles to given directory") do |directory|
write[:inc] = directory
end
opts.on("-C", "--comments", "insert additional comments into generated files") do
write[:comments] = true
end
opts.on("-V", "--vs-error-message-style", "produce visual studio compliant error messages") do
write[:vs] = true
end
opts.on("-f", "--force-output", "will force output even if errors occured (useful when working with single files") do
write[:force] = true
LOG.warn "using option 'force output' - please notice that some displayed errors may be important some not"
end
opts.on_tail("-h", "--help", "show this message") do
help = true
end
end
#print help if requested or no filenames are supplied
filenames = opts.parse!
if help || filenames.empty?
puts opts
exit
end
#check file existence and readablity
errors = false
compilation_units = []
filenames.each do |src_filename|
unless src_filename =~ /^(.*)\.[xy]absl$/
LOG.error "file '#{src_filename}' doesn't have extension .xabsl"
errors = true
next
end
dest_filename = "#{$1.to_s}.xml"
unless FileTest.file?(src_filename) && FileTest.readable?(src_filename)
LOG.error "unable to read from file '#{src_filename}'"
errors = true
next
end
cu = Translator::CompilationUnit.new
cu.set_src(File.dirname(src_filename), File.basename(src_filename))
cu.set_dest(".")
compilation_units << cu
end
exit 1 if errors
#hmmm put this elsewhere
unless write.empty?
timestamp_mtime = File.stat(TIMESTAMP_FILE).mtime
Dir.foreach('.') do |entry|
if entry =~ /xabsl\.[0-9A-Fa-f]+\.dump/ && FileTest.file?(entry) && File.stat(entry).mtime <= timestamp_mtime
LOG.info "removing #{entry} because compiler timestamp is newer"
FileUtils.rm(entry)
end
end
hash_value = "%8.8X" % [filenames.join.hash]
translator = Translator::XabslCompiler.new
translator.translate(hash_value, compilation_units, write)
end
#profiler.log
LOG.close
exit 1 if translator.errors?
end

View File

@ -0,0 +1,604 @@
class Translator::XabslParser
prechigh
nonassoc UMINUS '!'
left '*' '/' '%'
left '+' '-'
nonassoc '<' '>' LE GE EQ NEQ
left AND
left OR
nonassoc '?' ':'
preclow
token
LE
GE
EQ
NEQ
AND
OR
ACTION
NUMBER
TRUE
FALSE
STRING
RANGE
INTERNAL
IDENTIFIER
DOC_COMMENT
INITIAL_COMMENT
OPTION
STATE
COMMON
DECISION
TTS
STAY
DT
CDT
UMINUS
IF
ELSE
TOOX
TOSX
SORTS
INITIAL
TARGET
AGENT
FUNCTION
ENUM
INPUT
OUTPUT
BOOL
FLOAT
CONST
NAMESPACE
BEHAVIOR
INCLUDE
SYNCHRONIZED
CAPACITY
CONFLICT
'{' '}'
'(' ')'
'|' ',' ';'
'+' '-'
'*' '/'
'<' '<=' '>' '>=' '==' '!'
':' '?'
rule
xtc:
__initial_comment
__top_level
{@stb.comments(val)}
;
__initial_comment:
INITIAL_COMMENT
|
;
__top_level:
include
__top_level
|
option
|
agents
|
namespace
|
;
agents:
agent
agents
|
agent
;
include:
INCLUDE STRING ';'
{return @stb.include(val)}
;
namespace:
__doc_comment
NAMESPACE IDENTIFIER '(' STRING ')' '{'
{@stb.namespace_early(_values)}
__inner_namespace
'}'
{return @stb.namespace(val)}
;
__inner_namespace:
__inner_namespace
const
{ return val[0] + [val[1]] }
|
__inner_namespace
symbol_declaration
{ return val[0] + [val[1]] }
|
__inner_namespace
enum_symbol_declaration
{ return val[0] + [val[1]] }
|
__inner_namespace
behavior_declaration
{ return val[0] + [val[1]] }
|
{ return [] }
;
behavior_declaration:
__doc_comment
BEHAVIOR IDENTIFIER '{'
{@stb.behavior_declaration_early(_values)}
__parameter_declarations
'}'
{ return @stb.behavior_declaration(val) }
;
symbol_declaration:
__doc_comment
bool_or_float_or_enum __input_output_internal IDENTIFIER __range __measure
{@stb.symbol_declaration_early(_values)}
symbol_parameter_declarations
';'
{return @stb.symbol_declaration(val)}
;
__input_output_internal:
INPUT
|
OUTPUT
|
INTERNAL
|
;
enum_symbol_declaration:
__doc_comment
bool_or_float_or_enum __input_output_internal
'{'
enum_elements
'}'
';'
{ return @stb.enum_symbol_declaration(val) }
;
enum_elements:
IDENTIFIER
__enum_elements
{ return [val[0]] + val[1] }
;
__enum_elements:
__enum_elements
',' IDENTIFIER
{ return val[0] + [val[2]] }
|
{ return [] }
;
__minus:
'-'
|
;
bool_or_float_or_enum:
BOOL
|
FLOAT
|
ENUM IDENTIFIER
{
return val[1]
}
|
;
const:
__doc_comment
__float CONST IDENTIFIER '=' __minus NUMBER __measure ';'
{return @stb.const(val)}
;
__float:
FLOAT
|
;
agent:
__doc_comment
AGENT IDENTIFIER '(' STRING ',' IDENTIFIER ')' ';'
{return @stb.agent(val)}
;
option:
__doc_comment
OPTION IDENTIFIER '{'
{@stb.option_early(_values)}
__parameter_declarations
__common_declarations
state_declarations
'}'
{return @stb.option(val)}
;
symbol_parameter_declarations:
'('
__parameter_declarations
')'
{ return val[1] }
|
;
__parameter_declarations:
__parameter_declarations
parameter_declaration
{ return [] + val[0] + [val[1]] }
|
{ return [] };
parameter_declaration:
__doc_comment
bool_or_float_or_enum IDENTIFIER __range __measure ';'
{return @stb.parameter_declaration(val)}
;
__range:
RANGE
|
;
__measure:
STRING
|
;
state_declarations:
state_declaration
__state_declarations
{ return [val[0]] + val[1] }
;
__state_declarations:
__state_declarations
state_declaration
{ return [] + val[0] + [val[1]] }
|
{ return [] };
state_declaration:
__initial __target STATE IDENTIFIER cooperative '{'
{@stb.state_declaration_early(_values)}
decision_tree
ACTION '{'
__output_symbol_assignments_or_subsequent_declarations
'}'
'}'
{ return @stb.state_declaration(val) };
cooperative:
CAPACITY NUMBER
{ return [val[0], val[1]] }
|
SYNCHRONIZED NUMBER
{ return [val[0], val[1]] }
|
SYNCHRONIZED
{ return [val[0]] }
|;
__output_symbol_assignments_or_subsequent_declarations:
__output_symbol_assignments_or_subsequent_declarations
output_symbol_assignment
{ return val[0] + [val[1]] }
|
__output_symbol_assignments_or_subsequent_declarations
subsequent_declaration
{ return val[0] + [val[1]] }
|
{ return [] };
output_symbol_assignment:
IDENTIFIER
{@stb.output_symbol_assignment_early(_values)}
'=' exp ';'
{ return @stb.output_symbol_assignment(val) };
#handled in state_declaration
__doc_comment:
DOC_COMMENT
|;
#handled in state_declaration
__initial:
INITIAL
|;
#handled in state_declaration
__target:
TARGET
|;
subsequent_declaration:
IDENTIFIER __option_or_behavior '('
{@stb.subsequent_declaration_early(_values)}
__set_parameter_list ')' ';'
{return @stb.subsequent_declaration(val)};
__option_or_behavior:
OPTION
|
BEHAVIOR
|
;
__set_parameter_list:
set_parameter __set_parameter_list_end
{return [val[0]] + val[1]}
|
{return []}
;
__set_parameter_list_end:
',' __set_parameter_list
{return val[1]}
|
{return []}
;
set_parameter:
IDENTIFIER
{@stb.set_parameter_early(_values)}
'=' exp
{return @stb.set_parameter(val)}
;
__with_parameter_list:
with_parameter __with_parameter_list_end
{return [val[0]] + val[1]}
|
{return []}
;
__with_parameter_list_end:
',' __with_parameter_list
{return val[1]}
|
{return []}
;
with_parameter:
IDENTIFIER
{@stb.with_parameter_early(_values)}
'=' exp
{return @stb.with_parameter(val)}
;
exp:
'!' exp
{return @stb.exp_unary(val)}
|
exp '+' {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp '-' {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp '*' {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp '/' {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp '%' {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp NEQ {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp EQ {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp '<' {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp LE {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp '>' {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp GE {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp AND {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp OR {@stb.exp_binary_early(_values)} exp
{return @stb.exp_binary(val)}
|
exp '?' exp ':' exp
{return @stb.conditional_expression(val)}
|
'(' exp ')'
{return val[1]}
|
'-' exp = UMINUS
{return @stb.exp_unary(val)}
|
NUMBER
{return @stb.exp_number(val)}
|
TRUE
{return @stb.exp_boolean(val)}
|
FALSE
{return @stb.exp_boolean(val)}
|
function
|
IDENTIFIER
{return @stb.exp_identifier(val)}
|
TOSX
{return TOSXTag.new}
|
TOOX
{return TOOXTag.new}
|
SORTS
{return SORTSTag.new}
|
CONFLICT
{return ConflictTag.new}
;
function:
IDENTIFIER
{@stb.function_early(_values)}
'(' __with_parameter_list ')'
{return @stb.function(val)}
;
__common_declarations:
COMMON DECISION
__common_decision_tree
COMMON ACTION
__common_action
{return [val[2], val[5]]}
|
COMMON DECISION
__common_decision_tree
{return [val[2]]}
|
COMMON ACTION
__common_action
{return [val[2]]}
|;
__common_action:
'{'
__output_symbol_assignments_or_subsequent_declarations
'}'
{return @stb.common_action(val)}
|;
#CDT stuff
__common_decision_tree:
'{' cdtree '}'
{return @stb.common_decision_tree(val)}
|;
#rule with IF and optional ELSEIF
cdtree:
'{'
cdtree
'}'
{return val[1]}
|
__doc_comment
IF '(' exp ')' dtree
__cdtree_elseif_decisions
{return @stb.cdtree(val)};
__cdtree_elseif_decisions:
__doc_comment
ELSE cdtree
{return @stb.cdtree_elseif_decision(val)}
|
{return nil};
#DT stuff
decision_tree:
DECISION '{' dtree '}'
{return @stb.decision_tree(val)}
|
DECISION '{' __doc_comment ELSE dtree '}'
{return @stb.decision_tree(val)}
|
{return @stb.decision_tree(val)}
;
#rule with transition or (IF and ELSE)
dtree:
'{'
dtree
'}'
{return val[1]}
|
transition
{return [val[0]]}
|
__doc_comment
IF '(' exp ')' dtree
__doc_comment
ELSE dtree
{return @stb.dtree(val)}
;
transition:
TTS IDENTIFIER ';'
{return @stb.transition(val)}
|
STAY ';'
{return @stb.transition(val)}
;
end
---- header
require 'translator'
require 'syntax_tree_builder'
---- inner
def initialize
super
end
#start the parsing, use stb as SyntaxTreeBuilder, tokenize and rewind on demand
def parse(cc, stb)
@cc = cc
@stb = stb
@stb.compiler_context = cc
if @cc.tz.tokenized?
@cc.tz.rewind
else
File.open(cc.cu.src_fullname, 'rb') do |src|
@cc.tz.tokenize(src.read)
end
end
do_parse
@cc = nil
@stb.compiler_context = nil
@stb = nil
end
#return a token in the format the parser understands
def next_token
token = @cc.tz.next_token
return nil if token.nil?
return [token.token_type, token]
end
def on_error(error_token_id, error_value, value_stack)
if error_value == '$'
raise UnexpectedEndOfFile.new(@cc)
else
error = SyntaxError.new(@cc)
error.token = error_value if error_value.class <= Token
raise error
end
end
---- footer

View File

@ -0,0 +1,179 @@
module Translator
# parser callback with a stack of open tags.
class StackParserCallback
include REXML::StreamListener
attr_reader :le_classes_by_tag
attr_reader :root
attr_reader :symbol_table
def initialize
super
@stack = nil
@root = nil
@symbol_table = nil
@le_classes_by_tags = {}
end
# sets root, symbol_tables and clears parser stack.
def prepare(root, symbol_table)
@root = root
@symbol_table = symbol_table
@stack = [@root]
end
# registers an expected language element class for xml parsing.
def add_le_class le_class
@le_classes_by_tags[le_class.tag] = le_class
end
# when a new tag starts: creates a new language elmement with attributes and pushes it onto the stack
def tag_start(name, attributes)
@current = @stack.last
le_class = @le_classes_by_tags[name]
if le_class.nil?
le = UnknownLanguageElement.new(name)
else
le = le_class.new
end
@stack.push le
#then put it into the tree
@current.add_child(le)
#and after that import attributes
le.import(attributes, @symbol_table)
end
# when tag ends: pops of a language element from the stack
def tag_end(name)
@current = @stack.pop
end
# when text is encountered: send text to language element.
# used for platform, software environment, title tags
def text(text)
@stack.last.text = text unless @current.nil? || text =~ /\A\s*\z/
end
# REXML::StreamListener provided a function stub with only 2 parameters which caused an error
def entitydecl a,b,c
end
end
# this parser callback cares for XML entities found and is used for agents.xml.
class AgentCollectionParserCallback < StackParserCallback
attr_reader :entities
def prepare(root, symbol_table)
super
@entities = {}
end
def entitydecl(a, b, c)
@entities[a] = c
end
#hack for REXML. in some versions entitydecl is delivered as notationdecl
def notationdecl(n)
entitydecl(*n)
end
end
# parser callback implementation for parsing option-definitions files
# creates an mapping between ODTags and OptionSymbols
class OptionDefinitonsParserCallback < StackParserCallback
attr_reader :option_definitions_by_symbol
def initialize
super
@option_definitions_by_symbol = {}
end
def tag_start(name, attributes)
super
last = @stack.last
if (last.class <= ODTag)
@option_definitions_by_symbol[last.attr[ATTR_NAME]] = last
end
end
end
# small parser for dtd files.
class DTDEntityScanner
def scan(src)
filename_by_entity = {}
entity_by_filename = {}
entity_order = []
src.each do |line|
if line =~ /<!ENTITY\s+([A-Za-z0-9_.\-]*)\s+SYSTEM\s+"([^"]*)">/
filename = $2.to_s
entity = $1.to_s
filename_by_entity[entity] = filename
entity_by_filename[filename] = entity
entity_order << entity
end
end
return [filename_by_entity , entity_by_filename, entity_order]
end
end
# the counterpart to the dtd scanner.
class DTDEntityWriter
def initialize
super
end
def write(entities, dest)
dest.puts "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>"
symbols = []
behaviors = []
strings = []
keys = entities.keys
keys.each do |key|
symbols << key if key.class <= NamespaceSymbol && key.namespace_type == :symbols
behaviors << key if key.class <= NamespaceSymbol && key.namespace_type == :behaviors
strings << key if key.class <= String
end
symbols.sort! do |a,b|
a.identifier.downcase <=> b.identifier.downcase
end
behaviors.sort! do |a,b|
a.identifier.downcase <=> b.identifier.downcase
end
strings.sort! do |a,b|
a.downcase <=> b.downcase
end
symbols.each do |key|
write_single(dest, key.identifier, entities[key])
end
behaviors.each do |key|
write_single(dest, key.identifier, entities[key])
end
strings.each do |key|
write_single(dest, key, entities[key])
end
end
def write_single(dest, a , b)
dest.puts "<!ENTITY #{a} SYSTEM \"#{b}\">"
end
end
end

View File

@ -0,0 +1,153 @@
body {
font-family: sans-serif;
font-size: 10pt;
margin-top: 0pt;
}
td {
font-family: sans-serif;
font-size: 10pt;
vertical-align: top;
}
a:link {
text-decoration: none;
font-weight: bold;
color: #005A9C;
}
a:visited {
text-decoration: none;
font-weight: bold;
color: #005A9C;
}
a:hover {
text-decoration: underline;
font-weight: bold;
color: #005A9C;
}
h1 {
width: 100%;
padding-top:10pt;
font-size: 20pt;
font-weight: bold;
border-top: 1px none #FFFFFF;
border-right: 1px none #FFFFFF;
border-bottom: 2px solid #005A9C;
border-left: 1px none #FFFFFF;
color: #005A9C;
}
h2 {
width: 100%;
font-size: 15pt ;
font-weight: bold;
border-top: 1px none #FFFFFF;
border-right: 1px none #FFFFFF;
border-bottom: 1px solid #005A9C;
border-left: 1px none #FFFFFF;
color: #005A9C;
}
h3 {
padding-bottom:0pt;
font-size: 15pt;
font-weight: normal;
border-top: 1px none #FFFFFF;
border-right: 1px none #FFFFFF;
border-bottom: 1px none #005A9C;
border-left: 1px none #FFFFFF;
color: #005A9C;
}
.frameline {
background-color: #CCCCCC;
}
.bold { font-weight: bold; }
.italic { font-style: italic; }
.code {
font-family: "Courier New", Courier, mono;
font-size: 10pt;
color: #000000;
font-weight: bold;
background-color: #FFFFCC;
}
.tablehead{
font-size: 10pt;
font-weight: normal;
color: #005A9C;
border-bottom: 1px dotted #A0A0A0;
}
.menu-title{
font-size: 10pt;
font-weight: bold;
}
.menu-item{
font-size: 7pt;
font-weight: normal;
}
.menu-cell{
padding-right: 3pt;
border-right: 1px dotted #BBBBFF;
}
.main-area{
padding-left: 10pt;
}
.pseudo-code-frame{
background-color:#F4F4F4;
border-width:1;
border-style:solid;
border-color:#A0A0A0;
width:100%;
}
.common-pseudo-code-frame{
background-color:#FFFFFF;
border-width:1;
border-style:dashed;
border-color:#A0A0A0;
width:100%;
}
.pseudo-code-cell{
padding-top:1;
padding-bottom:1;
padding-right:0;
padding-left:0;
font-family:monospace;
}
.nowrap{
white-space:nowrap;
}
.pseudo-code-right-bracket{
padding-top:1;
padding-bottom:1;
padding-right:0;
padding-left:0;
vertical-align:bottom;
font-family:monospace;
}
.pseudo-code-left-bracket{
padding-top:1;
padding-bottom:1;
padding-right:0;
padding-left:0;
vertical-align:top;
font-family:monospace;
}
.xabsl-2-logo-big {
padding-top:10;
padding-bottom:0;
padding-right:15;
font-family:sans-serif;
font-weight:bold;
font-size:35pt;
color:#000000;
text-align:left;
white-space:nowrap;
background-color:#FFFFFF;
}
.xabsl-2-logo-small {
padding-top:0;
padding-bottom:0;
font-family:sans-serif;
font-weight:bold;
font-size:12pt;
color:#000000;
text-align:left;
white-space:nowrap;
background-color:#FFFFFF;
}

View File

@ -0,0 +1,185 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:output method="text"/>
<xsl:key name="basic-behaviors" match="xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:basic-behaviors/xabsl:basic-behavior" use="@name"/>
<xsl:key name="output-symbols" match="xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols/xabsl:decimal-output-symbol | xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols/xabsl:boolean-output-symbol | xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols/xabsl:enumerated-output-symbol" use="@name"/>
<xsl:key name="input-symbols" match="xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols/xabsl:decimal-input-symbol | xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols/xabsl:boolean-input-symbol | xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols/xabsl:enumerated-input-symbol" use="@name"/>
<xsl:key name="enumerations" match="xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols/xabsl:enumeration" use="@name"/>
<xsl:variable name="space">
<xsl:text> </xsl:text>
</xsl:variable>
<xsl:variable name="line-break">
<xsl:text>
</xsl:text>
</xsl:variable>
<xsl:template match="xabsl:agent-collection">
<xsl:text>// Debug Symbols for the agents of </xsl:text>
<xsl:value-of select="xabsl:title"/>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// number of enumerations</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="count(xabsl:options/xabsl:option/xabsl:symbols/xabsl:*[local-name()='enumeration'][count(key('enumerations',@name)[1] | .)=1])"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// enumerations</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:text>// (name number-of-elements (element)*)+</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:apply-templates select="xabsl:options/xabsl:option/xabsl:symbols/xabsl:enumeration"/>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// number of input symbols</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="count(xabsl:options/xabsl:option/xabsl:symbols/xabsl:*[local-name()='decimal-input-symbol' or local-name()='boolean-input-symbol' or local-name()='enumerated-input-symbol'][count(key('input-symbols',@name)[1] | .)=1])"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// input symbols</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:text>// (d decimal-input-symbol | b boolean-input-symbol | e enum-name enumerated-input-symbol)+</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:apply-templates select="xabsl:options/xabsl:option/xabsl:symbols/xabsl:decimal-input-symbol | xabsl:options/xabsl:option/xabsl:symbols/xabsl:boolean-input-symbol | xabsl:options/xabsl:option/xabsl:symbols/xabsl:enumerated-input-symbol"/>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// number of output symbols</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="count(xabsl:options/xabsl:option/xabsl:symbols/xabsl:*[local-name()='decimal-output-symbol' or local-name()='boolean-output-symbol' or local-name()='enumerated-output-symbol'][count(key('output-symbols',@name)[1] | .)=1])"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// output symbols</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:text>// (d decimal-output-symbol | b boolean-output-symbol | e enum-name enumerated-output-symbol)+</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:apply-templates select="xabsl:options/xabsl:option/xabsl:symbols/xabsl:decimal-output-symbol | xabsl:options/xabsl:option/xabsl:symbols/xabsl:boolean-output-symbol | xabsl:options/xabsl:option/xabsl:symbols/xabsl:enumerated-output-symbol"/>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// number of options</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="count(xabsl:options/xabsl:option)"/>
<xsl:value-of select="$line-break"/>
<xsl:text>//options: (name num-of-parameters (d decimal-parameter | b boolean_parameter | e enum-name enumerated-parameter)*)+</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:apply-templates select="xabsl:options/xabsl:option"/>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="$line-break"/>
<xsl:text>// number of basic behaviors</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="count(xabsl:options/xabsl:option/xabsl:basic-behaviors/xabsl:basic-behavior[count(key('basic-behaviors',@name)[1] | .)=1])"/>
<xsl:value-of select="$line-break"/>
<xsl:text>//basic behaviors: (name num-of-parameters (d decimal-parameter | b boolean_parameter | e enum-name enumerated-parameter)*)+</xsl:text>
<xsl:value-of select="$line-break"/>
<xsl:apply-templates select="xabsl:options/xabsl:option/xabsl:basic-behaviors/xabsl:basic-behavior"/>
<xsl:value-of select="$line-break"/>
<xsl:value-of select="$line-break"/>
</xsl:template>
<xsl:template match="xabsl:option">
<xsl:variable name="name" select="@name"/>
<xsl:value-of select="$name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="count(xabsl:option-definitions/xabsl:option-definition[@name=$name]/xabsl:*[local-name()='decimal-parameter' or local-name()='boolean-parameter' or local-name()='enumerated-parameter'])"/>
<xsl:value-of select="$space"/>
<xsl:apply-templates select="xabsl:option-definitions/xabsl:option-definition[@name=$name]/xabsl:*[local-name()='decimal-parameter' or local-name()='boolean-parameter' or local-name()='enumerated-parameter']"/>
<xsl:value-of select="$line-break"/>
</xsl:template>
<xsl:template match="xabsl:decimal-parameter">
<xsl:text>d</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
</xsl:template>
<xsl:template match="xabsl:boolean-parameter">
<xsl:text>b</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
</xsl:template>
<xsl:template match="xabsl:enumerated-parameter">
<xsl:text>e</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@enumeration"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
</xsl:template>
<xsl:template match="xabsl:basic-behavior">
<xsl:if test="count(key('basic-behaviors',@name)[1] | .)=1">
<xsl:variable name="name" select="@name"/>
<xsl:value-of select="$name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="count(xabsl:*[local-name()='decimal-parameter' or local-name()='boolean-parameter' or local-name()='enumerated-parameter'])"/>
<xsl:value-of select="$space"/>
<xsl:apply-templates select="xabsl:*[local-name()='decimal-parameter' or local-name()='boolean-parameter' or local-name()='enumerated-parameter']"/>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:decimal-input-symbol">
<xsl:if test="count(key('input-symbols',@name)[1] | .)=1">
<xsl:text>d</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:boolean-input-symbol">
<xsl:if test="count(key('input-symbols',@name)[1] | .)=1">
<xsl:text>b</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:enumerated-input-symbol">
<xsl:if test="count(key('input-symbols',@name)[1] | .)=1">
<xsl:text>e</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@enumeration"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:decimal-output-symbol">
<xsl:if test="count(key('output-symbols',@name)[1] | .)=1">
<xsl:text>d</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:boolean-output-symbol">
<xsl:if test="count(key('output-symbols',@name)[1] | .)=1">
<xsl:text>b</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:enumerated-output-symbol">
<xsl:if test="count(key('output-symbols',@name)[1] | .)=1">
<xsl:text>e</xsl:text>
<xsl:value-of select="$space"/>
<xsl:value-of select="@enumeration"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:enumeration">
<xsl:if test="count(key('enumerations',@name)[1] | .)=1">
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
<xsl:value-of select="count(xabsl:enum-element)"/>
<xsl:value-of select="$space"/>
<xsl:for-each select="xabsl:enum-element">
<xsl:value-of select="@name"/>
<xsl:value-of select="$space"/>
</xsl:for-each>
<xsl:value-of select="$line-break"/>
</xsl:if>
</xsl:template>
<xsl:template match="*"/>
<xsl:template match="text()"/>
</xsl:stylesheet>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:import href="generate-documentation.option-tree.xsl"/>
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="option-tree-xml"/>
<xsl:template match="xabsl:agent-collection">
<html>
<head>
<title>XABSL Behavior Documentation: Agents</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index-linked"/>
<xsl:call-template name="menu-entry-agents"/>
<xsl:call-template name="menu-agents"/>
<xsl:call-template name="menu-entry-symbols-linked"/>
<xsl:call-template name="menu-entry-basic-behaviors-linked"/>
<xsl:call-template name="menu-entry-options-linked"/>
</table>
</td>
<td class="main-area">
<h1>Agents</h1>
<xsl:apply-templates select="xabsl:agent"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="xabsl:agent">
<h2 id="agent.{@id}">
<xsl:value-of select="@title"/>
</h2>
<p>
<xsl:value-of select="@description"/>
</p>
<p>Option Graph:<br/>
<dotml:graph>
<xsl:attribute name="file-name">svg/agent_<xsl:value-of select="@id"/></xsl:attribute>
<xsl:call-template name="paint-option-tree">
<xsl:with-param name="root-option" select="@root-option"/>
<xsl:with-param name="option-tree-xml" select="$option-tree-xml"/>
</xsl:call-template>
</dotml:graph>
</p>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="html" indent="yes"/>
<xsl:key name="basic-behaviors" match="xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:basic-behaviors" use="@id"/>
<xsl:template match="xabsl:agent-collection">
<html>
<head>
<title>XABSL Behavior Documentation: Basic Behaviors</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index-linked"/>
<xsl:call-template name="menu-entry-agents-linked"/>
<xsl:call-template name="menu-entry-symbols-linked"/>
<xsl:call-template name="menu-entry-basic-behaviors"/>
<xsl:call-template name="menu-basic-behaviors"/>
<xsl:call-template name="menu-entry-options-linked"/>
</table>
</td>
<td class="main-area">
<h1>Basic Behaviors</h1>
<table border="0" cellpadding="4" cellspacing="0">
<xsl:for-each select="xabsl:options/xabsl:option/xabsl:basic-behaviors[count(key('basic-behaviors',@id)[1] | .)=1]">
<tr>
<td colspan="2">
<p>&#160;</p>
<a href="basic-behaviors.{@id}.html" title="{@description}">
<h3>
<xsl:value-of select="@title"/>
</h3>
</a>
<p>
<xsl:value-of select="@description"/>
</p>
<p/>
</td>
</tr>
<xsl:for-each select="xabsl:basic-behavior">
<tr>
<td>
<a href="basic-behaviors.{../@id}.html#{@name}" title="{@description}">
<xsl:value-of select="@name"/>
</a>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:for-each>
</xsl:for-each>
</table>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:import href="generate-documentation.parameters.xsl"/>
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="html" indent="yes"/>
<xsl:template match="xabsl:basic-behaviors">
<html>
<head>
<title>XABSL Behavior Documentation: <xsl:value-of select="@title"/>
</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index-linked"/>
<xsl:call-template name="menu-entry-agents-linked"/>
<xsl:call-template name="menu-entry-symbols-linked"/>
<xsl:call-template name="menu-entry-basic-behaviors-linked"/>
<xsl:call-template name="menu-basic-behavior"/>
<xsl:call-template name="menu-entry-options-linked"/>
</table>
</td>
<td class="main-area">
<h1>
<xsl:value-of select="@title"/>
</h1>
<p>
<xsl:value-of select="@description"/>
</p>
<xsl:for-each select="xabsl:basic-behavior">
<h2 id="{@name}">Basic Behavior &quot;<xsl:value-of select="@name"/>&quot;</h2>
<p>
<xsl:value-of select="@description"/>
</p>
<xsl:call-template name="parameters"/>
</xsl:for-each>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,72 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="html" indent="yes"/>
<xsl:template match="xabsl:agent-collection">
<html>
<head>
<title>XABSL Behavior Documentation: <xsl:value-of select="xabsl:title"/>
</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index"/>
<xsl:call-template name="menu-entry-agents-linked"/>
<xsl:call-template name="menu-entry-symbols-linked"/>
<xsl:call-template name="menu-entry-basic-behaviors-linked"/>
<xsl:call-template name="menu-entry-options-linked"/>
</table>
</td>
<td class="main-area">
<h1>
<xsl:value-of select="xabsl:title"/>: Behavior Documentation</h1>
<p>
<div class="bold">Platform:</div>
<xsl:value-of select="xabsl:platform"/>
</p>
<p>
<div class="bold">Software Environment:</div>
<xsl:value-of select="xabsl:software-environment"/>
</p>
<h2>Table Of Contents</h2>
<table border="0" cellpadding="4" cellspacing="6">
<tr>
<td>
<a href="agents.html" title="Available agents">Agents</a>
</td>
<td>All agents of <xsl:value-of select="xabsl:title"/>
</td>
</tr>
<tr>
<td>
<a href="symbols.html" title="Available symbols">Symbols</a>
</td>
<td>The symbols needed to run the behavior in the software environment</td>
</tr>
<tr>
<td>
<a href="basic-behaviors.html" title="Available basic behaviors">Basic Behaviors</a>
</td>
<td>C++ written behaviors at the leaves of the option tree.</td>
</tr>
<tr>
<td>
<a href="options.html" title="Available options">Options</a>
</td>
<td>All options of all agents.</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,283 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:output method="xml" indent="no"/>
<xsl:template name="menu-xabsl2-logo">
<tr>
<td colspan="2" class="xabsl-2-logo-big">
<a href="http://www.xabsl.de" title="The XABSL Web Site">&gt;xabsl</a>
</td>
</tr>
<tr>
<td colspan="2" class="xabsl-2-logo-small">Behavior Documentation</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-agents-linked">
<tr>
<td colspan="2" class="menu-title">
<a href="agents.html" title="All available agents">&gt;Agents</a>
</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-agents">
<tr>
<td colspan="2" class="menu-title">&gt;Agents</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-index-linked">
<tr>
<td colspan="2" class="menu-item">
<br/>&gt;<a href="index.html" title="Start Page">Index</a>
</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-index">
<tr>
<td colspan="2" class="menu-item">
<br/>&gt;Index</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-symbols-linked">
<tr>
<td colspan="2" class="menu-title">
<a href="symbols.html" title="All available symbols">&gt;Symbols</a>
</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-symbols">
<tr>
<td colspan="2" class="menu-title">&gt;Symbols</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-basic-behaviors-linked">
<tr>
<td colspan="2" class="menu-title">
<a href="basic-behaviors.html" title="All available basic behaviors">&gt;Basic Behaviors</a>
</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-basic-behaviors">
<tr>
<td colspan="2" class="menu-title">&gt;Basic Behaviors</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-options-linked">
<tr>
<td colspan="2" class="menu-title">
<a href="options.html" title="All available options">&gt;Options</a>
</td>
</tr>
</xsl:template>
<xsl:template name="menu-entry-options">
<tr>
<td colspan="2" class="menu-title">&gt;Options</td>
</tr>
</xsl:template>
<xsl:template name="menu-basic-behaviors">
<xsl:for-each select="xabsl:options/xabsl:option/xabsl:basic-behaviors[count(key('basic-behaviors',@id)[1] | .)=1]">
<xsl:sort select="@id"/>
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&gt;&gt;&#160;&#160;<a href="basic-behaviors.{@id}.html" title="{@description}">
<xsl:value-of select="@title"/>
</a>
</td>
</tr>
<xsl:for-each select="xabsl:basic-behavior">
<xsl:sort select="@name"/>
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&gt;&gt;&gt;&#160;&#160;<a href="basic-behaviors.{../@id}.html#{@name}" title="{@description}">
<xsl:value-of select="@name"/>
</a>
</td>
</tr>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template name="menu-basic-behavior">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&gt;&gt;&#160;&#160;<xsl:value-of select="@title"/>
</td>
</tr>
<xsl:for-each select="xabsl:basic-behavior">
<xsl:sort select="@name"/>
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&gt;&gt;&gt;&#160;&#160;<a href="basic-behaviors.{../@id}.html#{@name}" title="{@description}">
<xsl:value-of select="@name"/>
</a>
</td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template name="menu-options">
<xsl:for-each select="xabsl:option-definition">
<xsl:sort select="@name"/>
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&gt;&gt;&#160;&#160;<a href="option.{@name}.html" class="menu-item" title="{@description}">
<xsl:value-of select="@name"/>
</a>
</td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template name="menu-symbols">
<xsl:for-each select="xabsl:options/xabsl:option/xabsl:symbols[count(key('symbols',@id)[1] | .)=1]">
<xsl:sort select="@id"/>
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&gt;&gt;&#160;&#160;<a href="symbols.{@id}.html" title="{@description}">
<xsl:value-of select="@title"/>
</a>
</td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template name="menu-agents">
<xsl:for-each select="xabsl:agent">
<xsl:sort select="@id"/>
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&gt;&gt;&#160;&#160;<a href="agents.html#agent.{@id}" title="{@description}">
<xsl:value-of select="@title"/>
</a>
</td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template name="menu-symbol">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&gt;&gt;&#160;&#160;<xsl:value-of select="@title"/>
</td>
</tr>
<xsl:if test="xabsl:decimal-input-symbol | xabsl:boolean-input-symbol | xabsl:enumerated-input-symbol">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&gt;&gt;&gt;&#160;&#160;<a href="symbols.{@id}.html#input-symbols" title="All available input symbols">Input Symbols</a>
</td>
</tr>
</xsl:if>
<xsl:if test="xabsl:decimal-input-function">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&gt;&gt;&gt;&#160;&#160;<a href="symbols.{@id}.html#input-functions" title="All available input functions">Input Functions</a>
</td>
</tr>
</xsl:if>
<xsl:if test="xabsl:enumerated-output-symbol">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&gt;&gt;&gt;&#160;&#160;<a href="symbols.{@id}.html#output-symbols" title="All available output symbols">Output Symbols</a>
</td>
</tr>
</xsl:if>
<xsl:if test="xabsl:constant">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&gt;&gt;&gt;&#160;&#160;<a href="symbols.{@id}.html#constants" title="All available constants">Constants</a>
</td>
</tr>
</xsl:if>
</xsl:template>
<xsl:template name="menu-option">
<xsl:variable name="name" select="@name"/>
<xsl:for-each select="xabsl:option-definitions/xabsl:option-definition[@name = $name]">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&gt;&gt;&#160;&#160;<xsl:value-of select="@name"/>
</td>
</tr>
</xsl:for-each>
<xsl:for-each select="xabsl:state">
<tr>
<td class="menu-item" nowrap="nowrap" colspan="2">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&gt;&gt;&gt;&#160;&#160;<a href="option.{../@name}.html#state_{@name}" title="State {@name}">
<xsl:value-of select="@name"/>
</a>
</td>
</tr>
</xsl:for-each>
</xsl:template>
<xsl:template match="xabsl:agent-collection">
<table border="0" cellspacing="0" cellpadding="1">
<!--<tr>
<td colspan="2">
<img src="Xabsl2Logo.gif"/>
</td>
</tr>-->
<tr>
<td colspan="2" class="xabsl-2-logo-big">>xabsl 2</td>
</tr>
<tr>
<td colspan="2" class="xabsl-2-logo-small">Behavior Documentation</td>
</tr>
<tr>
<td colspan="2" class="menu-item">
<br/>><a href="index.html" title="Start Page">Index</a>
</td>
</tr>
<tr>
<td colspan="2" class="menu-title">>Agents:</td>
</tr>
<tr>
<xsl:for-each select="xabsl:agent">
<xsl:sort select="@id"/>
<tr>
<td class="menu-item" nowrap="nowrap">>></td>
<td>
<a href="agent.{@id}.html" class="menu-item" title="{@description}">
<xsl:value-of select="@title"/>
</a>
</td>
</tr>
</xsl:for-each>
</tr>
<tr>
<td colspan="2" class="menu-title">>Symbols:</td>
</tr>
<tr>
<xsl:for-each select="xabsl:agent/xabsl:symbols">
<xsl:sort select="@id"/>
<xsl:variable name="title" select="@title"/>
<xsl:if test="count(preceding::xabsl:symbols[@title=$title])=0">
<tr>
<td class="menu-item" nowrap="nowrap">>></td>
<td>
<a href="symbols.{@id}.html" class="menu-item" title="{@description}">
<xsl:value-of select="@title"/>
</a>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</tr>
<tr>
<td colspan="2" class="menu-title">>Basic Behaviors:</td>
</tr>
<tr>
<xsl:for-each select="xabsl:agent/xabsl:basic-behaviors">
<xsl:sort select="@id"/>
<xsl:variable name="title" select="@title"/>
<xsl:if test="count(preceding::xabsl:basic-behaviors[@title=$title])=0">
<tr>
<td class="menu-item" nowrap="nowrap">>></td>
<td>
<a href="basic-behaviors.{@id}.html" class="menu-item" title="{@description}">
<xsl:value-of select="@title"/>
</a>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</tr>
<tr>
<td colspan="2" class="menu-title">>Options:</td>
</tr>
<tr>
<xsl:for-each select="xabsl:agent/xabsl:option-definitions/xabsl:option-definition">
<xsl:sort select="@name"/>
<xsl:variable name="name" select="@name"/>
<xsl:if test="count(preceding::xabsl:option-definition[@name=$name])=0">
<tr>
<td class="menu-item" nowrap="nowrap">>></td>
<td>
<a href="option.{@name}.html" class="menu-item" title="{@description}">
<xsl:value-of select="@name"/>
</a>
</td>
</tr>
</xsl:if>
</xsl:for-each>
</tr>
</table>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:import href="generate-documentation.option-tree.xsl"/>
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="option-tree-xml"/>
<xsl:template match="xabsl:option-definitions">
<html>
<head>
<title>XABSL Behavior Documentation: Options</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index-linked"/>
<xsl:call-template name="menu-entry-agents-linked"/>
<xsl:call-template name="menu-entry-symbols-linked"/>
<xsl:call-template name="menu-entry-basic-behaviors-linked"/>
<xsl:call-template name="menu-entry-options"/>
<xsl:call-template name="menu-options"/>
</table>
</td>
<td class="main-area">
<h1>Options</h1>
<table border="0" cellpadding="4" cellspacing="0">
<xsl:for-each select="xabsl:option-definition">
<xsl:sort select="@name"/>
<tr>
<td>
<a href="option.{@name}.html" title="{@description}">
<xsl:value-of select="@name"/>
</a>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:for-each>
</table>
<p>Option Graph:<br/>
<dotml:graph>
<xsl:attribute name="file-name">svg/options</xsl:attribute>
<xsl:call-template name="paint-complete-option-tree">
<xsl:with-param name="option-tree-xml" select="$option-tree-xml"/>
</xsl:call-template>
</dotml:graph>
</p>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,127 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:import href="generate-documentation.string-functions.xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:key name="options" match="xabsl:agent-collection/xabsl:options/xabsl:option" use="@name"/>
<xsl:key name="basic-behaviors" match="xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:basic-behaviors/xabsl:basic-behavior" use="@name"/>
<xsl:template match="xabsl:agent-collection">
<xabsl:option-trees>
<xsl:for-each select="xabsl:options/xabsl:option">
<xabsl:option-tree root-option="{@name}">
<xsl:call-template name="create-option-tree"/>
</xabsl:option-tree>
</xsl:for-each>
</xabsl:option-trees>
</xsl:template>
<xsl:template name="create-option-tree">
<xabsl:o-n name="{@name}">
<xsl:for-each select="xabsl:common-action/xabsl:subsequent-option | xabsl:state/xabsl:subsequent-option">
<xsl:variable name="ref" select="@ref"/>
<xsl:if test="not(../preceding-sibling::xabsl:state/xabsl:subsequent-option[@ref=$ref])">
<xabsl:e2o to="{@ref}"/>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="xabsl:common-action/xabsl:subsequent-basic-behavior | xabsl:state/xabsl:subsequent-basic-behavior">
<xsl:variable name="ref" select="@ref"/>
<xsl:if test="not(../preceding-sibling::xabsl:state/xabsl:subsequent-basic-behavior[@ref=$ref])">
<xabsl:e2b to="{@ref}"/>
</xsl:if>
</xsl:for-each>
</xabsl:o-n>
<xsl:for-each select="xabsl:common-action/xabsl:subsequent-option | xabsl:state/xabsl:subsequent-option">
<xsl:variable name="ref" select="@ref"/>
<xsl:if test="not(../preceding-sibling::xabsl:state/xabsl:subsequent-option[@ref=$ref])">
<xsl:for-each select="key('options',@ref)[1]">
<xsl:call-template name="create-option-tree"/>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="xabsl:common-action/xabsl:subsequent-basic-behavior | xabsl:state/xabsl:subsequent-basic-behavior">
<xsl:variable name="ref" select="@ref"/>
<xsl:if test="not(../preceding-sibling::xabsl:state/xabsl:subsequent-basic-behavior[@ref=$ref])">
<xabsl:b-n name="{@ref}" g="{key('basic-behaviors',@ref)[1]/../@id}"/>
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template name="paint-option-tree">
<xsl:param name="root-option"/>
<xsl:param name="dont-paint-option"/>
<xsl:param name="option-tree-xml"/>
<xsl:for-each select="document($option-tree-xml)/xabsl:option-trees/xabsl:option-tree[@root-option=$root-option]">
<xsl:for-each select="xabsl:o-n[@name!=$dont-paint-option]">
<xsl:variable name="name" select="@name"/>
<xsl:if test="count(preceding-sibling::xabsl:o-n[@name=$name])=0">
<dotml:node fontname="Arial" fontcolor="#005A9C" fontsize="9" shape="box" URL="option.{@name}.html" fillcolor="#FFFFFF" style="filled">
<xsl:attribute name="id">option_<xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="label"><xsl:call-template name="replace-in-string"><xsl:with-param name="original-string" select="@name"/><xsl:with-param name="replace">_</xsl:with-param><xsl:with-param name="with">\n</xsl:with-param></xsl:call-template></xsl:attribute>
</dotml:node>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="xabsl:b-n">
<xsl:variable name="name" select="@name"/>
<xsl:if test="count(preceding-sibling::xabsl:b-n[@name=$name])=0">
<dotml:node fontname="Arial" fontcolor="#005A9C" fontsize="9" URL="basic-behaviors.{@g}.html#{@name}" style="filled" fillcolor="#FFFFFF">
<xsl:attribute name="id">basic_behavior_<xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="label"><xsl:call-template name="replace-in-string"><xsl:with-param name="original-string" select="@name"/><xsl:with-param name="replace">_</xsl:with-param><xsl:with-param name="with">\n</xsl:with-param></xsl:call-template></xsl:attribute>
</dotml:node>
</xsl:if>
</xsl:for-each>
<xsl:for-each select="xabsl:o-n[@name!=$dont-paint-option]">
<xsl:variable name="name" select="@name"/>
<xsl:if test="count(preceding-sibling::xabsl:o-n[@name=$name])=0">
<xsl:for-each select="xabsl:e2o">
<dotml:edge arrowsize="0.8" color="#808080">
<xsl:attribute name="from">option_<xsl:value-of select="../@name"/></xsl:attribute>
<xsl:attribute name="to">option_<xsl:value-of select="@to"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
<xsl:for-each select="xabsl:e2b">
<dotml:edge arrowsize="0.8" color="#808080">
<xsl:attribute name="from">option_<xsl:value-of select="../@name"/></xsl:attribute>
<xsl:attribute name="to">basic_behavior_<xsl:value-of select="@to"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template name="paint-complete-option-tree">
<xsl:param name="option-tree-xml"/>
<xsl:for-each select="document($option-tree-xml)/xabsl:option-trees/xabsl:option-tree">
<xsl:variable name="root-option" select="@root-option"/>
<dotml:node fontname="Arial" fontcolor="#005A9C" fontsize="9" shape="box" URL="option.{$root-option}.html" fillcolor="#FFFFFF" style="filled">
<xsl:attribute name="id">option_<xsl:value-of select="$root-option"/></xsl:attribute>
<xsl:attribute name="label"><xsl:call-template name="replace-in-string"><xsl:with-param name="original-string" select="$root-option"/><xsl:with-param name="replace">_</xsl:with-param><xsl:with-param name="with">\n</xsl:with-param></xsl:call-template></xsl:attribute>
</dotml:node>
<xsl:for-each select="xabsl:b-n">
<xsl:variable name="name" select="@name"/>
<xsl:if test="count(preceding-sibling::xabsl:b-n[@name=$name])=0">
<dotml:node fontname="Arial" fontcolor="#005A9C" fontsize="9" URL="basic-behaviors.{@g}.html#{@name}" style="filled" fillcolor="#FFFFFF">
<xsl:attribute name="id">basic_behavior_<xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="label"><xsl:call-template name="replace-in-string"><xsl:with-param name="original-string" select="@name"/><xsl:with-param name="replace">_</xsl:with-param><xsl:with-param name="with">\n</xsl:with-param></xsl:call-template></xsl:attribute>
</dotml:node>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="document($option-tree-xml)/xabsl:option-trees/xabsl:option-tree">
<xsl:variable name="root-option" select="@root-option"/>
<xsl:for-each select="xabsl:o-n[@name=$root-option]">
<xsl:if test="count(preceding-sibling::xabsl:o-n[@name=$root-option])=0">
<xsl:for-each select="xabsl:e2o">
<dotml:edge arrowsize="0.8" color="#808080">
<xsl:attribute name="from">option_<xsl:value-of select="$root-option"/></xsl:attribute>
<xsl:attribute name="to">option_<xsl:value-of select="@to"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
<xsl:for-each select="xabsl:e2b">
<dotml:edge arrowsize="0.8" color="#808080">
<xsl:attribute name="from">option_<xsl:value-of select="$root-option"/></xsl:attribute>
<xsl:attribute name="to">basic_behavior_<xsl:value-of select="@to"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,457 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:import href="generate-documentation.option-tree.xsl"/>
<xsl:import href="generate-documentation.parameters.xsl"/>
<xsl:import href="generate-documentation.pseudo-code.xsl"/>
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="xml" indent="yes"/>
<xsl:param name="option-tree-xml"/>
<xsl:key name="basic-behaviors" match="xabsl:option/xabsl:basic-behaviors/xabsl:basic-behavior" use="@name"/>
<xsl:key name="option-definitions" match="xabsl:option/xabsl:option-definitions/xabsl:option-definition" use="@name"/>
<xsl:key name="transitions" match="xabsl:option/descendant::xabsl:transition-to-state" use="@ref"/>
<xsl:template match="xabsl:option">
<xsl:variable name="name" select="@name"/>
<xsl:variable name="description" select="xabsl:option-definitions/xabsl:option-definition[@name=$name]/@description"/>
<html>
<head>
<title>XABSL Behavior Documentation: Option <xsl:value-of select="@name"/>
</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index-linked"/>
<xsl:call-template name="menu-entry-agents-linked"/>
<xsl:call-template name="menu-entry-symbols-linked"/>
<xsl:call-template name="menu-entry-basic-behaviors-linked"/>
<xsl:call-template name="menu-entry-options-linked"/>
<xsl:call-template name="menu-option"/>
</table>
</td>
<td class="main-area">
<h1>Option <xsl:value-of select="@name"/>
</h1>
<p>
<xsl:value-of select="$description"/>
</p>
<xsl:for-each select="key('option-definitions',@name)">
<xsl:if test="xabsl:decimal-parameter | xabsl:boolean-parameter | xabsl:enumerated-parameter">
<p>Parameters of that option:
<xsl:call-template name="parameters"/>
</p>
</xsl:if>
</xsl:for-each>
<h2>State Machine</h2>
<dotml:graph file-name="svg/option_{$name}" ranksep="0.4" nodesep="0.3">
<dotml:cluster id="option" label="option {$name}" fontname="Arial" fontcolor="#005A9C" fontsize="12" fillcolor="#F4F4F4" style="filled">
<xsl:call-template name="state-machine"/>
</dotml:cluster>
<dotml:cluster id="option_tree" color="#FFFFFF">
<xsl:call-template name="paint-option-tree">
<xsl:with-param name="root-option" select="@name"/>
<xsl:with-param name="dont-paint-option" select="@name"/>
<xsl:with-param name="option-tree-xml" select="$option-tree-xml"/>
</xsl:call-template>
<xsl:for-each select="xabsl:common-action/xabsl:subsequent-basic-behavior">
<xsl:variable name="ref" select="@ref"/>
<xsl:for-each select="../../xabsl:state">
<dotml:edge arrowsize="0.8" color="#808080" style="dashed" minlen="3">
<xsl:attribute name="from">state_<xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="to">basic_behavior_<xsl:value-of select="$ref"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="xabsl:common-action/xabsl:subsequent-option">
<xsl:variable name="ref" select="@ref"/>
<xsl:for-each select="../../xabsl:state">
<dotml:edge minlen="2" arrowsize="0.8" color="#808080" style="dashed">
<xsl:attribute name="from">state_<xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="to">option_<xsl:value-of select="$ref"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
</xsl:for-each>
<xsl:for-each select="xabsl:state/xabsl:subsequent-basic-behavior">
<dotml:edge arrowsize="0.8" color="#808080" style="dashed" minlen="3">
<xsl:attribute name="from">state_<xsl:value-of select="../@name"/></xsl:attribute>
<xsl:attribute name="to">basic_behavior_<xsl:value-of select="@ref"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
<xsl:for-each select="xabsl:state/xabsl:subsequent-option">
<dotml:edge minlen="2" arrowsize="0.8" color="#808080" style="dashed">
<xsl:attribute name="from">state_<xsl:value-of select="../@name"/></xsl:attribute>
<xsl:attribute name="to">option_<xsl:value-of select="@ref"/></xsl:attribute>
</dotml:edge>
</xsl:for-each>
</dotml:cluster>
</dotml:graph>
<xsl:apply-templates select="xabsl:state"/>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="xabsl:state">
<xsl:variable name="option-name" select="../@name"/>
<xsl:variable name="current-state" select="@name"/>
<h2 id="state_{@name}">State <xsl:value-of select="@name"/>
</h2>
<table cellpadding="0" cellspacing="5">
<xsl:if test="@is-target-state='true'">
<tr>
<td colspan="5">This state is a target state.<br/>
<br/>
</td>
</tr>
</xsl:if>
<xsl:if test="@synchronized">
<tr>
<td colspan="5">This state is synchronized. All cooperating agents that are executing this option will enter it at once.
<xsl:if test="@synchronized &gt; 0">
Minimum number of agents required to enter the state is <xsl:value-of select="@synchronized"/>.
</xsl:if>
<br/><br/>
</td>
</tr>
</xsl:if>
<xsl:if test="@capacity">
<tr>
<td colspan="5">This state has a capacity of <xsl:value-of select="@capacity"/>.
Only <xsl:value-of select="@capacity"/> of the cooperating agents that are executing this option can enter it at the same time.
<br/><br/>
</td>
</tr>
</xsl:if>
<tr>
<td colspan="5">If that state is active, </td>
</tr>
<xsl:for-each select="../xabsl:common-action/xabsl:subsequent-option | ../xabsl:common-action/xabsl:subsequent-basic-behavior |
../xabsl:common-action/xabsl:set-decimal-output-symbol | ../xabsl:common-action/xabsl:set-boolean-output-symbol | ../xabsl:common-action/xabsl:set-enumerated-output-symbol |
xabsl:subsequent-option | xabsl:subsequent-basic-behavior |
xabsl:set-decimal-output-symbol | xabsl:set-boolean-output-symbol | xabsl:set-enumerated-output-symbol">
<xsl:choose>
<xsl:when test="name()='subsequent-option'">
<tr>
<td nowrap="nowrap">
<span class="bold">&#160;>&#160;</span>
</td>
<td colspan="4">
The option <a href="option.{@ref}.html" title="{key('option-definitions',@ref)/@description}">
<xsl:value-of select="@ref"/>
</a> is executed. <xsl:if test="xabsl:set-parameter">Parameters:</xsl:if>
</td>
</tr>
</xsl:when>
<xsl:when test="name()='subsequent-basic-behavior'">
<tr>
<td nowrap="nowrap">
<span class="bold">&#160;>&#160;</span>
</td>
<td colspan="4">
The <xsl:variable name="ref" select="@ref"/> basic behavior <a href="basic-behaviors.{key('basic-behaviors',$ref)/../@id}.html#{$ref}" title="{key('basic-behaviors',$ref)/@description}">
<xsl:value-of select="@ref"/>
</a> is executed. <xsl:if test="xabsl:set-parameter">Parameters:</xsl:if>
</td>
</tr>
</xsl:when>
<xsl:when test="name()='set-decimal-output-symbol'">
<tr>
<td nowrap="nowrap">
<span class="bold">&#160;>&#160;</span>
</td>
<td colspan="4">This decimal output symbol is set:</td>
</tr>
<tr>
<xsl:variable name="ref" select="@ref"/>
<td nowrap="nowrap">&#160;</td>
<td nowrap="nowrap">&#160;</td>
<td class="pseudo-code-cell">
<a href="symbols.{../../xabsl:symbols/xabsl:decimal-output-symbol[@name=$ref]/../@id}.html#symbols.{$ref}" title="{../../xabsl:symbols/xabsl:decimal-output-symbol[@name=$ref]/@description}">
<xsl:value-of select="@ref"/>
</a>
</td>
<td nowrap="nowrap" class="pseudo-code-cell">&#160;=&#160;</td>
<td>
<xsl:call-template name="pseudo-code"/>
</td>
</tr>
</xsl:when>
<xsl:when test="name()='set-boolean-output-symbol'">
<tr>
<td nowrap="nowrap">
<span class="bold">&#160;>&#160;</span>
</td>
<td colspan="4">This boolean output symbol is set:</td>
</tr>
<tr>
<xsl:variable name="ref" select="@ref"/>
<td>&#160;</td>
<td>&#160;</td>
<td class="pseudo-code-cell">
<a href="symbols.{../../xabsl:symbols/xabsl:boolean-output-symbol[@name=$ref]/../@id}.html#symbols.{$ref}" title="{../../xabsl:symbols/xabsl:boolean-output-symbol[@name=$ref]/@description}">
<xsl:value-of select="@ref"/>
</a>
</td>
<td nowrap="nowrap" class="pseudo-code-cell">&#160;=&#160;</td>
<td>
<xsl:call-template name="pseudo-code"/>
</td>
</tr>
</xsl:when>
<xsl:when test="name()='set-enumerated-output-symbol'">
<tr>
<td nowrap="nowrap">
<span class="bold">&#160;>&#160;</span>
</td>
<td colspan="4">This enumerated output symbol is set:</td>
</tr>
<tr>
<xsl:variable name="ref" select="@ref"/>
<td nowrap="nowrap">&#160;</td>
<td nowrap="nowrap">&#160;</td>
<td class="pseudo-code-cell">
<a href="symbols.{../../xabsl:symbols/xabsl:enumerated-output-symbol[@name=$ref]/../@id}.html#symbols.{$ref}" title="{../../xabsl:symbols/xabsl:enumerated-output-symbol[@name=$ref]/@description}">
<xsl:value-of select="@ref"/>
</a>
</td>
<td nowrap="nowrap" class="pseudo-code-cell">&#160;=&#160;</td>
<td class="pseudo-code-cell">
<xsl:call-template name="pseudo-code"/>
</td>
</tr>
</xsl:when>
</xsl:choose>
<xsl:if test="xabsl:set-parameter">
<xsl:for-each select="xabsl:set-parameter">
<xsl:variable name="ref" select="@ref"/>
<xsl:variable name="subsequent" select="../@ref"/>
<tr>
<td>&#160;</td>
<td>&#160;</td>
<td class="pseudo-code-cell">
<xsl:if test="../../xabsl:subsequent-option">
<a href="option.{../@ref}.html" title="{key('option-definitions',$subsequent)/xabsl:parameter[@name=$ref]/@description}">
<xsl:value-of select="@ref"/>
</a>
</xsl:if>
<xsl:if test="../../xabsl:subsequent-basic-behavior">
<a href="basic-behaviors.{key('basic-behaviors',$subsequent)/../@id}.html#{$subsequent}" title="{key('basic-behaviors',$subsequent)/xabsl:parameter[@name=$ref]/@description}">
<xsl:value-of select="@ref"/>
</a>
</xsl:if>
</td>
<td nowrap="nowrap" class="pseudo-code-cell">&#160;=&#160;</td>
<td class="pseudo-code-cell">
<xsl:apply-templates/>;
</td>
</tr>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
<tr>
<td colspan="5">&#160;</td>
</tr>
<tr>
<td colspan="5">The decision tree:</td>
</tr>
<tr>
<td>&#160;</td>
<td colspan="4">
<dotml:graph ranksep="0.4">
<xsl:attribute name="file-name">svg/option_<xsl:value-of select="../@name"/>_state_<xsl:value-of select="@name"/></xsl:attribute>
<dotml:cluster id="option" label="option {../@name}" fontname="Arial" fontcolor="#005A9C" fontsize="12" fillcolor="#F4F4F4" style="filled">
<dotml:cluster id="states" style="filled" fillcolor="#F4F4F4" color="#F4F4F4">
<xsl:for-each select=".//xabsl:transition-to-state | ../xabsl:common-decision-tree//xabsl:transition-to-state">
<xsl:variable name="ref" select="@ref"/>
<xsl:for-each select="ancestor::xabsl:option/xabsl:state[@name=$ref and @name!=$current-state]">
<xsl:call-template name="paint-state-node">
<xsl:with-param name="option-name" select="../@name"/>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="ancestor::xabsl:option/xabsl:state[@name=$ref and @name=$current-state]">
<dotml:node label="{@name}" fontname="Arial" fontcolor="#005A9C" fontsize="9" style="dashed" fillcolor="#FFFFFF">
<xsl:attribute name="id">state_<xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="label"><xsl:call-template name="replace-in-string"><xsl:with-param name="original-string" select="@name"/><xsl:with-param name="replace">_</xsl:with-param><xsl:with-param name="with">\n</xsl:with-param></xsl:call-template></xsl:attribute>
<xsl:attribute name="shape"><xsl:choose><xsl:when test="../@initial-state=@name">Mcircle</xsl:when><xsl:when test="@is-target-state='true'">doublecircle</xsl:when><xsl:otherwise>circle</xsl:otherwise></xsl:choose></xsl:attribute>
</dotml:node>
</xsl:for-each>
</xsl:for-each>
</dotml:cluster>
<dotml:cluster id="decision_tree" label="state {@name}" fillcolor="#FFFFFF" fontname="Arial" fontcolor="#005A9C" fontsize="12" style="filled">
<dotml:node id="start" shape="point"/>
<xsl:choose>
<xsl:when test="../xabsl:common-decision-tree">
<xsl:for-each select="../xabsl:common-decision-tree">
<xsl:call-template name="decision-tree">
<xsl:with-param name="parent">start</xsl:with-param>
<xsl:with-param name="id-string"></xsl:with-param>
<xsl:with-param name="current-state" select="$current-state"/>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="xabsl:decision-tree">
<xsl:call-template name="decision-tree">
<xsl:with-param name="parent">start</xsl:with-param>
<xsl:with-param name="id-string"></xsl:with-param>
<xsl:with-param name="current-state" select="$current-state"/>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</dotml:cluster>
</dotml:cluster>
</dotml:graph>
</td>
</tr>
<tr>
<td colspan="5">&#160;</td>
</tr>
<tr>
<td colspan="5">Pseudo code of the decision tree:</td>
</tr>
<tr>
<td>&#160;</td>
<td colspan="4">
<xsl:choose>
<xsl:when test="../xabsl:common-decision-tree">
<xsl:for-each select="../xabsl:common-decision-tree">
<xsl:call-template name="pseudo-code">
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string">state_<xsl:value-of select="$current-state"/>_pseudo-code</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:for-each select="xabsl:decision-tree">
<xsl:call-template name="pseudo-code">
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string">state_<xsl:value-of select="$current-state"/>_pseudo-code</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:otherwise>
</xsl:choose>
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="decision-tree">
<xsl:param name="parent"/>
<xsl:param name="id-string"/>
<xsl:param name="current-state"/>
<xsl:param name="taillabel"/>
<xsl:variable name="pos_else" select="count(xabsl:else-if)+1"/>
<xsl:if test="xabsl:if">
<xsl:for-each select="xabsl:if | xabsl:else-if">
<dotml:node id="{$id-string}_{position()-1}" shape="box" fontsize="9" style="filled" fillcolor="#FFFFFF">
<xsl:attribute name="fontname"><xsl:choose><xsl:when test="ancestor-or-self::xabsl:common-decision-tree">Arial Italic</xsl:when><xsl:otherwise>Arial</xsl:otherwise></xsl:choose></xsl:attribute>
<xsl:attribute name="label"><xsl:call-template name="add-line-breaks"><xsl:with-param name="original-string"><xsl:value-of select="xabsl:condition/@description"/></xsl:with-param><xsl:with-param name="min-length">5</xsl:with-param></xsl:call-template></xsl:attribute>
<xsl:attribute name="URL">option.<xsl:value-of select="ancestor::xabsl:option/@name"/>.html#state_<xsl:value-of select="$current-state"/>_pseudo-code<xsl:value-of select="$id-string"/>_<xsl:value-of select="position()-1"/></xsl:attribute>
</dotml:node>
</xsl:for-each>
<xsl:for-each select="xabsl:if | xabsl:else-if">
<xsl:call-template name="decision-tree">
<xsl:with-param name="parent">
<xsl:value-of select="$id-string"/>_<xsl:value-of select="position()-1"/></xsl:with-param>
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string">
<xsl:value-of select="$id-string"/>_<xsl:value-of select="position()-1"/></xsl:with-param>
<xsl:with-param name="taillabel">1</xsl:with-param>
</xsl:call-template>
<xsl:if test="position() &lt; $pos_else">
<dotml:edge from="{$id-string}_{position()-1}" to="{$id-string}_{position()}" label="" fontsize="9" taillabel="0">
<xsl:attribute name="style"><xsl:choose><xsl:when test="ancestor-or-self::xabsl:common-decision-tree">dashed</xsl:when><xsl:otherwise>solid</xsl:otherwise></xsl:choose></xsl:attribute>
<xsl:attribute name="fontname"><xsl:choose><xsl:when test="ancestor-or-self::xabsl:common-decision-tree">Arial Bold Italic</xsl:when><xsl:otherwise>Arial Bold</xsl:otherwise></xsl:choose></xsl:attribute>
</dotml:edge>
</xsl:if>
</xsl:for-each>
<dotml:edge from="{$parent}" to="{$id-string}_0" label="" fontsize="9" taillabel="{$taillabel}">
<xsl:attribute name="style"><xsl:choose><xsl:when test="ancestor-or-self::xabsl:common-decision-tree">dashed</xsl:when><xsl:otherwise>solid</xsl:otherwise></xsl:choose></xsl:attribute>
<xsl:attribute name="fontname"><xsl:choose><xsl:when test="ancestor-or-self::xabsl:common-decision-tree">Arial Bold Italic</xsl:when><xsl:otherwise>Arial Bold</xsl:otherwise></xsl:choose></xsl:attribute>
</dotml:edge>
<xsl:if test="ancestor-or-self::xabsl:common-decision-tree and count(xabsl:else)=0">
<xsl:for-each select="ancestor::xabsl:option/xabsl:state[@name=$current-state]/xabsl:decision-tree">
<xsl:call-template name="decision-tree">
<xsl:with-param name="parent">
<xsl:value-of select="$id-string"/>_<xsl:value-of select="$pos_else - 1"/></xsl:with-param>
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string">
<xsl:value-of select="$id-string"/>_<xsl:value-of select="$pos_else"/></xsl:with-param>
<xsl:with-param name="taillabel">0</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:if>
<xsl:for-each select="xabsl:else">
<xsl:call-template name="decision-tree">
<xsl:with-param name="parent">
<xsl:value-of select="$id-string"/>_<xsl:value-of select="$pos_else - 1"/>
</xsl:with-param>
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string">
<xsl:value-of select="$id-string"/>_<xsl:value-of select="$pos_else"/>
</xsl:with-param>
<xsl:with-param name="taillabel">0</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</xsl:if>
<xsl:if test="xabsl:transition-to-state">
<dotml:edge from="{$parent}" minlen="2" label="" fontsize="9" taillabel="{$taillabel}">
<xsl:variable name="ref" select="xabsl:transition-to-state/@ref"/>
<xsl:attribute name="style"><xsl:choose><xsl:when test="ancestor-or-self::xabsl:common-decision-tree">dashed</xsl:when><xsl:otherwise>solid</xsl:otherwise></xsl:choose></xsl:attribute>
<xsl:attribute name="to">state_<xsl:value-of select="$ref"/></xsl:attribute>
</dotml:edge>
</xsl:if>
</xsl:template>
<xsl:template name="paint-state-node">
<xsl:param name="option-name"/>
<dotml:node fontcolor="#005A9C" fontsize="9" style="filled" fillcolor="#FFFFFF" fontname="Arial" URL="option.{$option-name}.html#state_{@name}">
<xsl:attribute name="id">state_<xsl:value-of select="@name"/></xsl:attribute>
<xsl:attribute name="label"><xsl:call-template name="replace-in-string"><xsl:with-param name="original-string" select="@name"/><xsl:with-param name="replace">_</xsl:with-param><xsl:with-param name="with">\n</xsl:with-param></xsl:call-template></xsl:attribute>
<xsl:attribute name="shape"><xsl:choose><xsl:when test="../@initial-state=@name">Mcircle</xsl:when><xsl:when test="@is-target-state='true'">doublecircle</xsl:when><xsl:otherwise>circle</xsl:otherwise></xsl:choose></xsl:attribute>
</dotml:node>
</xsl:template>
<xsl:template name="state-machine">
<xsl:variable name="name" select="@name"/>
<dotml:sub-graph rank="same">
<xsl:for-each select="xabsl:state[1]">
<xsl:call-template name="paint-state-node">
<xsl:with-param name="option-name" select="$name"/>
</xsl:call-template>
</xsl:for-each>
</dotml:sub-graph>
<xsl:for-each select="xabsl:state[position() mod 3 = 2]">
<dotml:sub-graph rank="same">
<xsl:call-template name="paint-state-node">
<xsl:with-param name="option-name" select="$name"/>
</xsl:call-template>
<xsl:for-each select="following-sibling::xabsl:state[1]">
<xsl:call-template name="paint-state-node">
<xsl:with-param name="option-name" select="$name"/>
</xsl:call-template>
</xsl:for-each>
<xsl:for-each select="following-sibling::xabsl:state[2]">
<xsl:call-template name="paint-state-node">
<xsl:with-param name="option-name" select="$name"/>
</xsl:call-template>
</xsl:for-each>
</dotml:sub-graph>
</xsl:for-each>
<xsl:for-each select="xabsl:state">
<xsl:variable name="name2" select="@name"/>
<xsl:for-each select="descendant::xabsl:transition-to-state | ../xabsl:common-decision-tree/descendant::xabsl:transition-to-state">
<xsl:if test="count(key('transitions',@ref)[ancestor::xabsl:state[@name=$name2] or ancestor::xabsl:common-decision-tree][1] | .) = 1">
<dotml:edge>
<xsl:attribute name="from">state_<xsl:value-of select="$name2"/></xsl:attribute>
<xsl:attribute name="to">state_<xsl:value-of select="@ref"/></xsl:attribute>
</dotml:edge>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:template name="parameters">
<xsl:if test="xabsl:decimal-parameter | xabsl:boolean-parameter | xabsl:enumerated-parameter">
<table border="0" cellspacing="6" cellpadding="0">
<tr>
<td class="tablehead">Parameter</td>
<td class="tablehead">Type</td>
<td class="tablehead">Measure</td>
<td class="tablehead">Range</td>
<td class="tablehead">Description</td>
</tr>
<xsl:for-each select="xabsl:decimal-parameter">
<tr>
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>decimal</td>
<td class="italic">
<xsl:value-of select="@measure"/>
</td>
<td>
<xsl:value-of select="@range"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:for-each>
<xsl:for-each select="xabsl:boolean-parameter">
<tr>
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>boolean</td>
<td class="italic">true/ false</td>
<td/>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:for-each>
<xsl:for-each select="xabsl:enumerated-parameter">
<tr>
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>enumerated</td>
<td class="bold">
<xsl:value-of select="@enumeration"/>
</td>
<td/>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,427 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:key name="decimal-input-symbols" match="//xabsl:decimal-input-symbol" use="@name"/>
<xsl:key name="boolean-input-symbols" match="//xabsl:boolean-input-symbol" use="@name"/>
<xsl:key name="enumerated-input-symbols" match="//xabsl:enumerated-input-symbol" use="@name"/>
<xsl:key name="decimal-output-symbols" match="//xabsl:decimal-output-symbol" use="@name"/>
<xsl:key name="boolean-output-symbols" match="//xabsl:boolean-output-symbol" use="@name"/>
<xsl:key name="enumerated-output-symbols" match="//xabsl:enumerated-output-symbol" use="@name"/>
<xsl:key name="constants" match="//xabsl:constant" use="@name"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template name="pseudo-code">
<xsl:param name="current-state"/>
<xsl:param name="id-string"/>
<table>
<xsl:attribute name="class"><xsl:choose><xsl:when test="ancestor-or-self::xabsl:common-decision-tree">common-pseudo-code-frame</xsl:when><xsl:otherwise>pseudo-code-frame</xsl:otherwise></xsl:choose></xsl:attribute>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<xsl:choose>
<xsl:when test="local-name(xabsl:*)='if' or local-name(xabsl:*)='else' or local-name(xabsl:*)='else-if'">
<xsl:apply-templates>
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string" select="$id-string"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<tr>
<xsl:for-each select="xabsl:*">
<xsl:call-template name="apply-template-in-new-table-cell">
<xsl:with-param name="current-state" select="$current-state"/>
</xsl:call-template>
</xsl:for-each>
</tr>
</xsl:otherwise>
</xsl:choose>
</table>
</td>
</tr>
</table>
</xsl:template>
<xsl:template name="apply-template-in-new-table-cell">
<xsl:param name="current-state"/>
<xsl:choose>
<xsl:when test="local-name()='not' or local-name()='and' or local-name()='or'">
<td>
<xsl:apply-templates select=".">
<xsl:with-param name="current-state" select="$current-state"/>
</xsl:apply-templates>
</td>
</xsl:when>
<xsl:otherwise>
<td class="pseudo-code-cell">
<xsl:apply-templates select=".">
<xsl:with-param name="current-state" select="$current-state"/>
</xsl:apply-templates>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="xabsl:else-if | xabsl:if">
<xsl:param name="current-state"/>
<xsl:param name="id-string"/>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr id="{$id-string}_{count(preceding-sibling::xabsl:else-if | preceding-sibling::xabsl:if)}">
<td colspan="4" class="pseudo-code-cell">
<xsl:for-each select="xabsl:condition">
<span class="italic">/** <xsl:value-of select="@description"/> */</span>
</xsl:for-each>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td class="pseudo-code-left-bracket" nowrap="nowrap">
<span class="bold">
<xsl:if test="local-name()='if'">if</xsl:if>
<xsl:if test="local-name()='else-if'">else if</xsl:if>
</span>&#160;(
</td>
<xsl:for-each select="xabsl:condition">
<xsl:for-each select="xabsl:*">
<xsl:call-template name="apply-template-in-new-table-cell">
<xsl:with-param name="current-state" select="$current-state"/>
</xsl:call-template>
</xsl:for-each>
</xsl:for-each>
<td class="pseudo-code-right-bracket">)</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">{</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="4">
<table cellpadding="0" cellspacing="0">
<tr>
<td class="pseudo-code-cell" nowrap="nowrap">&#160;&#160;</td>
<td>
<table cellpadding="0" cellspacing="0">
<xsl:apply-templates>
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string">
<xsl:value-of select="$id-string"/>_<xsl:value-of select="count(preceding-sibling::xabsl:else-if | preceding-sibling::xabsl:if)"/>
</xsl:with-param>
</xsl:apply-templates>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<xsl:if test="ancestor-or-self::xabsl:common-decision-tree and count(following-sibling::xabsl:*)=0">
<xsl:variable name="index" select="count(preceding-sibling::xabsl:else-if | preceding-sibling::xabsl:if)+1"/>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">
<span class="bold">else</span>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">{</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="4">
<table cellpadding="0" cellspacing="0">
<tr>
<td class="pseudo-code-cell" nowrap="nowrap">&#160;&#160;</td>
<td>
<xsl:for-each select="ancestor::xabsl:option/xabsl:state[@name=$current-state]/xabsl:decision-tree">
<xsl:call-template name="pseudo-code">
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string"><xsl:value-of select="$id-string"/>_<xsl:value-of select="$index"/></xsl:with-param>
</xsl:call-template>
</xsl:for-each>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</xsl:if>
</xsl:template>
<xsl:template match="xabsl:else">
<xsl:param name="current-state"/>
<xsl:param name="id-string"/>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">
<span class="bold">else</span>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">{</td>
</tr>
</table>
</td>
</tr>
<tr>
<td colspan="4">
<table cellpadding="0" cellspacing="0">
<tr>
<td class="pseudo-code-cell" nowrap="nowrap">&#160;&#160;</td>
<td>
<table cellpadding="0" cellspacing="0">
<xsl:apply-templates>
<xsl:with-param name="current-state" select="$current-state"/>
<xsl:with-param name="id-string"><xsl:value-of select="$id-string"/>_<xsl:value-of select="count(preceding-sibling::xabsl:else-if | preceding-sibling::xabsl:if)"/></xsl:with-param>
</xsl:apply-templates>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td colspan="4" class="pseudo-code-cell">}</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:transition-to-state">
<xsl:param name="current-state"/>
<tr>
<xsl:choose>
<xsl:when test="not(ancestor-or-self::xabsl:common-decision-tree) and @ref=$current-state">
<td class="pseudo-code-cell">stay;</td>
</xsl:when>
<xsl:otherwise>
<td class="pseudo-code-cell">goto <a href="#state_{@ref}">
<xsl:value-of select="@ref"/>
</a>;
</td>
</xsl:otherwise>
</xsl:choose>
</tr>
</xsl:template>
<xsl:template match="xabsl:condition"/>
<xsl:template match="xabsl:or | xabsl:and">
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td class="pseudo-code-left-bracket" nowrap="nowrap">(</td>
<xsl:for-each select="xabsl:*[1]">
<xsl:call-template name="apply-template-in-new-table-cell"/>
</xsl:for-each>
<td class="pseudo-code-right-bracket">)</td>
</tr>
</table>
</td>
</tr>
<xsl:for-each select="xabsl:*[position()>1]">
<tr>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td nowrap="nowrap" class="pseudo-code-cell">
<xsl:choose>
<xsl:when test="local-name(..)='or'">||&#160;</xsl:when>
<xsl:when test="local-name(..)='and'">&amp;&amp;&#160;</xsl:when>
</xsl:choose>
</td>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td class="pseudo-code-left-bracket" nowrap="nowrap">(</td>
<xsl:call-template name="apply-template-in-new-table-cell"/>
<td valign="bottom" class="pseudo-code-right-bracket" nowrap="nowrap">)</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</xsl:for-each>
</table>
</xsl:template>
<xsl:template match="xabsl:not">
<table cellpadding="0" cellspacing="0">
<tr>
<td class="pseudo-code-left-bracket" nowrap="nowrap">!(</td>
<xsl:for-each select="xabsl:*[1]">
<xsl:call-template name="apply-template-in-new-table-cell"/>
</xsl:for-each>
<td class="pseudo-code-right-bracket">)</td>
</tr>
</table>
</xsl:template>
<xsl:template match="xabsl:equal-to | xabsl:not-equal-to | xabsl:less-than | xabsl:less-than-or-equal-to | xabsl:greater-than | xabsl:greater-than-or-equal-to | xabsl:enumerated-input-symbol-comparison">
<xsl:apply-templates select="xabsl:*[1]"/>
<span class="nowrap">
<xsl:choose>
<xsl:when test="local-name()='equal-to'"> == </xsl:when>
<xsl:when test="local-name()='not-equal-to'"> != </xsl:when>
<xsl:when test="local-name()='less-than'"> &lt; </xsl:when>
<xsl:when test="local-name()='less-than-or-equal-to'"> &lt; </xsl:when>
<xsl:when test="local-name()='greater-than'"> > </xsl:when>
<xsl:when test="local-name()='greater-than-or-equal-to'"> >= </xsl:when>
<xsl:when test="local-name()='enumerated-input-symbol-comparison'"> == </xsl:when>
</xsl:choose>
<xsl:apply-templates select="xabsl:*[2]"/>
</span>
</xsl:template>
<xsl:template match="xabsl:plus | xabsl:minus | xabsl:multiply | xabsl:divide | xabsl:mod">(<xsl:apply-templates select="xabsl:*[1]"/>
<span class="nowrap">
<xsl:choose>
<xsl:when test="local-name()='plus'"> + </xsl:when>
<xsl:when test="local-name()='minus'"> - </xsl:when>
<xsl:when test="local-name()='multiply'"> * </xsl:when>
<xsl:when test="local-name()='divide'"> / </xsl:when>
<xsl:when test="local-name()='mod'"> % </xsl:when>
</xsl:choose>
<xsl:apply-templates select="xabsl:*[2]"/>)</span>
</xsl:template>
<xsl:template match="xabsl:decimal-input-symbol-ref">
<a href="symbols.{key('decimal-input-symbols',@ref)/../@id}.html#{@ref}" title="{key('decimal-input-symbols',@ref)/@description}">
<xsl:value-of select="@ref"/>
</a>(<xsl:for-each select="xabsl:with-parameter">
<span class="nowrap">
<xsl:apply-templates/>
<xsl:if test="count(following-sibling::xabsl:*)>0">, </xsl:if>
</span>
</xsl:for-each>)
</xsl:template>
<xsl:template match="xabsl:boolean-input-symbol-ref">
<a href="symbols.{key('boolean-input-symbols',@ref)/../@id}.html#{@ref}" title="{key('boolean-input-symbols',@ref)/@description}">
<xsl:value-of select="@ref"/>
</a>(<xsl:for-each select="xabsl:with-parameter">
<span class="nowrap">
<xsl:apply-templates/>
<xsl:if test="count(following-sibling::xabsl:*)>0">, </xsl:if>
</span>
</xsl:for-each>)
</xsl:template>
<xsl:template match="xabsl:enumerated-input-symbol-ref">
<a href="symbols.{key('enumerated-input-symbols',@ref)/../@id}.html#{@ref}" title="{key('enumerated-input-symbols',@ref)/@description}">
<xsl:value-of select="@ref"/>
</a>(<xsl:for-each select="xabsl:with-parameter">
<span class="nowrap">
<xsl:apply-templates/>
<xsl:if test="count(following-sibling::xabsl:*)>0">, </xsl:if>
</span>
</xsl:for-each>)
</xsl:template>
<xsl:template match="xabsl:decimal-output-symbol-ref">
<a href="symbols.{key('decimal-output-symbols',@ref)/../@id}.html#{@ref}" title="{key('decimal-output-symbols',@ref)/@description}">
<xsl:value-of select="@ref"/>
</a>
</xsl:template>
<xsl:template match="xabsl:boolean-output-symbol-ref">
<a href="symbols.{key('boolean-output-symbols',@ref)/../@id}.html#{@ref}" title="{key('boolean-output-symbols',@ref)/@description}">
<xsl:value-of select="@ref"/>
</a>
</xsl:template>
<xsl:template match="xabsl:enumerated-output-symbol-ref">
<a href="symbols.{key('enumerated-output-symbols',@ref)/../@id}.html#{@ref}" title="{key('enumerated-output-symbols',@ref)/@description}">
<xsl:value-of select="@ref"/>
</a>
</xsl:template>
<xsl:template match="xabsl:constant-ref">
<a href="symbols.{key('constants',@ref)/../@id}.html#{@ref}" title="{key('constants',@ref)/@description} ({key('constants',@ref)/@value})">
<xsl:value-of select="@ref"/>
</a>
</xsl:template>
<xsl:template match="xabsl:conditional-expression">(<xsl:for-each select="xabsl:condition">
<xsl:apply-templates/>
</xsl:for-each>?<xsl:for-each select="xabsl:expression1">
<xsl:apply-templates/>
</xsl:for-each>:<xsl:for-each select="xabsl:expression2">
<xsl:apply-templates/>
</xsl:for-each>)</xsl:template>
<xsl:template match="xabsl:option-parameter-ref">
<xsl:variable name="option-name" select="ancestor::xabsl:option/@name"/>
<xsl:variable name="ref" select="@ref"/>@<a href="option.{ancestor::xabsl:option/@name}.html" title="Option parameter {@ref}: {ancestor::xabsl:option/xabsl:option-definitions/xabsl:option-definition[@name=$option-name]/xabsl:parameter[@name=$ref]/@description}">
<xsl:value-of select="@ref"/>
</a>
</xsl:template>
<xsl:template match="xabsl:decimal-value">
<xsl:value-of select="@value"/>
</xsl:template>
<xsl:template match="xabsl:boolean-value">
<xsl:value-of select="@value"/>
</xsl:template>
<xsl:template match="xabsl:enum-element-ref">
<xsl:value-of select="@ref"/>
</xsl:template>
<xsl:template match="xabsl:subsequent-option-reached-target-state">action_done</xsl:template>
<xsl:template match="xabsl:time-of-state-execution">state_time</xsl:template>
<xsl:template match="xabsl:time-of-option-execution">option_time</xsl:template>
<xsl:template match="xabsl:*" priority="-10000">
<xsl:value-of select="local-name()"/>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:template name="replace-in-string">
<!-- A nice template for "search and replace" on strings.
Parameter original-string: the string to process
Parameter replace: the expression to be replaced.
Parameter with: the new string.
Example: original-string: "1+3+6=10", replace: "+", with: "-" returns "1-3-6=10". -->
<xsl:param name="original-string"/>
<xsl:param name="replace"/>
<xsl:param name="with"/>
<xsl:variable name="string-before-replace-pattern" select="substring-before($original-string,$replace)"/>
<xsl:choose>
<xsl:when test="string-length($string-before-replace-pattern)=0">
<xsl:value-of select="$original-string"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$string-before-replace-pattern"/>
<xsl:value-of select="$with"/>
<xsl:call-template name="replace-in-string">
<xsl:with-param name="original-string" select="substring-after($original-string,$replace)"/>
<xsl:with-param name="replace" select="$replace"/>
<xsl:with-param name="with" select="$with"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="add-line-breaks">
<!-- A template that adds "\n" line breaks to a string after a minimum length of characters.
Parameter original-string: the string to process
Parameter min-length: the minimum length after that a line break is inserted
Example: original-string: "Tom doesn't like to eat cats", min-length: "10" returns "Tom doesn't\nlike to eat\ncats."-->
<xsl:param name="original-string"/>
<xsl:param name="min-length"/>
<xsl:variable name="first-sub-string" select="substring-before($original-string,substring($original-string,$min-length+1))"/>
<xsl:if test="string-length($first-sub-string)=0">
<xsl:value-of select="$original-string"/>
</xsl:if>
<xsl:if test="string-length($first-sub-string)>0">
<xsl:variable name="second-sub-string" select="substring-before(substring($original-string,$min-length+1),' ')"/>
<xsl:variable name="third-sub-string" select="substring-after(substring($original-string,$min-length+1),' ')"/>
<xsl:if test="string-length($third-sub-string)=0">
<xsl:value-of select="$original-string"/>
</xsl:if>
<xsl:if test="string-length($third-sub-string)>0">
<xsl:value-of select="$first-sub-string"/>
<xsl:value-of select="$second-sub-string"/>\n<xsl:call-template name="add-line-breaks">
<xsl:with-param name="original-string" select="$third-sub-string"/>
<xsl:with-param name="min-length" select="$min-length"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de" xmlns:dotml="http://www.martin-loetzsch.de/DOTML">
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="html" indent="yes"/>
<xsl:key name="symbols" match="xabsl:agent-collection/xabsl:options/xabsl:option/xabsl:symbols" use="@id"/>
<xsl:template match="xabsl:agent-collection">
<html>
<head>
<title>XABSL Behavior Documentation: Symbols</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index-linked"/>
<xsl:call-template name="menu-entry-agents-linked"/>
<xsl:call-template name="menu-entry-symbols"/>
<xsl:call-template name="menu-symbols"/>
<xsl:call-template name="menu-entry-basic-behaviors-linked"/>
<xsl:call-template name="menu-entry-options-linked"/>
</table>
</td>
<td class="main-area">
<h1>Symbols</h1>
<table border="0" cellpadding="4" cellspacing="0">
<xsl:for-each select="xabsl:options/xabsl:option/xabsl:symbols[count(key('symbols',@id)[1] | .)=1]">
<tr>
<td class="bold">
<div class="nowrap">
<a href="symbols.{@id}.html" title="{@description}">
<xsl:value-of select="@title"/>
</a>
</div>
</td>
<td>
<xsl:value-of select="@description"/>
<br/>
<br/>
<div class="menu-item">
<xsl:for-each select="xabsl:*">
<a href="symbols.{../@id}.html#{@name}" title="{@description}">
<span class="nowrap">
<xsl:value-of select="@name"/>
</span>
</a>&#160;&#160;&#160; </xsl:for-each>
</div>
</td>
</tr>
<tr>
<td>&#160;</td>
</tr>
</xsl:for-each>
</table>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,238 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:import href="generate-documentation.parameters.xsl"/>
<xsl:import href="generate-documentation.menu.xsl"/>
<xsl:output method="html" indent="yes"/>
<xsl:template match="xabsl:symbols">
<html>
<head>
<title>XABSL Behavior Documentation: <xsl:value-of select="@title"/>
</title>
<link rel="stylesheet" type="text/css" href="styles.css">
<xsl:text> </xsl:text>
</link>
</head>
<body>
<table border="0" cellpadding="0" cellspacing="0">
<tr>
<td class="menu-cell">
<table border="0" cellspacing="0" cellpadding="1">
<xsl:call-template name="menu-xabsl2-logo"/>
<xsl:call-template name="menu-entry-index-linked"/>
<xsl:call-template name="menu-entry-agents-linked"/>
<xsl:call-template name="menu-entry-symbols-linked"/>
<xsl:call-template name="menu-symbol"/>
<xsl:call-template name="menu-entry-basic-behaviors-linked"/>
<xsl:call-template name="menu-entry-options-linked"/>
</table>
</td>
<td class="main-area">
<h1>
<xsl:value-of select="@title"/>
</h1>
<p>
<xsl:value-of select="@description"></xsl:value-of>
</p>
<p>The formalized behavior references a variety of input and output symbols, which can stand for variables or functions of the agent's software. Constants are constant decimal values.</p>
<xsl:if test="xabsl:enumeration">
<h2 id="enumerations">Enumerations</h2>
<table border="0" cellpadding="0" cellspacing="6">
<tr>
<td class="tablehead">Name</td>
<td class="tablehead">Elements</td>
<td class="tablehead">Internal</td>
<td class="tablehead">Description</td>
</tr>
<xsl:apply-templates select="xabsl:enumeration"/>
</table>
</xsl:if>
<xsl:if test="xabsl:decimal-input-symbol | xabsl:boolean-input-symbol | xabsl:enumerated-input-symbol">
<h2 id="input-symbols">Input Symbols</h2>
<table border="0" cellpadding="0" cellspacing="6">
<tr>
<td class="tablehead">Name</td>
<td class="tablehead">Type</td>
<td class="tablehead">Measure</td>
<td class="tablehead">Description / Parameters</td>
</tr>
<xsl:apply-templates select="xabsl:decimal-input-symbol | xabsl:boolean-input-symbol | xabsl:enumerated-input-symbol"/>
</table></xsl:if>
<xsl:if test="xabsl:decimal-output-symbol | xabsl:boolean-output-symbol | xabsl:enumerated-output-symbol">
<h2 id="output-symbols">Output Symbols</h2>
<table border="0" cellpadding="0" cellspacing="6">
<tr>
<td class="tablehead">Name</td>
<td class="tablehead">Type</td>
<td class="tablehead">Measure</td>
<td class="tablehead">Internal</td>
<td class="tablehead">Description</td>
</tr>
<xsl:apply-templates select="xabsl:decimal-output-symbol | xabsl:boolean-output-symbol | xabsl:enumerated-output-symbol"/>
</table>
</xsl:if>
<xsl:if test="xabsl:constant">
<h2 id="constants">Constants</h2>
<table border="0" cellpadding="0" cellspacing="6">
<tr>
<td class="tablehead">Name</td>
<td class="tablehead">Value</td>
<td class="tablehead">Measure</td>
<td class="tablehead">Description</td>
</tr>
<xsl:apply-templates select="xabsl:constant"/>
</table>
</xsl:if>
</td>
</tr>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="xabsl:enumeration">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td class="italic">
<xsl:for-each select="xabsl:enum-element">
<xsl:value-of select="@name"/>
<br/>
</xsl:for-each>
</td>
<td>
<xsl:value-of select="@internal"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:decimal-input-symbol">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>decimal</td>
<td class="italic">
<xsl:value-of select="@measure"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
<tr>
<td colspan="3">&#160;</td>
<td>
<xsl:call-template name="parameters"/>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:boolean-input-symbol">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>boolean</td>
<td class="italic">true/ false</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
<tr>
<td colspan="3">&#160;</td>
<td>
<xsl:call-template name="parameters"/>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:decimal-output-symbol">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>decimal</td>
<td class="italic">
<xsl:value-of select="@measure"/>
</td>
<td>
<xsl:value-of select="@internal"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:boolean-output-symbol">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>boolean</td>
<td class="italic">true/ false</td>
<td>
<xsl:value-of select="@internal"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:enumerated-input-symbol">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>enumerated</td>
<td class="bold">
<xsl:value-of select="@enumeration"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
<tr>
<td colspan="3">&#160;</td>
<td>
<xsl:call-template name="parameters"/>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:enumerated-output-symbol">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>enumerated</td>
<td class="bold">
<xsl:value-of select="@enumeration"/>
</td>
<td>
<xsl:value-of select="@internal"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:template>
<xsl:template match="xabsl:constant">
<tr id="{@name}">
<td class="bold">
<xsl:value-of select="@name"/>
</td>
<td>
<xsl:value-of select="@value"/>
</td>
<td class="italic">
<xsl:value-of select="@measure"/>
</td>
<td>
<xsl:value-of select="@description"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns="http://www.w3.org/1999/xhtml" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xabsl="http://www.xabsl.de">
<xsl:template match="*" priority="-1000">
<xsl:copy>
<xsl:copy-of select="./@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()" priority="-1000">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="comment()">
<!-- the aim of this stylesheet is to remove all comments from a xml file and to reproduce the rest of it. -->
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,84 @@
/*===========================================================================
MyBasicBehaviors.h
Implementation of all basic behaviors.
author: Martin Lötzsch
===========================================================================*/
#include "MyBasicBehaviors.h"
void BasicBehaviorGetBehindBall::execute()
{
int ballLocalDirection = worldState.getBallLocalDirection();
switch(ballLocalDirection)
{
case -1: action=worldState.ball_direction[worldState.activePlayerNumber]; break;
case E:
if (worldState.y[worldState.activePlayerNumber] < 11) action=SE;
else action=NE;
break;
case SE: action=E; break;
case NE: action=E; break;
case N:
if (worldState.local_area[NE][worldState.activePlayerNumber] == EMPTY) action=NE;
else action = E;
break;
case S:
if (worldState.local_area[SE][worldState.activePlayerNumber] == EMPTY) action=SE;
else action = E;
break;
action=SE; break;
case SW: action=S; break;
case NW: action=N; break;
case W: action=W; break;
case PLAYER: action=E; break;
}
}
void BasicBehaviorGoTo::execute()
{
int _x=(int)x, _y=(int)y;
if (_x<1) _x=1; if (_x>78) _x=78; if (_y>21) _y=21; if (_y<1) _y=1;
if (_x<worldState.ball_x && _y==worldState.ball_y) if (_y <11) _y++; else _y--;
int dx = _x - worldState.x[worldState.activePlayerNumber], dy = _y - worldState.y[worldState.activePlayerNumber];
if (dy < 0)
{
if (dx >= 0 || abs(dx) < abs(dy)) action=NE;
else action=NW;
}
else if (dy > 0)
{
if (dx >= 0 || abs(dx) < abs(dy)) action=SE;
else action=SW;
}
else // dy == 0
{
if (dx>0) action = E;
else if (dx<0) action = W;
else action = DO_NOTHING;
}
if (worldState.local_area[action][worldState.activePlayerNumber] != EMPTY)
{
switch (action)
{
case N: action=NE; break;
case NE: action=E; break;
case E: action=(worldState.y[worldState.activePlayerNumber]<11?SE:NE); break;
case SE: action=E; break;
case S: action=SE; break;
case SW: action=S; break;
case W: action=W; break;
case NW: action=N; break;
}
}
if (worldState.local_area[action][worldState.activePlayerNumber] != EMPTY) action=DO_NOTHING;
}

View File

@ -0,0 +1,65 @@
/*===========================================================================
MyBasicBehaviors.h
Definition of all basic behaviors.
author: Martin Lötzsch
===========================================================================*/
#ifndef __MyBasicBehaviors_h_
#define __MyBasicBehaviors_h_
#include "../Xabsl/XabslEngine/XabslBasicBehavior.h"
#include "WorldState.h"
#include "../ascii-soccer/soccer.h"
class BasicBehaviorGetBehindBall : public xabsl::BasicBehavior
{
public:
BasicBehaviorGetBehindBall(xabsl::ErrorHandler& errorHandler,
WorldState& worldState, int& action)
: xabsl::BasicBehavior("get_behind_ball",errorHandler),
worldState(worldState),
action(action)
{
}
virtual void execute();
private:
WorldState& worldState; // the world state on that the action is based
int& action; // the action to be generated
};
class BasicBehaviorGoTo : public xabsl::BasicBehavior
{
public:
double x,y; // the parameters of the basic behavior
BasicBehaviorGoTo(xabsl::ErrorHandler& errorHandler,
WorldState& worldState, int& action)
: xabsl::BasicBehavior("go_to",errorHandler),
worldState(worldState),
action(action)
{
}
virtual void registerParameters()
{
// as basic behaviors are shared among engines for all players this is called more than once
// register parameters only if they are not already registered
if (!parameters->decimal.exists("go_to.x"))
{
parameters->registerDecimal("go_to.x",x);
parameters->registerDecimal("go_to.y",y);
}
}
virtual void execute();
private:
WorldState& worldState; // the world state on that the action is based
int& action; // the action to be generated
};
#endif //__MyBasicBehaviors_h_

View File

@ -0,0 +1,81 @@
/*===========================================================================
Tools.h
Adapts the xabsl::Engine to the target platform.
author: Martin Lötzsch
===========================================================================*/
#ifndef __Tools_h_
#define __Tools_h_
#include <fstream>
#include <sys/timeb.h>
// An error handling class derived from xabsl::ErrorHandler
class MyErrorHandler : public xabsl::ErrorHandler
{
public:
MyErrorHandler() { logfile.open("messages.log"); }
~MyErrorHandler() { logfile.close(); }
virtual void printError(const char* text)
{logfile << "error: " << text << "\n"; logfile.flush();}
virtual void printMessage(const char* text)
{logfile << text << "\n"; logfile.flush();}
private:
std::ofstream logfile;
};
// A file access class derived from xabsl::InputSource
class MyFileInputSource : public xabsl::InputSource
{
public:
MyFileInputSource(const char* fileName) : file(0), theChar(' ')
{ strcpy(filename,fileName); }
~MyFileInputSource() {if (file!=0) delete file;}
virtual bool open() {file = new std::ifstream(filename); return(file!=0 && !file->fail());}
virtual void close() {if (file!=0) delete file; file = 0;}
virtual double readValue()
{ char buf[20]; readFromFile(buf); return atof(buf); }
virtual bool readString(char* destination, int maxLength)
{ readFromFile(destination); return true; }
private:
char filename[200]; // the file name
std::ifstream* file; // the file to access
char theChar; // the last character read
void readFromFile(char* value)
{
while(!file->eof() && isWhitespace())
{
if (theChar == '/') while(!file->eof() && theChar != '\n') file->read(&theChar,1);
file->read(&theChar,1);
}
while(!file->eof() && !isWhitespace())
{ *value++ = theChar; if(!file->eof()) file->read(&theChar,1); }
*value = 0;
}
bool isWhitespace()
{ return theChar == ' ' || theChar == '/' || theChar == '\n' || theChar == '\r' || theChar == '\t'; }
};
// returns the current system time in milliseconds
static unsigned getCurrentSystemTime() {
timeb sysTime;
ftime(&sysTime);
return (sysTime.time * 1000 + sysTime.millitm);
}
#endif //__Tools_h_

View File

@ -0,0 +1,224 @@
/*===========================================================================
WorldState.cpp
The class WorldState represents the knowledge of an agent.
author: Martin Lötzsch
===========================================================================*/
#include "WorldState.h"
WorldState* WorldState::theInstance = NULL;
WorldState::WorldState() : activePlayerNumber(0), ball_x(40), ball_y(10)
{
theInstance = this;
}
void WorldState::update(int playerNumber, int _local_area[9], int _ball_direction, int _x, int _y)
{
int i, j, k;
// set the active player
activePlayerNumber = playerNumber;
// copy new values
for (j=0; j<9; j++) local_area[j][activePlayerNumber] = _local_area[j];
ball_direction[activePlayerNumber] = _ball_direction;
x[activePlayerNumber] = _x; y[activePlayerNumber] = _y;
// estimate the ball position: fill "field" with the number of players that see the ball for each field element
for (i=0;i<MAX_Y;i++) for (j=0;j<MAX_X;j++) field[j][i] = 0;
double temp_angle; int temp_dir;
for (i=1;i<MAX_Y-1;i++) for (j=1;j<MAX_X-1;j++) for (k=3; k>=0; k--)
{
if ((j == x[k]) && (i == y[k])) temp_angle = 0;
else temp_angle = atan2((j - x[k]), (i - y[k]));
temp_angle += PI;
temp_angle = 360.0*temp_angle/(2.0*PI);
temp_dir = N;
if (temp_angle > 22.5+0*45) temp_dir = NW;
if (temp_angle > 22.5+1*45) temp_dir = W;
if (temp_angle > 22.5+2*45) temp_dir = SW;
if (temp_angle > 22.5+3*45) temp_dir = S;
if (temp_angle > 22.5+4*45) temp_dir = SE;
if (temp_angle > 22.5+5*45) temp_dir = E;
if (temp_angle > 22.5+6*45) temp_dir = NE;
if (temp_angle > 22.5+7*45) temp_dir = N;
if (temp_dir == ball_direction[k]) field[j][i] += 1;
}
// estimate the ball position: search for peaks:
int sum_x=0, sum_y=0, num_fields=0;
for (i=1;i<MAX_Y-1;i++) for (j=1;j<MAX_X-1;j++) if (field[j][i]==4) { sum_x += j; sum_y += i; num_fields++; }
if (num_fields!=0) { ball_x=sum_x / num_fields; ball_y=sum_y / num_fields; }
else
{
for (i=1;i<MAX_Y-1;i++) for (j=1;j<MAX_X-1;j++) if (field[j][i]==3) { sum_x += j; sum_y += i; num_fields++;}
if (num_fields!=0) { ball_x=sum_x / num_fields; ball_y=sum_y / num_fields; }
}
// check if the ball is in the local area of a player
for (i=3; i>=0; i--)
{
if (local_area[N][i] == BALL) { ball_x=x[i]; ball_y=y[i]-1; }
if (local_area[NE][i] == BALL) { ball_x=x[i]+1; ball_y=y[i]-1; }
if (local_area[E][i] == BALL) { ball_x=x[i]+1; ball_y=y[i]; }
if (local_area[SE][i] == BALL) { ball_x=x[i]+1; ball_y=y[i]+1; }
if (local_area[S][i] == BALL) { ball_x=x[i]; ball_y=y[i]+1; }
if (local_area[SW][i] == BALL) { ball_x=x[i]-1; ball_y=y[i]+1; }
if (local_area[W][i] == BALL) { ball_x=x[i]-1; ball_y=y[i]; }
if (local_area[NW][i] == BALL) { ball_x=x[i]-1; ball_y=y[i]-1; }
}
}
void WorldState::computeRoles()
{
int i,j;
double ball_distances[4];
int min_dist = 0;
int rank[4] = {0,1,2,3};
for (i=0;i<4;i++) ball_distances[i]=sqrt(pow(x[i] - ball_x,2) + pow(y[i] - ball_y,2));
for (i=0; i<4; i++) {
if (ball_distances[i] < ball_distances[min_dist]) {
min_dist = i;
}
}
int temp = rank[0];
rank[0] = min_dist;
rank[min_dist] = temp;
for (i=1; i<3; i++) {
for (j=i+1;j<4;j++) {
if (x[rank[i]] < x[rank[j]]) {
int temp = rank[i];
rank[i] = rank[j];
rank[j] = temp;
}
}
}
playerRole[rank[0]] = WorldState::midfielder;
playerRole[rank[1]] = WorldState::defender;
playerRole[rank[2]] = WorldState::midfielder; // substitute by role 'runner'
playerRole[rank[3]] = WorldState::striker;
for (i=0;i<4;i++) if (x[i] >73) playerRole[i]=WorldState::midfielder;
}
double WorldState::getMostWesterlyTeammateX()
{
double minX=78;
for (int player=1;player<4;player++) if (theInstance->x[player] < minX) minX = theInstance->x[player];
return minX;
}
double WorldState::getMostWesterlyTeammateY()
{
double minX=78;
double Y=22;
for (int player=1;player<4;player++) {
if (theInstance->x[player] < minX) {
minX = theInstance->x[player]; // x coordinate of most westerly team mate
Y = theInstance->y[player]; // y coordinate of most westerly team mate
}
}
return Y;
}
int WorldState::getBallLocalDirection()
{
for (int i=0;i<10;i++) if (theInstance->local_area[i][theInstance->activePlayerNumber]==BALL) return i;
return -1;
}
double WorldState::getBallDistance()
{
if (getBallLocalDirection()!=-1)
return 1;
else
return sqrt(pow(theInstance->x[theInstance->activePlayerNumber] - theInstance->ball_x,2) + pow(theInstance->y[theInstance->activePlayerNumber] - theInstance->ball_y,2));
}
int WorldState::getPlayerRole()
{
return theInstance->playerRole[theInstance->activePlayerNumber];
}
void WorldState::printField(xabsl::ErrorHandler& errorHandler)
{
int i,j;
field[(int)ball_x][(int)ball_y] = 5;
for (i=0;i<4;i++)
field[x[i]][y[i]] = playerRole[i] + ((i==activePlayerNumber) ? 6 : 10);
errorHandler.message("===============================================================================");
for (i=1;i<22;i++)
{
char line[80];
for (j=1;j<=78;j++)
{
line[0]='|';
char c;
switch ((char)field[j][i])
{
case 0: c=' '; break;
case 1: c='-'; break;
case 2: c='='; break;
case 3: c=':'; break;
case 4: c='*'; break;
case 5: c='o'; break;
case 6: c='D'; break;
case 7: c='M'; break;
case 8: c='S'; break;
case 9: c='R'; break;
case 10: c='d'; break;
case 11: c='m'; break;
case 12: c='s'; break;
case 13: c='r'; break;
default: c='.'; break;
}
line[j]=c;
}
line[79]=0;
errorHandler.message("%s",line);
}
errorHandler.message("===============================================================================");
}
void WorldState::reset()
{
for(int i = 0; i <4; i++)
{
x[i] = 46;
y[i] = 4+3*i;
for (int j=0; j<9; j++) local_area[j][i] = EMPTY;
ball_direction[i]=W;
}
}
double WorldState::getX()
{
return (double)theInstance->x[theInstance->activePlayerNumber];
}
double WorldState::getY()
{
return (double)theInstance->y[theInstance->activePlayerNumber];
}
double WorldState::getBallX()
{
return (double)theInstance->ball_x;
}
double WorldState::getBallY()
{
return (double)theInstance->ball_y;
}

View File

@ -0,0 +1,93 @@
/*===========================================================================
WorldState.h
The class WorldState represents the knowledge of all agents.
author: Martin Lötzsch
===========================================================================*/
#ifndef __WorldState_h_
#define __WorldState_h_
#include "../Xabsl/XabslEngine/XabslSymbols.h"
#include "../ascii-soccer/soccer.h"
class WorldState
{
public:
WorldState();
// the player indexing works like a ring buffer.
// E.g. x[0] is for the active player, x[1] for the previously active player etc.
/*
local_area[] Reveals what's nearby. Indexed by
N,NE,E,SE,S, etc. so that, for example,
local_area[S] tells you what is in the
cell to the south of the robot. Possible
values include: BOUNDARY, OPPONENT, TEAMMATE,
BALL and EMPTY. */
int local_area[9][4];
/* ball_direction Compass heading to the ball: N, S, E, W, NE, etc. */
int ball_direction[4];
/* x, y The robot's location. y varies from 1 to 22,
x varies from 1 to 78. */
int x[4];
int y[4];
// the position of the ball, estimated from observations by all four players.
int ball_x, ball_y;
// the number of the active player (0..3)
int activePlayerNumber;
/* updates the world state for a single player */
void update(int playerNumber, int local_area[9], int ball_direction, int x, int y);
/* computes the dynamic roles */
void computeRoles();
void reset(); // resets the positions
static WorldState* theInstance;
/* the dynamically assigned player role */
enum PlayerRole { defender, midfielder, striker, runner } playerRole[4];
static double getX(); // a function for the symbol "x"
static double getY(); // a function for the symbol "y"
static double getBallX(); // a function for the symbol "ball.x"
static double getBallY(); // a function for the symbol "ball.y"
static double getBallDistance(); // a function for the symbol "ball.distance"
static int getBallLocalDirection(); // a function for the symbol "ball.local.direction"
static double getMostWesterlyTeammateX(); // a function for the symbol "most-westerly-teammate.x"
static double getMostWesterlyTeammateY(); // a function for the symbol "most-westerly-teammate.y"
static int getPlayerRole(); // a function for the symbol "player-role"
char field[MAX_X][MAX_Y]; // for debug output
void printField(xabsl::ErrorHandler& errorHandler); // prints the field containing debug informations
};
#endif //__WorldState_h_

View File

@ -0,0 +1,18 @@
/*===========================================================================
common.c
Put routines in here that don't need unique names. You might
want to share these routines if your team is playing against
itself. You may not need to put anything in this file.
Tucker Balch tucker@cc.gatech.edu
===========================================================================*/
#include "players.h"
void dummyrandomname()
{
}

View File

@ -0,0 +1,258 @@
/*===========================================================================
main.cpp
Initializes and executes the four XABSL engines.
author: Martin Lötzsch
===========================================================================*/
#include "players.h"
#include "soccer.h"
#include "WorldState.h"
#include "MyBasicBehaviors.h"
#include "Tools.h"
#include "../Xabsl/XabslEngine/XabslEngine.h"
// an instance of the derived error handler
MyErrorHandler myErrorHandler;
// the world state that is shared by all players
WorldState worldState;
// the next action to be generated by the active agent
int nextAction;
// an xabsl engine for each of the four players
xabsl::Engine* pEngine[4];
// instances of the basic behaviors
BasicBehaviorGetBehindBall basicBehaviorGetBehindBall(myErrorHandler, worldState, nextAction);
BasicBehaviorGoTo basicBehaviorGoTo(myErrorHandler, worldState, nextAction);
void UN(initialize_game)()
{
// create four engines
for (int i=0; i<4;i++)
{
// create the engine
pEngine[i] = new xabsl::Engine(myErrorHandler, &getCurrentSystemTime);
// register basic behaviors
pEngine[i]->registerBasicBehavior(basicBehaviorGetBehindBall);
pEngine[i]->registerBasicBehavior(basicBehaviorGoTo);
// register the symbols
pEngine[i]->registerEnumeratedInputSymbol("role", "role", &WorldState::getPlayerRole);
pEngine[i]->registerEnumElement("role", "role.striker", WorldState::striker);
pEngine[i]->registerEnumElement("role", "role.defender", WorldState::defender);
pEngine[i]->registerEnumElement("role", "role.midfielder", WorldState::midfielder);
pEngine[i]->registerEnumeratedOutputSymbol("next_action", "next_action", &nextAction);
pEngine[i]->registerEnumElement("next_action", "next_action.undefined", -1);
pEngine[i]->registerEnumElement("next_action", "next_action.NW", NW);
pEngine[i]->registerEnumElement("next_action", "next_action.N", N);
pEngine[i]->registerEnumElement("next_action", "next_action.NE", NE);
pEngine[i]->registerEnumElement("next_action", "next_action.E", E);
pEngine[i]->registerEnumElement("next_action", "next_action.SE", SE);
pEngine[i]->registerEnumElement("next_action", "next_action.S", S);
pEngine[i]->registerEnumElement("next_action", "next_action.SW", SW);
pEngine[i]->registerEnumElement("next_action", "next_action.W", W);
pEngine[i]->registerEnumElement("next_action", "next_action.kick", KICK);
pEngine[i]->registerEnumElement("next_action", "next_action.do_nothing", DO_NOTHING);
pEngine[i]->registerDecimalInputSymbol("x", &WorldState::getX);
pEngine[i]->registerDecimalInputSymbol("y", &WorldState::getY);
pEngine[i]->registerDecimalInputSymbol("ball.x", &WorldState::getBallX);
pEngine[i]->registerDecimalInputSymbol("ball.y", &WorldState::getBallY);
pEngine[i]->registerDecimalInputSymbol("ball.distance", &WorldState::getBallDistance);
pEngine[i]->registerEnumeratedInputSymbol("ball.local.direction","next_action", &WorldState::getBallLocalDirection);
pEngine[i]->registerDecimalInputSymbol("most_westerly_teammate.x", &WorldState::getMostWesterlyTeammateX);
pEngine[i]->registerDecimalInputSymbol("most_westerly_teammate.y", &WorldState::getMostWesterlyTeammateY);
// parse the intermediate code
MyFileInputSource input("intermediate-code.dat");
pEngine[i]->createOptionGraph(input);
}
}
void printOptionActivationTree(xabsl::Engine& engine, xabsl::ErrorHandler& errorHandler);
int UN(player1)(int local_area[9], int ball_direction, int x, int y)
{
const char* actionStrings[] = {"NW","N","NE","W","","E","SW","S","SE","kick","do_nothing"};
if (!myErrorHandler.errorsOccurred)
{
worldState.update(0, local_area,ball_direction,x,y);
worldState.computeRoles();
pEngine[0]->execute();
printOptionActivationTree(*pEngine[0],myErrorHandler);
myErrorHandler.message("action = %s",actionStrings[nextAction]);
worldState.printField(myErrorHandler);
return nextAction;
}
else
{
return W;
}
}
int UN(player2)(int local_area[9], int ball_direction, int x, int y)
{
if (!myErrorHandler.errorsOccurred)
{
worldState.update(1, local_area,ball_direction,x,y);
pEngine[1]->execute();
return nextAction;
}
else
{
return W;
}
}
int UN(player3)(int local_area[9], int ball_direction, int x, int y)
{
if (!myErrorHandler.errorsOccurred)
{
worldState.update(2, local_area,ball_direction,x,y);
pEngine[2]->execute();
return nextAction;
}
else
{
return W;
}
}
int UN(player4)(int local_area[9], int ball_direction, int x, int y)
{
if (!myErrorHandler.errorsOccurred)
{
worldState.update(3, local_area,ball_direction,x,y);
pEngine[3]->execute();
return nextAction;
}
else
{
return W;
}
}
char *UN(team_name)()
{
char *s;
/* "####################\0" <--- 20 characters */
s = "XABSL Example Agents\0";
return(s);
}
void UN(initialize_point)()
{
worldState.reset();
}
void UN(lost_point)()
{
myErrorHandler.message("lost point");
}
void UN(won_point)()
{
myErrorHandler.message("won point");
}
void UN(game_over)()
{
// delete the four engines
for (int i=0; i<4;i++) if (pEngine[i]!=0) delete pEngine[i];
}
void printOptionActivationSubTree(int depth, const xabsl::Action* action, xabsl::ErrorHandler& errorHandler)
{
char string[300]; int i;
string[0]=0;
for (i=0;i<depth;i++) strcat(string," ");
if (const xabsl::Behavior* behavior = action->getBehavior())
{
strcat(string,behavior->n);
strcat(string,"(");
bool first=true;
for(i=0; i<action->getParameters()->decimalValues.getSize();i++)
{
if (!first) strcat(string,", ");
first = false;
sprintf(string+strlen(string),"%s=%.0f",action->getParameters()->decimalValues.getName(i), action->getParameters()->decimalValues[i]);
}
for(i=0; i<action->getParameters()->booleanValues.getSize();i++)
{
if (!first) strcat(string,", ");
first = false;
sprintf(string+strlen(string),"%s=%s",action->getParameters()->booleanValues.getName(i), action->getParameters()->booleanValues[i] ? "true" : "false");
}
for(i=0; i<action->getParameters()->enumeratedValues.getSize();i++)
{
if (!first) strcat(string,", ");
first = false;
strcat(string,action->getParameters()->enumeratedValues.getName(i));
strcat(string,"=");
const xabsl::Enumeration* enumeration = action->getParameters()->enumeratedExpressions[i]->enumeration;
for (int j = 0; j < enumeration->enumElements.getSize(); j++)
if (enumeration->enumElements[j]->v == action->getParameters()->enumeratedValues[i])
{
strcat(string, enumeration->enumElements[j]->n);
break;
}
}
strcat(string,")");
}
else if (const xabsl::DecimalOutputSymbol* decimalOutputSymbol = action->getDecimalOutputSymbol())
{
sprintf(string+strlen(string),"%s=%.0f",decimalOutputSymbol->n,action->getDecimalOutputSymbolValue());
}
else if (const xabsl::BooleanOutputSymbol* booleanOutputSymbol = action->getBooleanOutputSymbol())
{
sprintf(string+strlen(string),"%s=%s",booleanOutputSymbol->n,action->getBooleanOutputSymbolValue() ? "true" : "false");
}
else if (const xabsl::EnumeratedOutputSymbol* enumeratedOutputSymbol = action->getEnumeratedOutputSymbol())
{
strcat(string, enumeratedOutputSymbol->n);
strcat(string, "=");
const xabsl::Enumeration* enumeration = enumeratedOutputSymbol->enumeration;
for (int j = 0; j < enumeration->enumElements.getSize(); j++)
if (enumeration->enumElements[j]->v == action->getEnumeratedOutputSymbolValue())
{
strcat(string, enumeration->enumElements[j]->n);
break;
}
}
errorHandler.message("%s",string);
if (const xabsl::Option* option = action->getOption())
{
const xabsl::Array<xabsl::Action*>& actions =
option->activeState->actions;
for(i=0;i<actions.getSize();i++)
printOptionActivationSubTree(depth + 1, actions[i], errorHandler);
}
}
void printOptionActivationTree(xabsl::Engine& engine, xabsl::ErrorHandler& errorHandler)
{
errorHandler.message("\n\n\n\n");
const xabsl::Action* action = engine.getRootAction(0);
printOptionActivationSubTree(0, action, errorHandler);
}

View File

@ -0,0 +1,44 @@
XABSLFILES=$(shell echo `ls ../Xabsl/XabslEngine/ -c1 | grep .cpp` | sed "s%Xabsl%Build/Xabsl%g" | sed "s%\.cpp%.o%g")
all: Build/libeast.a Build/libcommon.a
Build/Xabsl%.o: ../Xabsl/XabslEngine/Xabsl%.cpp ../Xabsl/XabslEngine/Xabsl%.h
@echo $@
@if !(test -d Build); then mkdir Build; fi
@g++ -c $< -o $@
Build/WorldState.o: WorldState.cpp WorldState.h
@echo $@
@if !(test -d Build); then mkdir Build; fi
@g++ -c WorldState.cpp -o $@
Build/MyBasicBehaviors.o: MyBasicBehaviors.cpp MyBasicBehaviors.h
@echo $@
@if !(test -d Build); then mkdir Build; fi
@g++ -c MyBasicBehaviors.cpp -o $@
Build/east.o: main.cpp WorldState.h MyBasicBehaviors.h Tools.h
@echo $@
@if !(test -d Build); then mkdir Build; fi
@g++ -I../ascii-soccer -c -DEAST_TEAM main.cpp -o $@
Build/common.o: common.c
@echo $@
@if !(test -d Build); then mkdir Build; fi
@g++ -I../ascii-soccer -c -DWEST_TEAM common.c -o $@
Build/libeast.a: Build/east.o Build/MyBasicBehaviors.o Build/WorldState.o $(XABSLFILES)
@echo $@
@if !(test -d Build); then mkdir Build; fi
@ar rc $@ Build/east.o Build/MyBasicBehaviors.o Build/WorldState.o $(XABSLFILES)
@ranlib $@
Build/libcommon.a: Build/common.o Build/east.o
@echo $@
@if !(test -d Build); then mkdir Build; fi
@ar rc $@ Build/common.o
@ranlib $@
clean:
@rm -rf Build

View File

@ -0,0 +1,23 @@
XABSL_DIR = ../../Xabsl
XSLT = xsltproc #../../util/LibXML/xsltproc.exe --xinclude
DOT = dot #util/dot-1.9.0/dot.exe
DOTML_DIR = ../../util/dotml-1.2
XABSL_COMPILER_DIR = $(XABSL_DIR)/compiler
XABSL_XSL_DIR = $(XABSL_DIR)/xsl
XABSL_OUTPUT_DIR = ../../ascii-soccer
INTERMEDIATE_CODE = intermediate-code.dat
DEBUG_SYMBOLS = debug-symbols.dat
DOC_OUTPUT_DIR = ../xabsl-doc
XABSL_TEMP_DIR = .
XML_OUTPUT_DIR = ../xabsl-xml
XABSL_COMPILER_OPTIONS =
SOURCES = $(shell find . -name "*.xabsl")
AGENTS_FILE = agents.xabsl
include $(XABSL_DIR)/XabslMakefile

View File

@ -0,0 +1,35 @@
/** Waits behind the ball */
option defender {
initial state own_team_has_ball {
decision {
/** opponent team has ball */
if (most_westerly_teammate.x() < ball.x()) {
goto opponent_team_has_ball;
}
else {
stay;
}
}
action {
go_to(x = ball.x() + 12, y = ball.y());
}
}
state opponent_team_has_ball {
decision {
/** own team has ball */
if (most_westerly_teammate.x() >= ball.x()) {
goto own_team_has_ball;
}
else {
stay;
}
}
action {
go_to(x = ball.x() + 10, y = ball.y());
}
}
}

View File

@ -0,0 +1,50 @@
/** Dribbles the ball without kicking */
option dribble {
initial state behind_ball {
decision {
/** not behind ball */
if (ball.local.direction() != W) {
goto not_behind_ball;
}
else {
/** near opponent goal */
if (x() < 13) {
goto behind_ball_near_opponent_goal;
}
else {
stay;
}
}
}
action {
next_action = W;
}
}
state behind_ball_near_opponent_goal {
decision {
goto behind_ball;
}
action {
next_action = kick;
}
}
state not_behind_ball {
decision {
/** not behind ball */
if (ball.local.direction() != W) {
stay;
}
else {
goto behind_ball;
}
}
action {
get_behind_ball();
}
}
}

View File

@ -0,0 +1,95 @@
/** Handles the ball. */
option midfielder {
initial state get_to_ball {
decision {
/** far from ball */
if (ball.distance() > 3) {
stay;
}
else {
/** no teammate to the west */
if (most_westerly_teammate.x() > ball.x() + 2) {
goto dribble;
}
/** most westerly teammate north of ball */
else if (most_westerly_teammate.y() < ball.y()){
goto passNW;
}
/** most westerly teammate south of ball */
else
goto passSW;
}
}
action {
go_to(x = ball.x(), y = ball.y());
}
}
state passNW {
decision {
/** far from ball */
if (ball.distance() > 3) {
goto get_to_ball;
}
/** at desired position for pass to NW */
else if (x == ball.x()+1 && y == ball.y()+1)
goto pass;
else {
stay;
}
}
action {
// go to position SW of ball in order to pass in NW direction
go_to(x = ball.x()+1, y = ball.y()+1);
}
}
state passSW {
decision {
/** far from ball */
if (ball.distance() > 3) {
goto get_to_ball;
}
/** at desired position for pass to SW */
else if (x == ball.x()+1 && y == ball.y()-1)
goto pass;
else {
stay;
}
}
action {
// go to position SW of ball in order to pass in NW direction
go_to(x = ball.x()+1, y = ball.y()-1);
}
}
state pass {
decision {
if (ball.distance() > 3)
goto get_to_ball;
else
stay;
}
action {
pass();
}
}
state dribble {
decision {
/** far from ball */
if (ball.distance() > 3) {
goto get_to_ball;
}
else {
stay;
}
}
action {
dribble();
}
}
}

View File

@ -0,0 +1,35 @@
/** Passes the ball to a teammate. */
option pass {
initial state get_behind_ball {
decision {
/** at ball */
if (ball.local.direction() == NW || ball.local.direction() == W || ball.local.direction() == SW) {
goto kick;
}
else {
stay;
}
}
action {
get_behind_ball();
}
}
state kick {
decision {
/** still behind ball */
if (ball.local.direction() == N || ball.local.direction() == NW || ball.local.direction() == W || ball.local.direction() == SW || ball.local.direction() == S) {
stay;
}
else {
goto get_behind_ball;
}
}
action {
next_action = kick;
}
}
}

View File

@ -0,0 +1,37 @@
/** The soccer root behavior */
option play_soccer {
common decision {
/** player role is striker */
if (role() == striker) {
goto striker;
}
/** player role is defender */
else if (role() == defender) {
goto defender;
}
/** player role is midfielder */
else if (role() == midfielder) {
goto midfielder;
}
}
state striker {
action {
striker();
}
}
initial state midfielder {
action {
midfielder();
}
}
state defender {
action {
defender();
}
}
}

View File

@ -0,0 +1,11 @@
/** Waits in front of the other players for a pass */
option striker {
initial state __initial {
action {
go_to(x = ball.x() - 10, y = 11); //central position 10 units west of ball position
}
}
}

View File

@ -0,0 +1,18 @@
/***
Title: XABSL Example Agent Team
Platform: Soccer simulation.
Software-Environment: The ascii-soccer environment (http://www-2.cs.cmu.edu/~trb/soccer/).
*/
include "my-basic-behaviors.xabsl";
include "my-symbols.xabsl";
include "Options/play-soccer.xabsl";
include "Options/midfielder.xabsl";
include "Options/pass.xabsl";
include "Options/dribble.xabsl";
include "Options/defender.xabsl";
include "Options/striker.xabsl";
/** A simple soccer agent behavior */
agent soccer("Soccer", play_soccer);

View File

@ -0,0 +1,16 @@
/** My common basic behaviors */
namespace my_basic_behaviors("My Basic Behaviors") {
/** Lets the agent move to a point */
behavior go_to {
/** X of destination position */
float x [1..78] "px";
/** Y of destination position */
float y [1..22] "px";
}
/** Approaches the ball and gets behind it */
behavior get_behind_ball {
}
}

View File

@ -0,0 +1,68 @@
/** My most used symbols */
namespace my_symbols("My Symbols") {
/** The possible roles of a player */
enum role {
defender,
midfielder,
striker
};
/** The possible direction and actions */
enum next_action {
undefined,
NW,
N,
NE,
E,
SE,
S,
SW,
W,
kick,
do_nothing
};
/** The next action to be performed */
enum next_action output next_action;
/** The dynamically assigned role of the player */
enum role input role;
/** The x position of the player */
float input x;
/** The y position of the player */
float input y;
/** The x position of the ball */
float input ball.x;
/** The y position of the ball */
float input ball.y;
/** The distance to the ball */
float input ball.distance;
/** The direction of the ball if in the local area of the player. If the ball is not in the local area, undefined is returned */
enum next_action input ball.local.direction;
/** The x position of the most westerly teammate */
float input most_westerly_teammate.x;
/** The y position of the most westerly teammate */
float input most_westerly_teammate.y;
}

View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@ -0,0 +1,209 @@
ASCII Soccer version 2.0
========================
This program is a tool for investigating how groups of simple agents
interact while playing a soccer-like game. You can develop your own
team strategies and test them against others.
Two teams of players attempt to push a ball across the other team's
goal. The game can be viewed on your screen using patented
ASCII-animation(tm) technology.
Where to get it:
ASCII Soccer Homepage: http://www.cc.gatech.edu/grads/b/Tucker.Balch/soccer/
Source code: ftp://ftp.cc.gatech.edu/pub/people/tucker/soccer.2.0.tar.Z
For a synopsis of what's new in version 2.0, see the NEW file.
Compatibility
=============
NOTE: this is AS IS unsupported software. It was developed on and runs
on SunOS 4.1.3 and Linux systems, but it may compile on other systems.
To unpack the source code you will need uncompress and tar.
To compile you will need make, g++, csh, and the curses and termcap libraries.
It seems that most incompatiblities arise from OLD versions of gcc/g++.
I have compiled with versions of g++ as old as 2.5.8. To see which version
you have, type g++ --version . Note that gcc and g++ are usually installed
together.
To use the packteam and unpackteam you'll need tar, compress and uuencode.
Quickstart
==========
Get the source code off the web
http://www.cc.gatech.edu/grads/b/Tucker.Balch/soccer/
After you've uncompressed and untarred it, type:
contest example wall
This will set up a soccer match between the "example" team and the
"wall" team, by compiling and linking teams in the directories teams/example
and teams/wall. If it does not compile, you probably don't have all the
software you need to compile it. See COMPATIBLIY above. Don't be too
concerned about "warnings" but "errors" are bad! After the compilation
is complete the teams will automatically start a game. The first team to
7 points wins. To run another game, type "soccer"
Look in the "teams" directory for other teams to try.
RULES
=====
The teams consist of four players. Each team member is provided with
sensors that tell it about the immediately adjoining 8 cells and a
compass heading towards the ball, and their location on the field. Players
can push the ball by trying to move to the cell it occupies, but they
cannot move over one another or outside the boundaries. Players may also
kick the ball if they are immediately next to it. A kicked ball travels
10 cells at 8 times the speed of a player. When kicking the ball, the
player also moves into the cell were the ball was previously.
A point is scored when the ball is pushed or kicked across a goal line.
The game continues until the first team scores 7 points.
Occasionally, the ball gets "stuck" between two competitors. In that case
the ball is automatically "nudged" up or down, so play can resume.
Designing Your Own Team
=======================
Take a look at teams/example/main.c as a start. There are several things to
keep in mind as you write your code:
1) You MUST have the following functions:
player1(), player2(), player3(), player4() and
team_name(), initialize_point(), won_point(), lost_point(),
initialize_game(), game_over(). Just use the example
team as a shell and this will happen for you.
2) Always assume you are the East Team: you start on the east
side and you want to push the ball to the west. The
program will automatically reverse things for you when
you start on the other side.
The player() functions represent each player's strategy, the team_name
function is used to print your team's name on the screen.
You will notice a macro called UN(). This is used to ensure that function
and variable names are not duplicated between team's .c files.
For instance, for the east team, UN(team_name)() will become EASTteam_name().
This is necessary for the automatic compiling and linking of arbitrary teams
for tournaments. It also allows the same team to play itself. Be sure to
use the macro around all functions and global variables in your main.c file.
The players are actually functions player1() through player4(). Each
function is passed 4 parameters. The incoming parameters are the robot's
sensory information:
local_area[] Reveals what's nearby. Indexed by
N,NE,E,SE,S, etc. so that, for example,
local_area[S] tells you what is in the
cell to the south of the robot. Possible
values include: BOUNDARY, OPPONENT, TEAMMATE,
BALL and EMPTY.
ball_direction Compass heading to the ball: N, S, E, W, NE, etc.
x, y The robot's location. y varies from 1 to 22,
x varies from 1 to 78. +x is east, +y is south.
0 and 79 are goal lines, so your players will never
occupy those locations.
Each player function should return an integer indicating either a direction to
move (N, NE, E, S, etc) or KICK to kick the ball.
How the Compiling and Linking Works
====================================
You don't have to read this section!
This is rather hairy mostly because we can link together any two arbitrary
teams, and they can play on either side of the field. Fortunately, if you
just copy everything from the teams/example directory to a new directory,
and develop your team there, you shouldn't have to worry about this too much.
The default makefile assumes your team is coded in main.c .
main.c is compiled into either west.o or east.o depending on whether your
team will take the east or west side of the field. The symbols WEST_TEAM
and EAST_TEAM are defined/not defined according to which side you're on.
The makefile also compiles common.c which is presumed to include functions
and globals that do not have unique names and that might be shared if your
team was playing itself. Even if you don't use common.c, don't remove it!
the contest script and makefiles aren't smart enough not to use it. I found
I needed this to make it easier to use some c++ classes I use for my
learning team.
Finally, the .o files are grouped into libraries: libeast.a libwest.a
and libcommon.a . The contest script copies the appropriate libraries
up to the top directory, then links soccer.o with them to generate the
final executable.
You can take advantage of this library approach now to design more complex
teams composed of several separately compiled modules - but you don't have
to! Just make sure your makefile correctly generates libeast.a libwest.a
and libcommon.a .
Advanced Techniques
===================
There are some additional hooks for learning, etc. which you may choose
to use. You will notice at the bottom of example.c there are several
additional functions with no body. These functions are automatically
called at various points in the game, as follows:
initialize_game() Called once per game before play begins.
game_over() Called once per game at the end of the game.
initialize_point() Called once per point before play begins.
lost_point() Called if your team loses a point.
won_point() Called if your team wins a point.
You may find these functions handy for initialization and learning strategies.
Command-line Arguments
======================
The soccer executable offers a few command-line arguments you may want
to use:
-d Don't display the game on the screen.
-s seed Use seed as the random seed for the game.
time() is used otherwise.
-p points Play to points instead of the default 7.
packteam and unpackteam
=======================
These two scipts will pack up or unpack a team for you so that they are more
convenient to exchange by email. The command "packteam fred" will look for
a team in the teams/fred directory and tar, compress and uuencode it. The
resulting file fred.tar.Z.uu is plain ascii text. If someone sends you one
of these files, or you download one you can unpack it with the command
"unpackteam fred" Unpackteam will look for fred.tar.Z.uu, so make sure all
the file extensions are there.
When you use either of these scripts make sure you cd to the top of your
soccer directory structure.
Bugs, Gripes, Complaints
========================
I don't promise ANYTHING, but I am very glad to see your teams and hear
about bugs. Especially if you have fixed them!!!!
Email: tucker@cc.gatech.edu

View File

@ -0,0 +1,54 @@
#!/bin/sh -f
if test $2'x' = 'x'; then
echo "usage: contest team1name team2name"
exit 1
fi
echo "contest: Removing old stuff"
rm -f *.a
rm -f *.o
rm -f soccer
rm -f soccer.exe #if compiled under cygwin
rm -f core
if test $1 != $2; then
echo "contest: Moving to ./teams/"$1" ."
echo "contest: Compiling libraries for the " $1 " team."
cd teams/$1
make libwest.a
cp libwest.a ../..
make libcommon.a
cp libcommon.a ../../libwestcommon.a
echo "contest: Moving to ./teams/"$2" ."
echo "contest: Compiling libraries for the " $2 " team."
cd ../$2
make libeast.a
cp libeast.a ../..
make libcommon.a
cp libcommon.a ../../libeastcommon.a
cd ../..
echo "contest: Compiling and linking soccer."
make soccer;
else
cd teams/$1
echo "contest: This team will play against itself."
echo "contest: WARNING some teams will fail to link in this case."
echo "contest: Moving to ./teams/"$2" ."
echo "contest: Compiling libraries for the " $1 " team."
make libeast.a
make libwest.a
make libcommon.a
cp libeast.a ../../libeast.a
cp libwest.a ../../libwest.a
cp libcommon.a ../../libcommon.a
cd ../..
echo "contest: Compiling and linking soccer."
make soccerboth;
fi
echo "contest: starting a game."
./soccer -p 7

View File

@ -0,0 +1,19 @@
soccer.o: soccer.c soccer.h players.h
g++ -w -c soccer.c
soccer: soccer.o libeast.a libwest.a libeastcommon.a libwestcommon.a
g++ -w soccer.o -o soccer -L./ -lncurses -lm \
-least -leastcommon -lwest -lwestcommon
soccerboth: soccer.o libeast.a libwest.a libcommon.a
g++ -w soccer.o -o soccer -L./ -lncurses -lm \
-least -lcommon -lwest
clean:
rm -f *.o
rm -f *.a
rm -f soccer
rm -f core
reallyclean: clean
cleanteams

View File

@ -0,0 +1,17 @@
#include "soccer.h"
#ifndef PLAYERS_H
#define PLAYERS_H
#ifdef EAST_TEAM
#define OPPONENT WEST_PLAYER
#define TEAMMATE EAST_PLAYER
#define UN(original_name) EAST ## original_name
#endif
#ifdef WEST_TEAM
#define OPPONENT EAST_PLAYER
#define TEAMMATE WEST_PLAYER
#define UN(original_name) WEST ## original_name
#endif
#define unique_name(a) UN(a)
#endif

Some files were not shown because too many files have changed in this diff Show More