/*
* aegis - project change supervisor
* Copyright (C) 2001-2008, 2012, 2014 Peter Miller
*
* 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 3 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, see .
*/
%{
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef DEBUG
#undef YYDEBUG
#define YYDEBUG 1
#endif
%}
%token COMMENT
%token DELTA_BEGIN
%token DELTA_END
%token D_KEYWORD
%token E_KEYWORD
%token FLAGS
%token HEADER
%token I_KEYWORD
%token JUNK
%token MR
%token MR_EXCLUDE
%token MR_IGNORE
%token MR_INCLUDE
%token STRING
%token SUMMARY
%token TEXTLINE
%token TITLE_BEGIN
%token TITLE_END
%token USERS_BEGIN
%token USERS_END
%union {
nstring *lv_string;
long lv_long;
}
%type date_and_time number
%type COMMENT STRING TEXTLINE
%destructor { delete $$; }
%{
static format_version *current;
static itab_ty *itp;
static nstring pfn;
static nstring lfn;
static format_version *
find(int n)
{
assert(itp);
format_version *fvp = (format_version *)itab_query(itp, n);
if (!fvp)
{
fvp = new format_version();
itab_assign(itp, n, fvp);
fvp->filename_physical = pfn;
fvp->filename_logical = lfn;
fvp->edit.push_back(nstring::format("%d", n));
}
return fvp;
}
static void
walker(itab_ty *, itab_key_ty, void *data, void *)
{
format_version *fvp = (format_version *)data;
if (fvp->after_branch)
{
size_t ndots = fvp->edit.front().count_the_dots();
for (size_t j = 0; j < fvp->after_branch->length; ++j)
{
format_version *after = fvp->after_branch->item[j];
if
(
!after->edit.empty()
&&
after->edit.front().count_the_dots() <= ndots
)
{
fvp->after = after;
if (j + 1 < fvp->after_branch->length)
{
fvp->after_branch->item[j] =
fvp->after_branch->item[fvp->after_branch->length - 1];
}
fvp->after_branch->length--;
if (fvp->after_branch->length == 0)
{
delete fvp->after_branch;
fvp->after_branch = NULL;
}
break;
}
}
}
}
format_version *
sccs_parse(const nstring &physical, const nstring &logical)
{
itp = itab_alloc();
pfn = physical;
lfn = logical;
sccs_lex_open(physical);
#if YYDEBUG
{ extern int yydebug; yydebug = 1; }
#endif
{ extern int yyparse(void); yyparse(); }
sccs_lex_close();
itab_walk(itp, walker, 0);
format_version *result = find(1); // FIXME: manual says largest sid
itab_free(itp);
itp = 0;
return result;
}
%}
%%
sccsfile
: header deltas users flags title body
;
header
: HEADER ignore_arguments
;
deltas
: delta
| deltas delta
;
delta
: summary delta_begin delta_lines delta_end
;
summary
: SUMMARY ignore_arguments
;
delta_begin
: DELTA_BEGIN STRING STRING date_and_time STRING number number
{
format_version *before;
(void)$2;
/*
* $2 some kind of state info, we ignore it
* $3 edit
* $4 time_t
* $5 who
* $6 number of this delta
* $7 number of predecessor
*/
before = $7 ? find($7) : 0;
current = find($6);
current->edit.push_front_unique(*$3);
current->when = $4;
current->who.push_back_unique(*$5);
nstring sid = nstring::format("%ld", $6);
current->edit.push_back_unique(sid);
current->before = before;
if (before)
{
if (!before->after_branch)
{
before->after_branch = new format_version_list();
}
before->after_branch->append(current);
}
}
;
date_and_time
: STRING STRING
{
//
// make time_t value from strings
//
nstring_list sl1;
sl1.split(*$1, "/");
while (sl1.size() < 3)
sl1.push_back("0");
nstring_list sl2;
sl2.split(*$2, ":");
while (sl2.size() < 3)
sl2.push_back("0");
static struct tm tm_zero;
struct tm temp = tm_zero;
temp.tm_year = fix_tm_year(sl1[0].to_long());
temp.tm_mon = sl1[1].to_long() - 1;
temp.tm_mday = sl1[2].to_long();
temp.tm_hour = sl2[0].to_long();
temp.tm_min = sl2[1].to_long();
temp.tm_sec = sl2[2].to_long();
time_t t = mktime(&temp);
if (t == (time_t)-1)
{
nstring s = nstring(*$1) + " " + nstring(*$2);
fatal_date_unknown(s.c_str());
}
trace_time(t);
$$ = t;
}
;
number
: STRING
{
char *cp = 0;
$$ = strtol($1->c_str(), &cp, 10);
if ($1->size() && *cp != 0)
yyerror("number expected");
}
;
delta_lines
: /* empty */
| delta_lines delta_line
;
delta_line
: comment
| mr
| included
| excluded
| ignored
| error
;
comment
: COMMENT
{
assert(current);
if (current)
{
nstring_list log;
log.split(*$1, "\n", true);
current->description.push_back_unique(log);
}
}
;
mr
: MR ignore_arguments
;
included
: MR_INCLUDE ignore_arguments
;
excluded
: MR_EXCLUDE ignore_arguments
;
ignored
: MR_IGNORE ignore_arguments
;
delta_end
: DELTA_END ignore_arguments
{
assert(current);
if (current->description.empty())
{
current->description.push_back("no description");
}
current = NULL;
}
;
users
: users_start textlines_opt users_end
;
users_start
: USERS_BEGIN ignore_arguments
;
users_end
: USERS_END ignore_arguments
;
flags
: /* empty */
| flags flag
;
flag
: FLAGS ignore_arguments
;
ignore_arguments
: /* empty */
| ignore_arguments STRING
{ (void)$2; }
;
title
: title_begin textlines_opt title_end
;
title_begin
: TITLE_BEGIN ignore_arguments
;
title_end
: TITLE_END ignore_arguments
;
body
: /* empty */
| body I_stuff
| body D_stuff
| body E_stuff
| body error
;
/* ^AI */
I_stuff
: I_KEYWORD ignore_arguments textlines_opt
;
/* ^AD */
D_stuff
: D_KEYWORD ignore_arguments textlines_opt
;
/* ^AE */
E_stuff
: E_KEYWORD ignore_arguments textlines_opt
;
textlines_opt
: /* empty */
| textlines_opt TEXTLINE
{ (void)$2; }
;
/* vim: set ts=8 sw=4 et : */