summaryrefslogtreecommitdiffstats
path: root/src/languages/asmparser.cpp
blob: eb4b7cd32310a4f03d42bded625c0bf7dbab75d4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   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.                                   *
 ***************************************************************************/

#include "asmparser.h"
#include "config.h"
#include "gpsimprocessor.h"

#include <kdebug.h>
#include <qfile.h>
#include <qregexp.h>

AsmParser::AsmParser( const QString &url )
	: m_url(url)
{
	m_bContainsRadix = false;
	m_type = Absolute;
}


AsmParser::~AsmParser()
{
}


bool AsmParser::parse( GpsimDebugger * debugger )
{
	QFile file(m_url);
	if ( !file.open(IO_ReadOnly) )
		return false;
	
	QTextStream stream( &file );
	
	m_type = Absolute;
	m_bContainsRadix = false;
	m_picID = QString::null;
	
	QStringList nonAbsoluteOps = QStringList::split( ",",
			"code,.def,.dim,.direct,endw,extern,.file,global,idata,.ident,.line,.type,udata,udata_acs,udata_ovr,udata_shr" );
	
	unsigned inputAtLine = 0;
	while ( !stream.atEnd() )
	{
		const QString line = stream.readLine().stripWhiteSpace();
		if ( m_type != Relocatable )
		{
			QString col0 = line.section( QRegExp("[; ]"), 0, 0 );
			col0 = col0.stripWhiteSpace();
			if ( nonAbsoluteOps.contains(col0) )
				m_type = Relocatable;
		}
		if ( !m_bContainsRadix )
		{
			if ( line.contains( QRegExp("^RADIX[\\s]*") ) || line.contains( QRegExp("^radix[\\s]*") ) )
				m_bContainsRadix = true;
		}
		if ( m_picID.isEmpty() )
		{
			// We look for "list p = ", and "list p = picid ", and subtract the positions / lengths away from each other to get the picid text position
			QRegExp fullRegExp("[lL][iI][sS][tT][\\s]+[pP][\\s]*=[\\s]*[\\d\\w]+");
			QRegExp halfRegExp("[lL][iI][sS][tT][\\s]+[pP][\\s]*=[\\s]*");
			
			int startPos = fullRegExp.search(line);
			if ( (startPos != -1) && (startPos == halfRegExp.search(line)) )
			{
				m_picID = line.mid( startPos + halfRegExp.matchedLength(), fullRegExp.matchedLength() - halfRegExp.matchedLength() );
				m_picID = m_picID.upper();
				if ( !m_picID.startsWith("P") )
					m_picID.prepend("P");
			}
		}
#ifndef NO_GPSIM
		if ( debugger && line.startsWith(";#CSRC\t") )
		{
			// Assembly file produced (by sdcc) from C, line is in format:
			// ;#CSRC\t[file-name] [file-line]
			// The filename can contain spaces.
			int fileLineAt = line.findRev(" ");
			
			if ( fileLineAt == -1 )
				kdWarning() << k_funcinfo << "Syntax error in line \"" << line << "\" while looking for file-line" << endl;
			else
			{
				// 7 = length_of(";#CSRC\t")
				QString fileName = line.mid( 7, fileLineAt-7 );
				QString fileLineString = line.mid( fileLineAt+1, line.length() - fileLineAt - 1 );
					
				if ( fileName.startsWith("\"") )
				{
					// Newer versions of SDCC insert " around the filename
					fileName.remove( 0, 1 ); // First "
					fileName.remove( fileName.length()-1, 1 ); // Last "
				}
				
				bool ok;
				int fileLine = fileLineString.toInt(&ok) - 1;
				if ( ok && fileLine >= 0 )
					debugger->associateLine( fileName, fileLine, m_url, inputAtLine );
				else
					kdDebug() << k_funcinfo << "Not a valid line number: \"" << fileLineString << "\"" << endl;
			}
		}
		if ( debugger && (line.startsWith(".line\t") || line.startsWith(";#MSRC") ) )
		{
			// Assembly file produced by either sdcc or microbe, line is in format:
			// \t[".line"/"#MSRC"]\t[file-line]; [file-name]\t[c/microbe source code for that line]
			// We're screwed if the file name contains tabs, but hopefully not many do...
			QStringList lineParts = QStringList::split( '\t', line );
			if ( lineParts.size() < 2 )
				kdWarning() << k_funcinfo << "Line is in wrong format for extracing source line and file: \""<<line<<"\""<<endl;
			else
			{
				const QString lineAndFile = lineParts[1];
				int lineFileSplit = lineAndFile.find("; ");
				if ( lineFileSplit == -1 )
					kdDebug() << k_funcinfo << "Could not find file / line split in \""<<lineAndFile<<"\""<<endl;
				else
				{
					QString fileName = lineAndFile.mid( lineFileSplit + 2 );
					QString fileLineString = lineAndFile.left( lineFileSplit );
					
					if ( fileName.startsWith("\"") )
					{
						// Newer versions of SDCC insert " around the filename
						fileName.remove( 0, 1 ); // First "
						fileName.remove( fileName.length()-1, 1 ); // Last "
					}
				
					bool ok;
					int fileLine = fileLineString.toInt(&ok) - 1;
					if ( ok && fileLine >= 0 )
						debugger->associateLine( fileName, fileLine, m_url, inputAtLine );
					else
						kdDebug() << k_funcinfo << "Not a valid line number: \"" << fileLineString << "\"" << endl;
				}
			}
		}
#endif // !NO_GPSIM
		inputAtLine++;
	}
	
	return true;
}