summaryrefslogtreecommitdiffabout
authorMichael Krelin <hacker@klever.net>2005-03-30 21:58:44 (UTC)
committer Michael Krelin <hacker@klever.net>2005-03-30 21:58:44 (UTC)
commit5c757590c7561f6d85b3f9011aa0695c4111b379 (patch) (side-by-side diff)
treee0bf20ca58b3e7bd9cc4eda54db5674ba1d71db0
parent3ddbfeafde93d1aab16a710498d86eef4e787406 (diff)
downloadsitecing-5c757590c7561f6d85b3f9011aa0695c4111b379.zip
sitecing-5c757590c7561f6d85b3f9011aa0695c4111b379.tar.gz
sitecing-5c757590c7561f6d85b3f9011aa0695c4111b379.tar.bz2
1. fixed a bug just introduced, preventing the last skeleton-generated file
from being written. 2. introduced pragma directive and pragma main=class 3. minor changes of no importance
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--include/sitecing/sitecing_enflesher.h9
-rw-r--r--include/sitecing/sitecing_parser.h8
-rw-r--r--lib/component_factory.cc2
-rw-r--r--lib/sitecing_enflesher.ll8
-rw-r--r--lib/sitecing_parser.ll49
5 files changed, 72 insertions, 4 deletions
diff --git a/include/sitecing/sitecing_enflesher.h b/include/sitecing/sitecing_enflesher.h
index 8bc43a0..db15bc3 100644
--- a/include/sitecing/sitecing_enflesher.h
+++ b/include/sitecing/sitecing_enflesher.h
@@ -27,53 +27,62 @@ class sitecing_enflesher : public sitecing_enflesherFlexLexer {
public:
/**
* It is time to anchor output with the #line directive.
*/
bool anchor_time;
/**
* The file currently being written is supposed to have #line
* directives all around the place.
*/
bool anchoraged;
/**
* The reference to the parser object containg the parsed source.
*/
sitecing_parser& parser;
/**
* The output stream.
*/
ofstream outs;
/**
* the outs stream destination file.
* @see outs
*/
string outs_filename;
/**
* @param p The parser object containing preparsed data.
*/
sitecing_enflesher(sitecing_parser& p)
: parser(p), anchor_time(true) { }
/**
* Do the job.
*/
void enflesh();
virtual void LexerOutput(const char *buf,int size);
virtual int yylex();
/**
* Put a #line anchor into output.
*/
void anchor();
/**
* Close previously opened output stream, rename to the 'correct'
* destination filename, if needed, and open new file.
* @see outs
* @see outs_filename
+ * @see outs_close
*/
void outs_open(const string& nfile);
+ /**
+ * Close previously opened output stream, and rename to the 'correct'
+ * destination filename, if needed.
+ * @see outs_open
+ * @see outs
+ * @see outs_filename
+ */
+ void outs_close();
};
#endif /* __SITECING_SITECING_ENFLESHER_H */
diff --git a/include/sitecing/sitecing_parser.h b/include/sitecing/sitecing_parser.h
index 22d716f..a8474f3 100644
--- a/include/sitecing/sitecing_parser.h
+++ b/include/sitecing/sitecing_parser.h
@@ -246,81 +246,89 @@ class sitecing_parser : public sitecing_parserFlexLexer {
*/
typedef list<modus_operandi> modi_operandi;
/**
* The modes stack.
*/
modi_operandi modi;
/**
* Input file name.
*/
string input_file;
/**
* Base class name.
*/
string base_class;
/**
* Base class header.
*/
string base_header;
/**
* Component's basename.
* @todo TODO: wish I could remember the details -- document me.
*/
string component_basename;
/**
* The skeleton file name.
*/
string skeleton;
/**
* The component class name.
*/
string class_name;
/**
* Output basename.
* @todo TODO: wish I could remember the details -- document me.
*/
string output_basename;
/**
* Verbatim declaration part.
*/
string decl;
/**
* Verbatim implementation part.
*/
string impl;
/**
* The reference to the component factory object.
*/
component_factory& factory;
+ /**
+ * Pragma map type.
+ */
+ typedef map<string,string> pragmas_t;
+ /**
+ * Pragma's found in the component.
+ */
+ pragmas_t pragmas;
/**
* @param f the component factory.
*/
sitecing_parser(component_factory& f);
/**
* Preprocess file.
* @param in input file name.
*/
void preprocess(const string& in);
virtual void LexerOutput(const char *buf,int size);
virtual int yylex();
/**
* Retrieve reference to the to of the modes stack.
* @return the reference in question.
*/
modus_operandi& M() {
return modi.front();
}
/**
* Anchor the output with the #line, if we're not in the text output mode.
*/
void soft_anchor();
/**
* Anchor the output with the #line directive, changing to the appropriate output mode if needed.
*/
void anchor();
};
#endif /* __SITECING_SITECING_PARSER_H */
diff --git a/lib/component_factory.cc b/lib/component_factory.cc
index b8f5a16..1253111 100644
--- a/lib/component_factory.cc
+++ b/lib/component_factory.cc
@@ -274,59 +274,59 @@ namespace sitecing {
cerr << "executing: " << cmd;
vector<const char*> argv(args.size()+2);
argv[0]=cmd.c_str();
int an = 1;
for(list<string>::const_iterator i=args.begin();i!=args.end();i++) {
cerr << " " << *i ;
argv[an++] = i->c_str();
}
cerr << endl;
argv[an++]=NULL;
pid_t pid = vfork();
if(pid==-1) {
close(stdo); close(stde);
throw konforka::exception(CODEPOINT,"failed to vfork()");
}
if(!pid) {
// child
if(dup2(stdo,1)!=1)
_exit(-1);
if(dup2(stde,2)!=2)
_exit(-1);
close(0);
execvp(cmd.c_str(),(char**)&argv.front());
_exit(-1);
}
// parent
close(stdo); close(stde);
int rv;
if(waitpid(pid,&rv,0)<0)
throw konforka::exception(CODEPOINT,"failed to waitpid()");
return rv;
}
string component_factory::get_classname(const string& component) {
string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".classname";
make(cn);
ifstream ifs(cn.c_str());
if(!ifs.good())
throw konforka::exception(CODEPOINT,"failed to access component .classname");
ifs >> cn;
return cn;
}
void component_factory::get_ancestors(const string& component,file_list_t& rv) {
string cn = root_intermediate+normalize_path(component,strip_trailing_slash|strip_leading_slash)+".ancestors";
make(cn);
ifstream ifs(cn.c_str());
if(!ifs.good())
- throw konforka::exception(CODEPOINT,"filed to access component .ancestors");
+ throw konforka::exception(CODEPOINT,string("failed to access component '")+component+"' .ancestors");
rv.clear();
while(!ifs.eof()) {
string a;
ifs >> a;
if(!a.empty())
rv.push_back(a);
}
}
}
diff --git a/lib/sitecing_enflesher.ll b/lib/sitecing_enflesher.ll
index 46489c7..bb667be 100644
--- a/lib/sitecing_enflesher.ll
+++ b/lib/sitecing_enflesher.ll
@@ -134,121 +134,127 @@ ID [A-Za-z_][A-Za-z0-9_]*
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << "#include \"" << i->path << ".h\"\n";
}
anchor_time = true;
}
\<\%ancestors:component_list\%\> {
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << i->path << "\n";
}
anchor_time = true;
}
\<\%ancestors:base_clause_part\%\> {
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << ", virtual public " << parser.factory.get_classname(i->path);
}
}
\<\%ancestors:typedefs\%\> {
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << "typedef class " << parser.factory.get_classname(i->path) << " " << i->name << ";\n";
}
anchor_time = true;
}
\<\%ancestors:import\%\> {
for(sitecing_parser::ancestor_classes_t::const_iterator i=parser.ancestor_classes.begin();i!=parser.ancestor_classes.end();++i) {
outs << i->name << "::__do_imports();\n";
}
anchor_time = true;
}
\n {
if(anchor_time)
anchor();
ECHO;
}
. ECHO;
%%
void sitecing_enflesher::LexerOutput(const char *buf,int size) {
outs.write(buf,size);
}
void sitecing_enflesher::enflesh() {
ifstream ifs(parser.skeleton.c_str());
if(!ifs.good())
throw preprocessor_error(CODEPOINT,"failed to open skeleton file");
switch_streams(&ifs,NULL);
yylex();
+ outs_close();
}
void sitecing_enflesher::anchor() {
if(!anchoraged)
return;
outs << "\n#line " << lineno() << " \"" << parser.skeleton << "\"\n";
anchor_time = false;
}
-void sitecing_enflesher::outs_open(const string& nfile) {
+void sitecing_enflesher::outs_close() {
if(!outs_filename.empty()) {
outs.flush();
outs.close();
outs.clear();
/*
* compare source and destination files.
*
* one can also keep a hash for the old one and compute one for the
* output while writing, but I'm not sure if it's any better. Surely a
* bit less accurate, unless we're going to compare it in case of
* difference, anyway.
*/
bool overwrite = false;
struct stat st_s, st_d;
string fn_s = outs_filename+".new";
string fn_d = outs_filename;
if(stat(fn_d.c_str(),&st_d)) {
overwrite = true;
}else{
if(stat(fn_s.c_str(),&st_s))
throw preprocessor_error(CODEPOINT,"failed to stat() supposedly created file");
if(st_s.st_size!=st_d.st_size) {
overwrite = true;
}else{
ifstream i_s(fn_s.c_str(),ios::in);
if(!i_s)
throw preprocessor_error(CODEPOINT,"failed to open supposedly created file");
ifstream i_d(fn_d.c_str(),ios::in);
if(!i_d)
throw preprocessor_error(CODEPOINT,"failed to open the old preprocessed source");
off_t remaining = st_s.st_size;
char t1[2048];
char t2[sizeof(t1)];
while(remaining) {
int rb = remaining;
if(rb>sizeof(t1))
rb = sizeof(t1);
if(i_s.read(t1,rb).gcount()!=rb)
throw preprocessor_error(CODEPOINT,"error reading just created file");
if(i_d.read(t2,rb).gcount()!=rb)
throw preprocessor_error(CODEPOINT,"error reading the old preprocessed source");
if(memcmp(t1,t2,rb)) {
overwrite = true;
break;
}
remaining -= rb;
}
}
}
if(overwrite) {
cerr << "renaming '" << fn_s << "'" << endl;
if(rename(fn_s.c_str(),fn_d.c_str()))
throw preprocessor_error(CODEPOINT,"failed to rename() generated output");
}
}
+ outs_filename.erase();
+}
+
+void sitecing_enflesher::outs_open(const string& nfile) {
+ outs_close();
outs_filename = nfile;
outs.open((nfile+".new").c_str(),ios::trunc);
if(!outs.good())
throw preprocessor_error(CODEPOINT,"failed to write preprocessor output");
}
/*
* vim:set ft=lex:
*/
diff --git a/lib/sitecing_parser.ll b/lib/sitecing_parser.ll
index 6cb78f3..8ba8673 100644
--- a/lib/sitecing_parser.ll
+++ b/lib/sitecing_parser.ll
@@ -1,160 +1,195 @@
%{
/*
* XXX: I have a strong feeling that this parser should be completely rewritten.
*/
#include <iostream>
#include <fstream>
#include <cassert>
#include <stdexcept>
using namespace std;
#include "sitecing/sitecing_util.h"
#include "sitecing/sitecing_exception.h"
using namespace sitecing;
#define sitecing_parser_flexlexer_once
#include "sitecing/sitecing_parser.h"
#include "sitecing/sitecing_enflesher.h"
#undef yyFlexLexer
#define yyFlexLexer sitecing_parserFlexLexer
%}
%x SLASHSTAR_COMMENT SLASHSLASH_COMMENT STRING
%x CODELINE CLASSLINE DECLLINE IMPLLINE DECLBLOCK IMPLBLOCK VARLINE VARINIT
%x IMPORTLINE IMPORTCOMPONENT
%x IMPORTTYPELINE IMPORTTYPECOMPONENT
%x DERIVELINE DERIVECOMPONENT
%x CONSTRUCTOR DESTRUCTOR CODEMETHODLINE CODEMETHODARGS
%x CODEMETHODBLOCK INLINE METHODLINE METHODARGS METHODBLOCK CODEBLOCK OUTPUTBLOCK
+%x PRAGMALINE
%option 8bit c++ verbose noyywrap yyclass="sitecing_parser" prefix="sitecing_parser" stack yylineno
WHITESPACE [ \t]
ID [A-Za-z_][A-Za-z0-9_]*
NOIDCHAR [^A-Za-z0-9_]
%%
<INITIAL>{
^\%\%class{WHITESPACE}+ {
// TODO: signal error if we already have class name acquired from source.
modi.push_front(modus_operandi(modus_operandi::flag_devour_comments|modus_operandi::flag_devour_whitespace));
BEGIN(CLASSLINE);
}
^\%\%decl{WHITESPACE}+ {
modi.push_front(modus_operandi(0));
anchor();
BEGIN(DECLLINE);
}
^\%\%impl{WHITESPACE}+ {
modi.push_front(modus_operandi(0));
anchor();
BEGIN(IMPLLINE);
}
\<\%decl\> {
modi.push_front(modus_operandi(0));
anchor();
BEGIN(DECLBLOCK);
}
\<\%impl\> {
modi.push_front(modus_operandi(0));
anchor();
BEGIN(IMPLBLOCK);
}
^\%\%var{WHITESPACE}+ {
modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
anchor();
BEGIN(VARLINE);
}
^\%\%import{WHITESPACE}+ {
modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
BEGIN(IMPORTLINE);
}
^\%\%import_type{WHITESPACE}+ {
modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
BEGIN(IMPORTTYPELINE);
}
^\%\%derive{WHITESPACE}+ {
modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
BEGIN(DERIVELINE);
}
\<\%constructor\> {
modi.push_front(modus_operandi());
anchor();
BEGIN(CONSTRUCTOR);
}
\<\%destructor\> {
modi.push_front(modus_operandi());
anchor();
BEGIN(DESTRUCTOR);
}
\<\%codemethod{WHITESPACE}+ {
modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
anchor();
BEGIN(CODEMETHODLINE);
}
\<\%method{WHITESPACE}+ {
modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
anchor();
BEGIN(METHODLINE);
}
+ ^\%\%pragma{WHITESPACE}+ {
+ modi.push_front(modus_operandi(modus_operandi::flag_devour_comments));
+ BEGIN(PRAGMALINE);
+ }
<<EOF>> {
assert(modi.size()==1);
M().modify(modus_operandi::modus_preop);
LexerOutput(";",1);
return 0;
}
}
<<EOF>> throw preprocessor_error(CODEPOINT,"unexpected end of file",lineno());
<CODEBLOCK,CODEMETHODBLOCK>{
"<%output>" {
anchor();
yy_push_state(OUTPUTBLOCK);
}
}
+<PRAGMALINE>{
+ {WHITESPACE}+ {
+ modus_operandi& m = M();
+ if(!m.output.empty()) {
+ string::size_type eq = m.output.find('=');
+ if(eq==string::npos) {
+ pragmas[m.output]=m.output;
+ }else{
+ pragmas[m.output.substr(0,eq)] = m.output.substr(eq+1);
+ }
+ m.output.erase();
+ }
+ }
+ \n {
+ modus_operandi& m = M();
+ if(!m.output.empty()) {
+ string::size_type eq = m.output.find('=');
+ if(eq==string::npos) {
+ pragmas[m.output]=m.output;
+ }else{
+ pragmas[m.output.substr(0,eq)] = m.output.substr(eq+1);
+ }
+ m.output.erase();
+ }
+ modi.pop_front();
+ BEGIN(INITIAL);
+ anchor();
+ }
+}
+
<METHODLINE>{
{WHITESPACE}+ {
modus_operandi& m = modi.front();
if(!m.output.empty()) {
if(!m._lastid.empty()) {
if(!m._type.empty()) m._type += ' ';
m._type += m._lastid;
}
m._lastid = m.output;
m.output.clear();
}
}
\* {
modus_operandi& m = modi.front();
ECHO;
if(!m._lastid.empty()) {
if(!m._type.empty()) m._type += ' ';
m._type += m._lastid;
}
m._lastid = m.output;
m.output.clear();
}
\( {
modus_operandi& m = modi.front();
if(m.output.empty()) {
m._name=m._lastid;
}else{
if(!m._lastid.empty()) { // XXX: lastid, I believe should never be emtpy...
if(!m._type.empty()) m._type += ' ';
m._type += m._lastid;
}
m._name = m.output;
m.output.clear();
}
ECHO;
BEGIN(METHODARGS);
}
}
<METHODARGS>{
\%\> {
modus_operandi& m = modi.front();
m._args = m.output;
m.output.clear();
anchor();
BEGIN(METHODBLOCK);
}
}
@@ -361,97 +396,97 @@ NOIDCHAR [^A-Za-z0-9_]
if(m.output.empty()) {
m._name=m._lastid;
}else{
if(!m._lastid.empty()) { // XXX: lastid should never be emtpy, I believe?
if(!m._type.empty()) m._type += ' ';
m._type += m._lastid;
}
m._name=m.output;
m.output.clear();
}
BEGIN(VARINIT);
if(*yytext!='=')
unput('\n');
}
}
<VARINIT>{
\n {
modus_operandi& m = modi.front();
string::size_type t = m.output.find_first_not_of(" \t");
if(t!=string::npos)
m.output.erase(0,t);
t = m.output.find_last_not_of(" \t;");
if(t!=string::npos)
m.output.erase(t+1);
member_variables.push_back(member_variable(m._type,m._name,m.output));
if(!m.output.empty())
have_initializers=true;
modi.pop_front();
BEGIN(INITIAL);
}
}
<DECLLINE>\n {
ECHO;
decl += modi.front().output;
modi.pop_front();
BEGIN(INITIAL);
}
<IMPLLINE>\n {
ECHO;
impl += modi.front().output;
modi.pop_front();
BEGIN(INITIAL);
}
<CLASSLINE>\n {
class_name = modi.front().output;
modi.pop_front();
BEGIN(INITIAL);
}
-<CLASSLINE,DECLLINE,IMPLLINE,VARLINE,VARINIT,IMPORTLINE,IMPORTCOMPONENT,CODEMETHODLINE,CODEMETHODARGS,INLINE,METHODLINE,METHODARGS,DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,CODELINE,CODEBLOCK>{
+<CLASSLINE,DECLLINE,IMPLLINE,VARLINE,VARINIT,IMPORTLINE,IMPORTCOMPONENT,CODEMETHODLINE,CODEMETHODARGS,INLINE,METHODLINE,METHODARGS,DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,CODELINE,CODEBLOCK,PRAGMALINE>{
"/*" {
yy_push_state(SLASHSTAR_COMMENT);
if(!M().devour_comments()) {
ECHO;
}
}
"//" {
yy_push_state(SLASHSLASH_COMMENT);
if(!M().devour_comments()) {
ECHO;
}
}
\" {
yy_push_state(STRING);
ECHO;
}
\'\\.\' {
ECHO;
}
}
<INITIAL,METHODBLOCK,OUTPUTBLOCK>{
\" soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\\"",2);
\n soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\n",2);
\r soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\r",2);
\t soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\t",2);
\b soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\b",2);
\a soft_anchor(); M().modify(modus_operandi::modus_text); LexerOutput("\\a",2);
. soft_anchor(); M().modify(modus_operandi::modus_text); ECHO;
{WHITESPACE}+ soft_anchor(); M().modify(modus_operandi::modus_text); ECHO;
}
<DECLBLOCK,IMPLBLOCK,CONSTRUCTOR,DESTRUCTOR,CODEMETHODBLOCK,METHODBLOCK,CODEBLOCK>{
\<\/\%decl\> {
if(YY_START!=DECLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
decl += modi.front().output;
modi.pop_front();
BEGIN(INITIAL);
}
\<\/\%impl\> {
if(YY_START!=IMPLBLOCK) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
impl += modi.front().output;
modi.pop_front();
BEGIN(INITIAL);
}
\<\/\%constructor\> {
if(YY_START!=CONSTRUCTOR) throw preprocessor_error(CODEPOINT,"tags mismatch",lineno());
member_functions.push_back(member_function("","","",modi.front().output));
@@ -501,94 +536,104 @@ NOIDCHAR [^A-Za-z0-9_]
}
}
}
<SLASHSLASH_COMMENT>{
\n {
if(!M().devour_comments()) {
ECHO;
}
yy_pop_state();
if(YY_START!=CODEBLOCK && YY_START!=CODEMETHODBLOCK && YY_START!=IMPLBLOCK && YY_START!=DECLBLOCK)
unput('\n');
}
}
<SLASHSTAR_COMMENT,SLASHSLASH_COMMENT>. {
if(!M().devour_comments()) {
ECHO;
}
}
<STRING>{
\\. ECHO;
\" ECHO; yy_pop_state();
. ECHO;
}
{WHITESPACE}+ {
if(!(M().flags&modus_operandi::flag_devour_whitespace)) {
ECHO;
}
}
%%
sitecing_parser::sitecing_parser(component_factory& f)
: factory(f), have_initializers(false), have_constructor(false),
base_class("sitecing::cgi_component"),
base_header("sitecing/cgi_component.h"),
skeleton(__SC_DEFAULT_SKELETON) {
}
void sitecing_parser::preprocess(const string& in) {
ifstream ifs(in.c_str(),ios::in);
if(!ifs.good())
throw preprocessor_error(CODEPOINT,"failed to open input file");
input_file = in;
modi.push_front(modus_operandi(0));
switch_streams(&ifs,NULL);
if(yylex())
throw preprocessor_error(CODEPOINT,"unknown error");
- member_functions.push_back(member_function("void","main","(int _magic,va_list _args)",M().output));
+ pragmas_t::const_iterator mp = pragmas.find("main");
+ if(mp==pragmas.end()) {
+ member_functions.push_back(member_function("void","main","(int _magic,va_list _args)",M().output));
+ }else{
+ member_functions.push_back(
+ member_function(
+ "void","main","(int _magic,va_list _args)",
+ mp->second+"::main(_magic,_args);"
+ )
+ );
+ }
if(have_initializers && !have_constructor)
member_functions.push_back(member_function("","","",""));
sitecing_enflesher enflesher(*this);
enflesher.enflesh();
}
void sitecing_parser::LexerOutput(const char* buf,int size) {
assert(modi.size());
M().output.append(buf,size);
}
static const char *modus_transitions
[sitecing_parser::modus_operandi::modi]
[sitecing_parser::modus_operandi::modi] = {
// To:
// code preop postop text From:
{ "", "(*(__SCIF->out))", "(*(__SCIF->out))<<", "(*(__SCIF->out))<<\"" }, // code
{ ";", "", "<<", "<<\"" }, // preop
{ NULL, NULL, "", "\"" }, // postop
{ "\";", "\"", "\"<<", "" } // text
};
void sitecing_parser::modus_operandi::modify(modus_t m) {
const char * x = modus_transitions[modus][m];
assert(x);
output += x;
modus = m;
}
void sitecing_parser::soft_anchor() {
if(M().modus!=modus_operandi::modus_text)
anchor();
}
void sitecing_parser::anchor() {
if(M().modus==modus_operandi::modus_text)
M().modify(modus_operandi::modus_preop);
M().output += "\n#line ";
char tmp[7];
snprintf(tmp,sizeof(tmp),"%d",lineno());
M().output += tmp;
M().output += " \"";
M().output += input_file;
M().output += "\"\n";
}
/* vim:set ft=lex: */