Click here to Skip to main content
15,897,181 members
Articles / Programming Languages / C++

A scanner and scanner generator

Rate me:
Please Sign up or sign in to vote.
4.95/5 (10 votes)
9 Apr 20012 min read 99.6K   2.7K   33  
Supports both common approaches to scanners in one object.
// ScanGenView.cpp : implementation of the CScanGenView class
//

#include "stdafx.h"
#include "ScanGen.h"

#include "ScanGenDoc.h"
#include "ScanGenView.h"
#include  "direct.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CScanGenView

IMPLEMENT_DYNCREATE(CScanGenView, CFormView)

BEGIN_MESSAGE_MAP(CScanGenView, CFormView)
	//{{AFX_MSG_MAP(CScanGenView)
	ON_WM_SIZE()
	ON_BN_CLICKED(IDC_BUTTON_OPEN, OnButtonOpen)
	ON_BN_CLICKED(IDC_BUTTON_RUN, OnButtonRun)
	ON_BN_CLICKED(IDC_BUTTON_FINAL, OnButtonFinal)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CScanGenView construction/destruction

CScanGenView::CScanGenView()
	: CFormView(CScanGenView::IDD)
{
	//{{AFX_DATA_INIT(CScanGenView)
	m_strTokens = _T("");
	m_bIgnoreCase = FALSE;
	m_strTestSrc = _T("");
	m_strSkip = _T("[ \\t\\v\\r\\n]*");
	m_strTestOutput = _T("");
	//}}AFX_DATA_INIT
	// TODO: add construction code here

}

CScanGenView::~CScanGenView()
{
}

void CScanGenView::DoDataExchange(CDataExchange* pDX)
{
	CFormView::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CScanGenView)
	DDX_Control(pDX, IDC_EDIT_SKIP, m_btnSkip);
	DDX_Control(pDX, IDC_BUTTON_RUN, m_btnRun);
	DDX_Control(pDX, IDC_BUTTON_OPEN, m_btnOpen);
	DDX_Control(pDX, IDC_BUTTON_FINAL, m_btnFinal);
	DDX_Control(pDX, IDC_EDIT_TEST_OUTPUT, m_editTestOutput);
	DDX_Control(pDX, IDC_EDIT_TEST_SRC, m_editTestSrc);
	DDX_Control(pDX, IDC_EDIT_SOURCE, m_editTokens);
	DDX_Text(pDX, IDC_EDIT_SOURCE, m_strTokens);
	DDX_Check(pDX, IDC_CHECK_IGNORECASE, m_bIgnoreCase);
	DDX_Text(pDX, IDC_EDIT_TEST_SRC, m_strTestSrc);
	DDX_Text(pDX, IDC_EDIT_SKIP, m_strSkip);
	DDX_Text(pDX, IDC_EDIT_TEST_OUTPUT, m_strTestOutput);
	//}}AFX_DATA_MAP
}

BOOL CScanGenView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CFormView::PreCreateWindow(cs);
}

void CScanGenView::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();
	GetParentFrame()->RecalcLayout();
	ResizeParentToFit();

}

void CScanGenView::SetInitialExample()
{
    static CString s_strTokens=
                "AVAILABLE\tCANCELLED\tORDERED\tOUT-OF-PRINT\t,\t\\n\r\n"
                 "#T_ISBN= [0-9]\\-[0-9]+\\-[0-9]+\\-[0-9]\t"
                 "#T_TITLE= \"( [^\"\\n] | \\\\\" )* \"\r\n"
                 "#T_ERR_TITLE= \"( [^\"\\n\\0] | \\\\\" )* [\\n\\0] \r\n"
                 "$Int= [0-9]+\t##T_PRICE= $Int (\\. $Int)?";
    static CString s_strHelp=   
        "THIS IS THE HELP: Next Line contains all supported constructs:\r\n"
        "if\t#T_Quote= '[^']'\t$Int= [0-9]+\t##T_FLOAT= $Int (\\. $Int)?\r\n"
        "Above line contains 3 tokens and one helper-definition, each separated by tabs (necessary)\r\n"
        "1. Token (if):\t\t\tThe scanner searches for exactly the word 'if' and automagically creates a constant T_if for the token\r\n"
        "2. Token (#T_Quote= '[^']'):\tThe leading # means: The next identifier up to the = is the name of the token constant, after the = the token definition follows.\r\n"
        "3. Helper ($Int= [0-9]+):\t Defines a helper definition, which can be used later.\r\n"
        "4. Token (##T_FLOAT= $Int (\\. $Int)?):\t The leading ## means: Same as # but do postprocessing after recognizing this token.";
    if( ::IsWindow(m_editTokens.m_hWnd)){
        UpdateData();
    }
    if( s_strTokens==m_strTokens ){
        m_strTokens="";
        m_strTestSrc= "";
        m_bIgnoreCase= false;
        m_strSkip= "[ \\t\\v\\r\\n]*";
    }else{
        m_strTokens= s_strTokens;
        m_strTestSrc= "3-8272-5737-9,AVAILABLE, 72.50,\t\"XML praxis und referenz\"\r\n"
                      "0-201-05866-9,cancelled,150.75,\t\"Parallel Program Design\"\r\n"
                      "0-13-637331-3,ORDERED,50.00,\t\"Operating Systems\r\n"
                      "7-9423-4342-1,OUT-OF-PRINT,100,\"Witchcraft and Computing\"\r\n";
        m_strTestOutput= s_strHelp;
        m_bIgnoreCase=  true;
        m_strSkip=      "[ \\t\\v\\r]*";
    }
    UpdateData(false);
}
/////////////////////////////////////////////////////////////////////////////
// CScanGenView printing

