|
|
|
![]() |
|
|||||||
|
||||||||
![]() |
| Thread Tools | Rate Thread | Display Modes |
|
#1
|
|||||
|
|||||
|
Parsing file-based autonomous modes with lex and yacc
Note: the AutonController is meant for IterativeRobot-based robots, but can be modified fairly easily.
I've been playing around with reading autonomous modes from the filesystem on the cRIO and've found lex and yacc to be very useful and want to share them. I've set up configurations to read commands in the format of: Code:
# comment [ModeName] COMMAND 0 0; # command_name parameter timeout; # examples [Wait3sAndFire] SHOOTER 3800 0; NOTHING 0 3; CHUTE 1 0; [DoNothing] NOTHING 0 15; lexer.l Code:
%{
#include <stdio.h>
#include "parser.h"
%}
%%
#.* /* comment */;
[0-9\.]+ yylval.number=atof(yytext); return NUMBER;
[a-zA-Z0-9_][a-zA-Z0-9_]* yylval.string=strdup(yytext); return WORD;
\[ return LBRACKET;
\] return RBRACKET;
; return SEMICOLON;
\n /* whitespace */;
[ \t]+ /* whitespace */;
%%
parser.y Code:
%{
#include <stdio.h>
#include <string.h>
#include "AutonController.h"
void yyerror(const char *str)
{
//printf("error: %s\n",str);
}
extern "C"
{
int yyparse(void);
int yylex(void);
int yywrap()
{
return 1;
}
}
extern FILE* yyin;
AutonController* controller = NULL;
int AutonController::parseCommands(FILE* file)
{
controller = this;
yyin = file;
return yyparse();
}
char* section = NULL;
%}
%token <number> NUMBER
%token <string> WORD
%token <string> LBRACKET
%token <string> RBRACKET
%token <string> SEMICOLON
%union
{
double number;
char* string;
}
%%
start:
section commands
;
commands:
|
commands command
;
command:
section
|
WORD NUMBER NUMBER SEMICOLON
{
controller->addCommand(section, $1, $2, $3);
}
;
section:
LBRACKET WORD RBRACKET
{
section = $2;
}
;
%%
Code:
lex lexer.l yacc -o parser.cc -d parser.y AutonController.h Code:
#ifndef _AUTON_CONTROLLER_H
#define _AUTON_CONTROLLER_H
#include <map>
#include <queue>
#include <string>
#include <stdio.h>
#include "WPILib.h"
typedef struct AutonCommand
{
std::string type;
double parameter;
double timeout;
} AutonCommand;
class AutonController
{
public:
AutonController(const char* filename);
void reloadCommands();
void reset();
void handle();
void addCommand(char* scriptName, char* type, double param, double timeout);
void cycleMode();
char* getModeName();
private:
DriverStationLCD* lcd;
const char* scriptFilename;
std::map<char*, std::queue<AutonCommand> > commands;
std::map<char*, std::queue<AutonCommand> >::iterator selector;
Timer* timer;
int parseCommands(FILE* file);
};
#endif
AutonController.cpp Code:
#include "AutonController.h"
AutonController::AutonController(const char* filename)
{
lcd = DriverStationLCD::GetInstance();
timer = new Timer();
scriptFilename = filename;
reloadCommands();
}
void AutonController::reloadCommands()
{
commands.clear();
FILE* file = fopen(scriptFilename, "r");
if(!file)
{
printf("Auton script file \"%s\" does not exist. No commands loaded.\n", scriptFilename);
return;
}
if(parseCommands(file) != 0)
{
printf("Syntax error in %s!\n", scriptFilename);
commands.clear();
}
selector = commands.begin();
timer->Start();
fclose(file);
}
void AutonController::reset()
{
// Reset robot state here
timer->Reset();
}
void AutonController::handle()
{
AutonCommand curCmd = selector->second.front();
if(selector->second.empty());
return;
bool result = false;
printf("Current command: %s\n", curCmd.type.c_str());
if(curCmd.type == "NOTHING")
{
// waiting...
} else
{
printf("Unknown command \"%s\" in script %s (file %s)!\n", curCmd.type.c_str(), selector->first, scriptFilename);
result = true;
}
if(result || timer->Get() > curCmd.timeout)
{
selector->second.pop();
timer->Reset();
}
}
void AutonController::addCommand(char* scriptName, char* type, double param, double timeout)
{
printf("Adding %s (%f) to %s with timeout of %f\n", type, param, scriptName, timeout);
AutonCommand c;
c.type = type;
c.parameter = param;
c.timeout = timeout;
commands[scriptName].push(c);
}
void AutonController::cycleMode()
{
selector++;
if(selector == commands.end())
{
lcd->PrintfLine(DriverStationLCD::kUser_Line1, "Reloading auto script");
lcd->UpdateLCD();
reloadCommands();
}
}
char* AutonController::getModeName()
{
return selector->first;
}
Last edited by connor.worley : 12-04-2012 at 14:23. |
|
#2
|
||||
|
||||
|
Re: Parsing file-based autonomous modes with lex and yacc
Thanks!
I'm definitely going to look into using this during the summer. Maybe now I won't be the only one who can program autonomous ![]() |
![]() |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|