/* cdrdao - write audio CD-Rs in disc-at-once mode * * Copyright (C) 1998-2001 Andreas Mueller * * 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. */ #header << #include #include #include "Toc.h" #include "util.h" #include "log.h" #include "CdTextItem.h" >> << #include "CdTextContainer.h" #include "TocLexerBase.h" // Maximum length of binary data for CD-TEXT #define MAX_CD_TEXT_DATA_LEN (256 * 12) /* Use 'ANTLRCommonToken' as 'ANTLRToken' to be compatible with some bug * fix releases of PCCTS-1.33. The drawback is that the token length is * limited to 100 characters. This might be a problem for long file names. * Define 'USE_ANTLRCommonToken' to 0 if you want to use the dynamic token * which handles arbitrary token lengths (there'll be still a limitation in * the lexer code but that's more than 100 characters). In this case it might * be necessary to adjust the types of the member functions to the types in * 'ANTLRAbstractToken' defined in PCCTSDIR/h/AToken.h'. */ #define USE_ANTLRCommonToken 0 #if USE_ANTLRCommonToken typedef ANTLRCommonToken ANTLRToken; #else class ANTLRToken : public ANTLRRefCountToken { private: ANTLRTokenType type_; int line_; ANTLRChar *text_; public: ANTLRToken(ANTLRTokenType t, ANTLRChar *s) : ANTLRRefCountToken(t, s) { setType(t); line_ = 0; setText(s); } ANTLRToken() { setType((ANTLRTokenType)0); line_ = 0; setText(""); } virtual ~ANTLRToken() { delete[] text_; } #if 0 // use this for basic PCCTS-1.33 release ANTLRTokenType getType() { return type_; } virtual int getLine() { return line_; } ANTLRChar *getText() { return text_; } void setText(ANTLRChar *s) { text_ = strdupCC(s); } #else // use this for PCCTS-1.33 bug fix releases ANTLRTokenType getType() const { return type_; } virtual int getLine() const { return line_; } ANTLRChar *getText() const { return text_; } void setText(const ANTLRChar *s) { text_ = strdupCC(s); } #endif void setType(ANTLRTokenType t) { type_ = t; } void setLine(int line) { line_ = line; } virtual ANTLRAbstractToken *makeToken(ANTLRTokenType tt, ANTLRChar *txt, int line) { ANTLRAbstractToken *t = new ANTLRToken(tt,txt); t->setLine(line); return t; } }; #endif >> << class TocLexer : public TocLexerBase { public: TocLexer(DLGInputStream *in, unsigned bufsize=2000) : TocLexerBase(in, bufsize) { parser_ = NULL; } virtual ANTLRTokenType erraction(); TocParserGram *parser_; }; >> #lexclass START #token Eof "@" #token "[\t\r\ ]+" << skip(); >> #token Comment "//~[\n@]*" << skip(); >> #token "\n" << newline(); skip(); >> #token BeginString "\"" << mode(STRING); >> #token Integer "[0-9]+" #token TrackDef "TRACK" #token FirstTrackNo "FIRST_TRACK_NO" #token Audio "AUDIO" #token Mode0 "MODE0" #token Mode1 "MODE1" #token Mode1Raw "MODE1_RAW" #token Mode2 "MODE2" #token Mode2Raw "MODE2_RAW" #token Mode2Form1 "MODE2_FORM1" #token Mode2Form2 "MODE2_FORM2" #token Mode2FormMix "MODE2_FORM_MIX" #token SubChanRw "RW" #token SubChanRwRaw "RW_RAW" #token Index "INDEX" #token Catalog "CATALOG" #token Isrc "ISRC" #token No "NO" #token Copy "COPY" #token PreEmphasis "PRE_EMPHASIS" #token TwoChannel "TWO_CHANNEL_AUDIO" #token FourChannel "FOUR_CHANNEL_AUDIO" #tokclass AudioFile { "AUDIOFILE" "FILE" } #token DataFile "DATAFILE" #token Fifo "FIFO" #token Silence "SILENCE" #token Zero "ZERO" #token Pregap "PREGAP" #token Start "START" #token End "END" #token TocTypeCdda "CD_DA" #token TocTypeCdrom "CD_ROM" #token TocTypeCdromXa "CD_ROM_XA" #token TocTypeCdi "CD_I" #token Swap "SWAP" #token CdText "CD_TEXT" #token Language "LANGUAGE" #token LanguageMap "LANGUAGE_MAP" #token Title "TITLE" #token Performer "PERFORMER" #token Songwriter "SONGWRITER" #token Composer "COMPOSER" #token Arranger "ARRANGER" #token Message "MESSAGE" #token DiscId "DISC_ID" #token Genre "GENRE" #token TocInfo1 "TOC_INFO1" #token TocInfo2 "TOC_INFO2" #token Reserved1 "RESERVED1" #token Reserved2 "RESERVED2" #token Reserved3 "RESERVED3" #token Reserved4 "RESERVED4" #token UpcEan "UPC_EAN" #token SizeInfo "SIZE_INFO" #token LangEn "EN" #lexclass STRING #token EndString "\"" << mode(START); >> #token StringQuote "\\\"" #token StringOctal "\\[0-9][0-9][0-9]" #token String "\\" #token String "[ ]+" #token String "~[\\\n\"\t ]*" #lexclass START class TocParserGram { << public: const char *filename_; int error_; void syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k); >> toc > [ Toc *t ] : << $t = new Toc; Track *tr = NULL; int lineNr = 0; char *catalog = NULL; Toc::TocType toctype; int firsttrack, firstLine; >> ( Catalog string > [ catalog ] << if (catalog != NULL) { if ($t->catalog(catalog) != 0) { log_message(-2, "%s:%d: Illegal catalog number: %s.\n", filename_, $1->getLine(), catalog); error_ = 1; } delete[] catalog; catalog = NULL; } >> | tocType > [ toctype ] << $t->tocType(toctype); >> )* { FirstTrackNo integer > [ firsttrack, firstLine ] << if (firsttrack > 0 && firsttrack < 100) { $t->firstTrackNo(firsttrack); } else { log_message(-2, "%s:%d: Illegal track number: %d\n", filename_, firstLine, firsttrack); error_ = 1; } >> } { cdTextGlobal [ $t->cdtext_ ] } ( track > [ tr, lineNr ] << if (tr != NULL) { if ($t->append(tr) != 0) { log_message(-2, "%s:%d: First track must not have a pregap.\n", filename_, lineNr); error_ = 1; } delete tr, tr = NULL; } >> )+ Eof ; // fail action << delete $t, $t = NULL; delete[] catalog; >> track > [ Track *tr, int lineNr ] : << $tr = NULL; $lineNr = 0; SubTrack *st = NULL; char *isrcCode = NULL; TrackData::Mode trackType; TrackData::SubChannelMode subChanType = TrackData::SUBCHAN_NONE; Msf length; Msf indexIncrement; Msf pos; int posGiven = 0; Msf startPos; // end of pre-gap Msf endPos; // start if post-gap int startPosLine = 0; int endPosLine = 0; int lineNr = 0; int flag = 1; >> TrackDef << $lineNr = $1->getLine(); >> trackMode > [ trackType ] { subChannelMode > [ subChanType ] } << $tr = new Track(trackType, subChanType); >> ( Isrc string > [ isrcCode ] << if (isrcCode != NULL) { if ($tr->isrc(isrcCode) != 0) { log_message(-2, "%s:%d: Illegal ISRC code: %s.\n", filename_, $1->getLine(), isrcCode); error_ = 1; } delete[] isrcCode; } >> | { No << flag = 0; >> } Copy << $tr->copyPermitted(flag); flag = 1; >> | { No << flag = 0; >> } PreEmphasis << $tr->preEmphasis(flag); flag = 1; >> | TwoChannel << $tr->audioType(0); >> | FourChannel << $tr->audioType(1); >> )* { cdTextTrack [ $tr->cdtext_ ] } { Pregap msf > [ length ] << if (length.lba() == 0) { log_message(-2, "%s:%d: Length of pregap is zero.\n", filename_, $1->getLine()); error_ = 1; } else { if (trackType == TrackData::AUDIO) { $tr->append(SubTrack(SubTrack::DATA, TrackData(length.samples()))); } else { $tr->append(SubTrack(SubTrack::DATA, TrackData(trackType, subChanType, length.lba() * TrackData::dataBlockSize(trackType, subChanType)))); } startPos = $tr->length(); startPosLine = $1->getLine(); } >> } ( subTrack [ trackType, subChanType ] > [ st, lineNr ] << if (st != NULL && $tr->append(*st) == 2) { log_message(-2, "%s:%d: Mixing of FILE/AUDIOFILE/SILENCE and DATAFILE/ZERO statements not allowed.", filename_, lineNr); log_message(-2, "%s:%d: PREGAP acts as SILENCE in audio tracks.", filename_, lineNr); error_ = 1; } delete st, st = NULL; >> | Start << posGiven = 0; >> { msf > [ pos ] << posGiven = 1; >> } << if (startPosLine != 0) { log_message(-2, "%s:%d: Track start (end of pre-gap) already defined.\n", filename_, $1->getLine()); error_ = 1; } else { if (!posGiven) { pos = $tr->length(); // retrieve current position } startPos = pos; startPosLine = $1->getLine(); } pos = Msf(0); >> | End << posGiven = 0; >> { msf > [ pos ] << posGiven = 1; >> } << if (endPosLine != 0) { log_message(-2, "%s:%d: Track end (start of post-gap) already defined.\n", filename_, $1->getLine()); error_ = 1; } else { if (!posGiven) { pos = $tr->length(); // retrieve current position } endPos = pos; endPosLine = $1->getLine(); } pos = Msf(0); >> )+ // set track start (end of pre-gap) and check for minimal track length << if (startPosLine != 0 && $tr->start(startPos) != 0) { log_message(-2, "%s:%d: START %s behind or at track end.\n", filename_, startPosLine, startPos.str()); error_ = 1; } >> ( Index msf > [ indexIncrement ] << if ($tr != NULL) { switch ($tr->appendIndex(indexIncrement)) { case 1: log_message(-2, "%s:%d: More than 98 index increments.\n", filename_, $1->getLine()); error_ = 1; break; case 2: log_message(-2, "%s:%d: Index beyond track end.\n", filename_, $1->getLine()); error_ = 1; break; case 3: log_message(-2, "%s:%d: Index at start of track.\n", filename_, $1->getLine()); error_ = 1; break; } } >> )* // set track end (start of post-gap) << if (endPosLine != 0) { switch ($tr->end(endPos)) { case 1: log_message(-2, "%s:%d: END %s behind or at track end.\n", filename_, endPosLine, endPos.str()); error_ = 1; break; case 2: log_message(-2, "%s:%d: END %s within pre-gap.\n", filename_, endPosLine, endPos.str()); error_ = 1; break; case 3: log_message(-2, "%s:%d: END %s: Cannot create index mark for post-gap.\n", filename_, endPosLine, endPos.str()); error_ = 1; break; } } >> ; // fail action << delete $tr, $tr = NULL; delete[] isrcCode; >> subTrack < [ TrackData::Mode trackType, TrackData::SubChannelMode subChanType ] > [ SubTrack *st, int lineNr ] : << $st = NULL; $lineNr = 0; char *filename = NULL; unsigned long start = 0; unsigned long len = 0; long offset = 0; TrackData::Mode dMode; int swapSamples = 0; >> ( AudioFile string > [ filename ] { Swap << swapSamples = 1; >> } { "#" sLong > [ offset ] } samples > [start] { samples > [len] } << $st = new SubTrack(SubTrack::DATA, TrackData(filename, offset, start, len)); $st->swapSamples(swapSamples); $lineNr = $1->getLine(); if (trackType != TrackData::AUDIO) { log_message(-2, "%s:%d: FILE/AUDIOFILE statements are only allowed for audio tracks.", filename_, $1->getLine()); error_ = 1; } if (subChanType != TrackData::SUBCHAN_NONE) { log_message(-2, "%s:%d: FILE/AUDIOFILE statements are only allowed for audio tracks without sub-channel mode.", filename_, $1->getLine()); error_ = 1; } >> | DataFile string > [ filename ] << dMode = $trackType; >> // { dataMode > [ dMode ] } { "#" sLong > [ offset ] } { dataLength [ dMode, $subChanType ] > [ len ] } << $st = new SubTrack(SubTrack::DATA, TrackData(dMode, $subChanType, filename, offset, len)); $lineNr = $1->getLine(); >> | Fifo string > [ filename ] dataLength [$trackType, $subChanType ] > [ len ] << $st = new SubTrack(SubTrack::DATA, TrackData($trackType, $subChanType, filename, len)); >> | Silence samples > [len] << $st = new SubTrack(SubTrack::DATA, TrackData(len)); $lineNr = $1->getLine(); if (len == 0) { log_message(-2, "%s:%d: Length of silence is 0.\n", filename_, $lineNr); error_ = 1; } if (trackType != TrackData::AUDIO) { log_message(-2, "%s:%d: SILENCE statements are only allowed for audio tracks.", filename_, $1->getLine()); error_ = 1; } if (subChanType != TrackData::SUBCHAN_NONE) { log_message(-2, "%s:%d: SILENCE statements are only allowed for audio tracks without sub-channel mode.", filename_, $1->getLine()); error_ = 1; } >> | Zero << dMode = $trackType; >> { dataMode > [ dMode ] } { subChannelMode > [ $subChanType ] } dataLength [ dMode, $subChanType ] > [ len ] << $st = new SubTrack(SubTrack::DATA, TrackData(dMode, $subChanType, len)); $lineNr = $1->getLine(); if (len == 0) { log_message(-2, "%s:%d: Length of zero data is 0.\n", filename_, $lineNr); error_ = 1; } >> ) << if ($st != NULL && $st->length() == 0) { // try to determine length if ($st->determineLength() != 0) { log_message(-2, "%s:%d: Cannot determine length of track data specification.", filename_, $lineNr); error_ = 1; } } >> ; // fail action << delete $st, $st = NULL; delete[] filename; >> string > [ char *ret ] : << $ret = strdupCC(""); char *s; char buf[2]; >> << buf[1] = 0; >> BeginString ( ( String << s = strdup3CC($ret, $1->getText(), NULL); >> | StringQuote << s = strdup3CC($ret, "\"", NULL); >> | StringOctal << buf[0] = strtol($1->getText() + 1, NULL, 8); s = strdup3CC($ret, buf, NULL); >> ) << delete[] $ret; $ret = s; >> )+ EndString ; stringEmpty > [ char *ret ] : << $ret = strdupCC(""); char *s; char buf[2]; >> << buf[1] = 0; >> BeginString ( ( String << s = strdup3CC($ret, $1->getText(), NULL); >> | StringQuote << s = strdup3CC($ret, "\"", NULL); >> | StringOctal << buf[0] = strtol($1->getText() + 1, NULL, 8); s = strdup3CC($ret, buf, NULL); >> ) << delete[] $ret; $ret = s; >> )* EndString ; uLong > [ unsigned long l ] : << $l = 0; >> Integer << $l = strtoul($1->getText(), NULL, 10); >> ; sLong > [ long l ] : << $l = 0; >> Integer << $l = strtol($1->getText(), NULL, 10); >> ; integer > [ int i, int lineNr ] : << $i = 0; >> Integer << $i = atol($1->getText()); $lineNr = $1->getLine(); >> ; msf > [ Msf m ] : << int min = 0; int sec = 0; int frac = 0; int err = 0; int minLine; int secLine; int fracLine; >> integer > [min, minLine] ":" integer > [sec, secLine] ":" integer > [frac, fracLine] << if (min < 0) { log_message(-2, "%s:%d: Illegal minute field: %d\n", filename_, minLine, min); err = error_ = 1; } if (sec < 0 || sec > 59) { log_message(-2, "%s:%d: Illegal second field: %d\n", filename_, secLine, sec); err = error_ = 1; } if (frac < 0 || frac > 74) { log_message(-2, "%s:%d: Illegal fraction field: %d\n", filename_, fracLine, frac); err = error_ = 1; } if (err != 0) { $m = Msf(0); } else { $m = Msf(min, sec, frac); } >> ; samples > [ unsigned long s ] : << Msf m; >> ( msf > [ m ] << $s = m.samples(); >> | uLong > [ $s ] ) ; // fail action << $s = 0; >> dataLength [ TrackData::Mode mode, TrackData::SubChannelMode sm] > [ unsigned long len ] : << Msf m; unsigned long blen; blen = TrackData::dataBlockSize(mode, sm); >> ( msf > [ m] << $len = m.lba() * blen; >> | uLong > [ $len ] ) ; // fail action << $len = 0; >> dataMode > [ TrackData::Mode m ] : ( Audio << $m = TrackData::AUDIO; >> | Mode0 << $m = TrackData::MODE0; >> | Mode1 << $m = TrackData::MODE1; >> | Mode1Raw << $m = TrackData::MODE1_RAW; >> | Mode2 << $m = TrackData::MODE2; >> | Mode2Raw << $m = TrackData::MODE2_RAW; >> | Mode2Form1 << $m = TrackData::MODE2_FORM1; >> | Mode2Form2 << $m = TrackData::MODE2_FORM2; >> | Mode2FormMix << $m = TrackData::MODE2_FORM_MIX; >> ) ; trackMode > [ TrackData::Mode m ] : ( Audio << $m = TrackData::AUDIO; >> | Mode1 << $m = TrackData::MODE1; >> | Mode1Raw << $m = TrackData::MODE1_RAW; >> | Mode2 << $m = TrackData::MODE2; >> | Mode2Raw << $m = TrackData::MODE2_RAW; >> | Mode2Form1 << $m = TrackData::MODE2_FORM1; >> | Mode2Form2 << $m = TrackData::MODE2_FORM2; >> | Mode2FormMix << $m = TrackData::MODE2_FORM_MIX; >> ) ; subChannelMode > [ TrackData::SubChannelMode m ] : ( SubChanRw << $m = TrackData::SUBCHAN_RW; >> | SubChanRwRaw << $m = TrackData::SUBCHAN_RW_RAW; >> ) ; tocType > [ Toc::TocType t ] : ( TocTypeCdda << $t = Toc::CD_DA; >> | TocTypeCdrom << $t = Toc::CD_ROM; >> | TocTypeCdromXa << $t = Toc::CD_ROM_XA; >> | TocTypeCdi << $t = Toc::CD_I; >> ) ; packType > [ CdTextItem::PackType t, int lineNr ] : ( Title << $t = CdTextItem::CDTEXT_TITLE; $lineNr = $1->getLine(); >> | Performer << $t = CdTextItem::CDTEXT_PERFORMER; $lineNr = $1->getLine(); >> | Songwriter << $t = CdTextItem::CDTEXT_SONGWRITER; $lineNr = $1->getLine(); >> | Composer << $t = CdTextItem::CDTEXT_COMPOSER; $lineNr = $1->getLine(); >> | Arranger << $t = CdTextItem::CDTEXT_ARRANGER; $lineNr = $1->getLine(); >> | Message << $t = CdTextItem::CDTEXT_MESSAGE; $lineNr = $1->getLine(); >> | DiscId << $t = CdTextItem::CDTEXT_DISK_ID; $lineNr = $1->getLine(); >> | Genre << $t = CdTextItem::CDTEXT_GENRE; $lineNr = $1->getLine(); >> | TocInfo1 << $t = CdTextItem::CDTEXT_TOC_INFO1; $lineNr = $1->getLine(); >> | TocInfo2 << $t = CdTextItem::CDTEXT_TOC_INFO2; $lineNr = $1->getLine(); >> | Reserved1 << $t = CdTextItem::CDTEXT_RES1; $lineNr = $1->getLine(); >> | Reserved2 << $t = CdTextItem::CDTEXT_RES2; $lineNr = $1->getLine(); >> | Reserved3 << $t = CdTextItem::CDTEXT_RES3; $lineNr = $1->getLine(); >> | Reserved4 << $t = CdTextItem::CDTEXT_RES4; $lineNr = $1->getLine(); >> | UpcEan << $t = CdTextItem::CDTEXT_UPCEAN_ISRC; $lineNr = $1->getLine(); >> | Isrc << $t = CdTextItem::CDTEXT_UPCEAN_ISRC; $lineNr = $1->getLine(); >> | SizeInfo << $t = CdTextItem::CDTEXT_SIZE_INFO; $lineNr = $1->getLine(); >> ) ; binaryData > [ const unsigned char *data, long len ] : << static unsigned char buf[MAX_CD_TEXT_DATA_LEN]; $data = buf; $len = 0; int i; int lineNr; >> "\{" { integer > [ i, lineNr ] << if (i < 0 || i > 255) { log_message(-2, "%s:%d: Illegal binary data: %d", filename_, lineNr, i); error_ = 1; i = 0; } buf[0] = i; $len = 1; >> ( "," integer > [ i, lineNr ] << if (i < 0 || i > 255) { log_message(-2, "%s:%d: Illegal binary data: %d", filename_, lineNr, i); error_ = 1; i = 0; } if ($len >= MAX_CD_TEXT_DATA_LEN) { log_message(-2, "%s:%d: Binary data exceeds maximum length (%d).", filename_, lineNr, MAX_CD_TEXT_DATA_LEN); error_ = 1; } else { buf[$len] = i; $len += 1; } >> )* } "\}" ; // fail action << $len = 0; >> cdTextItem [ int blockNr ] > [ CdTextItem *item, int lineNr ] : << $item = NULL; CdTextItem::PackType type; const char *s; const unsigned char *data; long len; >> packType > [ type, $lineNr ] ( stringEmpty > [ s ] << if (s != NULL) { $item = new CdTextItem(type, blockNr, s); delete[] s; } >> | binaryData > [ data, len ] << $item = new CdTextItem(type, blockNr, data, len); >> ) ; // fail action << delete $item; $item = NULL; >> cdTextBlock [ CdTextContainer &container, int isTrack ] : << CdTextItem *item = NULL; int blockNr; int lineNr; >> Language integer > [ blockNr, lineNr ] "\{" << if (blockNr < 0 || blockNr > 7) { log_message(-2, "%s:%d: Invalid block number, allowed range: [0..7].", filename_, lineNr); error_ = 1; blockNr = 0; } >> ( cdTextItem [ blockNr ] > [ item, lineNr ] << if (item != NULL) { int type = item->packType(); if (isTrack && ((type > 0x86 && type <= 0x89) || type == 0x8f)) { log_message(-2, "%s:%d: Invalid CD-TEXT item for a track.", filename_, lineNr); error_ = 1; delete item; item = NULL; } else { container.add(item); item = NULL; } } >> )* "\}" ; // fail action << delete item; >> cdTextLanguageMap [ CdTextContainer &container ] : << int blockNr; int lang; int blockNrLine; int langLine = 0; >> LanguageMap "\{" ( integer > [ blockNr, blockNrLine] ":" ( integer > [ lang, langLine ] | LangEn << lang = 9; >> ) << if (blockNr >= 0 && blockNr <= 7) { if (lang >= 0 && lang <= 255) { container.language(blockNr, lang); } else { log_message(-2, "%s:%d: Invalid language code, allowed range: [0..255].", filename_, langLine); error_ = 1; } } else { log_message(-2, "%s:%d: Invalid language number, allowed range: [0..7].", filename_, blockNrLine); error_ = 1; } >> )+ "\}" ; cdTextTrack [ CdTextContainer &container ] : CdText "\{" ( cdTextBlock [ container, 1 ] )* "\}" ; cdTextGlobal [ CdTextContainer &container ] : CdText "\{" { cdTextLanguageMap [ container ] } ( cdTextBlock [ container, 0 ] )* "\}" ; } << ANTLRTokenType TocLexer::erraction() { log_message(-2, "%s:%d: Illegal token: %s", parser_->filename_, _line, _lextext); parser_->error_ = 1; return Eof; } >> << void TocParserGram::syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k) { int line; error_ = 1; line = LT(1)->getLine(); log_message(-2, "%s:%d: syntax error at \"%s\" ", filename_, line, LT(1)->getType() == Eof ? "EOF" : LT(1)->getText()); if ( !etok && !eset ) { log_message(0, ""); return; } if ( k==1 ) { log_message(0, "missing "); } else { log_message(0, "; \"%s\" not ", LT(1)->getText()); if ( set_deg(eset)>1 ) log_message(-2, " in "); } if ( set_deg(eset)>0 ) edecode(eset); else log_message(0, "%s ", token_tbl[etok]); if ( strlen(egroup) > 0 ) log_message(0, "in %s ", egroup); log_message(0, ""); } Toc *parseToc(const char* inp, const char *filename) { DLGStringInput in(inp); TocLexer scan(&in); ANTLRTokenBuffer pipe(&scan); ANTLRToken aToken; scan.setToken(&aToken); TocParserGram parser(&pipe); parser.filename_ = filename; scan.parser_ = &parser; parser.init(); parser.error_ = 0; Toc *t = parser.toc(); if (parser.error_ != 0) { return NULL; } else { return t; } } Toc *parseToc(FILE *fp, const char *filename) { DLGFileInput in(fp); TocLexer scan(&in); ANTLRTokenBuffer pipe(&scan); ANTLRToken aToken; scan.setToken(&aToken); TocParserGram parser(&pipe); parser.filename_ = filename; scan.parser_ = &parser; parser.init(); parser.error_ = 0; Toc *t = parser.toc(); if (parser.error_ != 0) { return NULL; } else { return t; } } >>