BOOL CScanGenView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CScanGenView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CScanGenView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

void CScanGenView::OnPrint(CDC* pDC, CPrintInfo* /*pInfo*/)
{
	// TODO: add customized printing code here
}

/////////////////////////////////////////////////////////////////////////////
// CScanGenView diagnostics

#ifdef _DEBUG
void CScanGenView::AssertValid() const
{
	CFormView::AssertValid();
}

void CScanGenView::Dump(CDumpContext& dc) const
{
	CFormView::Dump(dc);
}

CScanGenDoc* CScanGenView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CScanGenDoc)));
	return (CScanGenDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CScanGenView message handlers

void CScanGenView::OnSize(UINT nType, int cx, int cy) 
{
	CFormView::OnSize(nType, cx, cy);
    if( cx>0 && cy>0 && ::IsWindow(m_editTokens.m_hWnd)){
        SetScrollSizes(MM_TEXT, CSize(cx,cy));
        CRect rect;
        m_editTokens.GetWindowRect(rect);
        ScreenToClient(&rect);
        m_editTokens.SetWindowPos(NULL,0,0, cx-10-rect.left,cy/2-10, 
            SWP_NOMOVE|SWP_NOZORDER);
        m_btnOpen.SetWindowPos(NULL,rect.left,cy/2+20,0,0,SWP_NOSIZE|SWP_NOZORDER);
        m_btnRun.SetWindowPos(NULL,cx/2+10,cy/2+20,0,0,SWP_NOSIZE|SWP_NOZORDER);
        m_editTestSrc.SetWindowPos(NULL,rect.left,cy/2+45,cx/2-10-rect.left,cy/2-45,SWP_NOZORDER);
        m_editTestOutput.SetWindowPos(NULL,cx/2+10,cy/2+45,cx/2-10-rect.left,cy/2-45,SWP_NOZORDER);
    }
}

void CScanGenView::Serialize(CArchive& ar) 
{
	if (ar.IsStoring())
	{
        UpdateData();
        ar  <<  m_strTokens;
        ar  <<  m_strSkip;
        ar  <<  m_bIgnoreCase;
	}
	else
	{	
        ar  >>  m_strTokens;
        ar  >>  m_strSkip;
        ar  >>  m_bIgnoreCase;
        UpdateData(false);
	}
}

void CScanGenView::OnButtonOpen() 
{
    CFileDialog dlg(true);
    if( dlg.DoModal()==IDOK ){
        CFile file;
        if( file.Open(dlg.GetPathName(),CFile::modeRead) ){
            CString str;
            file.Read(str.GetBufferSetLength(file.GetLength()),file.GetLength());
            m_editTestSrc.SetWindowText(str);
        }
    }	
}

bool CScanGenView::HasError(REXI_DefErr err)
{
    if( err.eErrCode!= REXI_DefErr::eNoErr ){
        AfxMessageBox(err.strErrMsg.c_str());
        m_editTokens.SetFocus();
        m_editTokens.SetSel(err.nErrOffset,err.nErrOffset);
        return true;
   }
   return false;
}

void CScanGenView::OnButtonRun() 
{
    CWaitCursor wait;
	UpdateData();
    pair<REXI_DefErr,CScanGeneratedScanner>  res;
    CString strTokens=  m_strTokens+"\n\n";
    CString strSkip=    m_strSkip+"\n\n";
    res= m_scanGenAlgo.GenScanner(strTokens,strSkip,m_bIgnoreCase?true:false);
    if( HasError(res.first) ){
        return;
    }
    m_btnFinal.EnableWindow(true);
    GetDlgItem(IDC_EDIT_TEST_OUTPUT)->SetWindowText("");
    REXI_DefErr err= res.second.InitScanner(m_strTestSrc);
    if( HasError(err) ){
        return;
    }
    string  strTokenId;
    int     nOfLineBreaksBefore,nNofLineBreaksIn;
    string  strOutput;
    int nAnswer;
    while((nAnswer=res.second.Scan(strTokenId,nOfLineBreaksBefore,nNofLineBreaksIn))!=REXA_DFAState::eEos){
        int i;
        for(i=0;i<nOfLineBreaksBefore;i++){
            strOutput+= "\r\n";
        }
        strOutput+= strTokenId + " ";
        for(i=0;i<nNofLineBreaksIn;i++){
            strOutput+= "\r\n";
        }
    }
    m_strTestOutput= strOutput.c_str();
    UpdateData(false);
}
string CScanGenView::GetScannerName()
{
    m_strScannerName= GetDocument()->GetTitle();
    string::size_type n;
    if((n=m_strScannerName.rfind('.'))!=string::npos  ){
        m_strScannerName= m_strScannerName.substr(0,n);
    }
    for(int i=0;i<m_strScannerName.size();i++){
        if(!isalnum(m_strScannerName[i])){
            m_strScannerName[i]= '_';
        }
    }
    return m_strScannerName;
}
string CScanGenView::CreateScannerDir(string strScannerName)
{   
    char aFileName[1024];
    unsigned nRes= GetModuleFileName(NULL,aFileName,sizeof(aFileName)-1);
    string strDir(aFileName);
    string::size_type nPos;
    if(     (nPos=strDir.rfind('\\')) != string::npos ){
        strDir= strDir.substr(0,nPos);
        if(     (nPos=strDir.rfind('\\')) != string::npos  
            &&  strDir.substr(0,nPos).rfind('\\')!=string::npos ){
            strDir= strDir.substr(0,nPos);
        }
    }
    strDir+= "\\"+strScannerName;
    mkdir(strDir.c_str());
    return  strDir;
}
void     CScanGenView::SaveToFile(string strFileName,string strFileContent)
{
    CFile file;
    if( file.Open(strFileName.c_str(),CFile::modeCreate|CFile::modeWrite) ){
        file.Write(strFileContent.c_str(),strFileContent.size());
    }
}
bool  CScanGenView::FindThis(string s, string sToFind,string& sVers)
{
    string::size_type n= s.find(sToFind);
    if( n!=string::npos && n+sToFind.size()+2 < s.size()  ){
        string sFound= s.substr(n+sToFind.size(),2);
        if( isdigit(sFound[0])&&isdigit(sFound[1]) ){
            sVers= sFound;
            return true;
        }
    }
    return false;
}
bool  CScanGenView::GetVersionInfo(string strFileName,string& sMajor,string& sMinor)
{
    bool bFound= false;
    CFile file;
    if( file.Open(strFileName.c_str(),CFile::modeRead) ){
        const string sToFind("::m_pcszVersMajor[3]=\"");
        string s(file.GetLength()+1,'\0');
        file.Read((void*)s.c_str(),file.GetLength());
        bFound=    FindThis(s,"::m_pcszVersMajor[3]=\"",sMajor)
                    &&  FindThis(s,"::m_pcszVersMinor[3]=\"",sMinor);
    }
    return bFound;
}
bool CScanGenView::ExistsFile(string strFileName)
{
    CFile file;
    return file.Open(strFileName.c_str(),CFile::modeRead)!=0;
}
void  CScanGenView::GenSourceFiles(CScanGeneratedScanner& rScanner)
{
    Sources sources;
    string  sMinor="00",sMajor="01";
    string  strScannerDir= CreateScannerDir(m_strScannerName);
    string  strBaseFileName=  strScannerDir+"\\"+m_strScannerName;
    if( GetVersionInfo(strBaseFileName+".cpp",sMajor,sMinor) ){
        if( sMinor[1]=='9' ){
            sMinor[0]= (sMinor[0]-'0')+1+'0';
            sMinor[1]= '0';
        }else{
            sMinor[1]= (sMinor[1]-'0')+1+'0';
        }
    }
    if( rScanner.GenSourceCode(m_strScannerName.c_str(),sMajor,sMinor,sources) ){
        SaveToFile(strBaseFileName+".h",sources.m_headerCpp.first);
        SaveToFile(strBaseFileName+".cpp",sources.m_headerCpp.second);
        SaveToFile(strBaseFileName+"Main.cpp",sources.m_strMain);
        if( !ExistsFile(strBaseFileName+".dsp") ){
            SaveToFile(strBaseFileName+".dsp",sources.m_strDsp);
        }
    }
}

void CScanGenView::OnButtonFinal() 
{
	UpdateData();
    CWaitCursor wait;
    pair<REXI_DefErr,CScanGeneratedScanner>  res;
    CString strTokens= m_strTokens+"\n\n";
    CString strSkip= m_strSkip+ "\n\n";
    res= m_scanGenAlgo.GenScanner(strTokens,strSkip,m_bIgnoreCase?true:false);
    if( HasError(res.first) ){
        return;
    }
    GetScannerName();
    GenSourceFiles(res.second);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Switzerland Switzerland
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions