- fix: Can't parse enum values.
- fix: Can't correctly show enum values in the class browser. - fix: Can't correctly create project, if template's encoding setting is not valid. - enhancement: Add "embed assembly" template.
This commit is contained in:
parent
1b8ff37a60
commit
25d0f5b782
4
NEWS.md
4
NEWS.md
|
@ -20,6 +20,10 @@ Red Panda C++ Version 2.12
|
||||||
- fix: If current editor is empty, parser will parse the file's content on the disk instead from the editor.
|
- fix: If current editor is empty, parser will parse the file's content on the disk instead from the editor.
|
||||||
- fix: Can't show completion when cursor is after "char["
|
- fix: Can't show completion when cursor is after "char["
|
||||||
- change: Don't confirm rebuild/recompile when run/debug.
|
- change: Don't confirm rebuild/recompile when run/debug.
|
||||||
|
- fix: Can't parse enum values.
|
||||||
|
- fix: Can't correctly show enum values in the class browser.
|
||||||
|
- fix: Can't correctly create project, if template's encoding setting is not valid.
|
||||||
|
- enhancement: Add "embed assembly" template.
|
||||||
|
|
||||||
Red Panda C++ Version 2.11
|
Red Panda C++ Version 2.11
|
||||||
|
|
||||||
|
|
|
@ -9456,3 +9456,9 @@ void MainWindow::on_actionNew_GAS_File_triggered()
|
||||||
newEditor("s");
|
newEditor("s");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::on_actionGNU_Assembler_Manual_triggered()
|
||||||
|
{
|
||||||
|
QDesktopServices::openUrl(QUrl("https://sourceware.org/binutils/docs/as/index.html"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -777,6 +777,8 @@ private slots:
|
||||||
|
|
||||||
void on_actionNew_GAS_File_triggered();
|
void on_actionNew_GAS_File_triggered();
|
||||||
|
|
||||||
|
void on_actionGNU_Assembler_Manual_triggered();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
bool mFullInitialized;
|
bool mFullInitialized;
|
||||||
|
|
|
@ -270,6 +270,7 @@
|
||||||
<addaction name="actionDocument"/>
|
<addaction name="actionDocument"/>
|
||||||
<addaction name="actionC_Reference"/>
|
<addaction name="actionC_Reference"/>
|
||||||
<addaction name="actionC_C_Reference"/>
|
<addaction name="actionC_C_Reference"/>
|
||||||
|
<addaction name="actionGNU_Assembler_Manual"/>
|
||||||
<addaction name="actionRaylib_Manual"/>
|
<addaction name="actionRaylib_Manual"/>
|
||||||
<addaction name="actionEGE_Manual"/>
|
<addaction name="actionEGE_Manual"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
@ -3332,6 +3333,11 @@
|
||||||
<string>New GAS File</string>
|
<string>New GAS File</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionGNU_Assembler_Manual">
|
||||||
|
<property name="text">
|
||||||
|
<string>GNU Assembler Manual</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
|
@ -1535,16 +1535,9 @@ QStringList CppParser::sortFilesByIncludeRelations(const QSet<QString> &files)
|
||||||
continue;
|
continue;
|
||||||
//already removed in interalInvalidateFiles
|
//already removed in interalInvalidateFiles
|
||||||
//mPreprocessor.removeScannedFile(file);
|
//mPreprocessor.removeScannedFile(file);
|
||||||
QStringList buffer;
|
|
||||||
if (mOnGetFileStream) {
|
|
||||||
mOnGetFileStream(file,buffer);
|
|
||||||
//prevent preprocessor to read file
|
|
||||||
if (buffer.isEmpty())
|
|
||||||
buffer.append(QString());
|
|
||||||
}
|
|
||||||
//we only use local include relations
|
//we only use local include relations
|
||||||
mPreprocessor.setScanOptions(false, true);
|
mPreprocessor.setScanOptions(false, true);
|
||||||
mPreprocessor.preprocess(file,buffer);
|
mPreprocessor.preprocess(file);
|
||||||
mPreprocessor.clearTempResults();
|
mPreprocessor.clearTempResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2267,8 +2260,11 @@ void CppParser::handleEnum(bool isTypedef)
|
||||||
QString args;
|
QString args;
|
||||||
if (mTokenizer[mIndex]->text!='}') {
|
if (mTokenizer[mIndex]->text!='}') {
|
||||||
while ((mIndex < mTokenizer.tokenCount()) &&
|
while ((mIndex < mTokenizer.tokenCount()) &&
|
||||||
!isblockChar(mTokenizer[mIndex]->text[0])) {
|
mTokenizer[mIndex]->text!='}') {
|
||||||
if (!mTokenizer[mIndex]->text.startsWith(',')) {
|
if (mTokenizer[mIndex]->text=="=") {
|
||||||
|
mIndex=indexOfNextPeriodOrSemicolon(mIndex);
|
||||||
|
continue;
|
||||||
|
} else if (tokenIsIdentifier(mTokenizer[mIndex]->text)) {
|
||||||
cmd = mTokenizer[mIndex]->text;
|
cmd = mTokenizer[mIndex]->text;
|
||||||
args = "";
|
args = "";
|
||||||
if (isEnumClass) {
|
if (isEnumClass) {
|
||||||
|
@ -3793,26 +3789,13 @@ void CppParser::internalParse(const QString &fileName)
|
||||||
// if (!isCfile(fileName) && !isHfile(fileName)) // support only known C/C++ files
|
// if (!isCfile(fileName) && !isHfile(fileName)) // support only known C/C++ files
|
||||||
// return;
|
// return;
|
||||||
|
|
||||||
QStringList buffer;
|
|
||||||
if (mOnGetFileStream) {
|
|
||||||
mOnGetFileStream(fileName,buffer);
|
|
||||||
//prevent preprocessor to read file
|
|
||||||
if (buffer.isEmpty())
|
|
||||||
buffer.append(QString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preprocess the file...
|
// Preprocess the file...
|
||||||
{
|
|
||||||
auto action = finally([this]{
|
auto action = finally([this]{
|
||||||
mTokenizer.clear();
|
mTokenizer.clear();
|
||||||
});
|
});
|
||||||
// Let the preprocessor augment the include records
|
// Let the preprocessor augment the include records
|
||||||
// mPreprocessor.setIncludesList(mIncludesList);
|
|
||||||
// mPreprocessor.setScannedFileList(mScannedFiles);
|
|
||||||
// mPreprocessor.setIncludePaths(mIncludePaths);
|
|
||||||
// mPreprocessor.setProjectIncludePaths(mProjectIncludePaths);
|
|
||||||
mPreprocessor.setScanOptions(mParseGlobalHeaders, mParseLocalHeaders);
|
mPreprocessor.setScanOptions(mParseGlobalHeaders, mParseLocalHeaders);
|
||||||
mPreprocessor.preprocess(fileName, buffer);
|
mPreprocessor.preprocess(fileName);
|
||||||
|
|
||||||
QStringList preprocessResult = mPreprocessor.result();
|
QStringList preprocessResult = mPreprocessor.result();
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
|
@ -3847,7 +3830,6 @@ void CppParser::internalParse(const QString &fileName)
|
||||||
//reduce memory usage
|
//reduce memory usage
|
||||||
internalClear();
|
internalClear();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void CppParser::inheritClassStatement(const PStatement& derived, bool isStruct,
|
void CppParser::inheritClassStatement(const PStatement& derived, bool isStruct,
|
||||||
const PStatement& base, StatementClassScope access)
|
const PStatement& base, StatementClassScope access)
|
||||||
|
@ -5732,7 +5714,6 @@ int CppParser::parserId() const
|
||||||
|
|
||||||
void CppParser::setOnGetFileStream(const GetFileStreamCallBack &newOnGetFileStream)
|
void CppParser::setOnGetFileStream(const GetFileStreamCallBack &newOnGetFileStream)
|
||||||
{
|
{
|
||||||
mOnGetFileStream = newOnGetFileStream;
|
|
||||||
mPreprocessor.setOnGetFileStream(newOnGetFileStream);
|
mPreprocessor.setOnGetFileStream(newOnGetFileStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -671,7 +671,6 @@ private:
|
||||||
#else
|
#else
|
||||||
QMutex mMutex;
|
QMutex mMutex;
|
||||||
#endif
|
#endif
|
||||||
GetFileStreamCallBack mOnGetFileStream;
|
|
||||||
QMap<QString,KeywordType> mCppKeywords;
|
QMap<QString,KeywordType> mCppKeywords;
|
||||||
QSet<QString> mCppTypeKeywords;
|
QSet<QString> mCppTypeKeywords;
|
||||||
};
|
};
|
||||||
|
|
|
@ -155,12 +155,12 @@ void CppPreprocessor::setScanOptions(bool parseSystem, bool parseLocal)
|
||||||
mParseLocal=parseLocal;
|
mParseLocal=parseLocal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::preprocess(const QString &fileName, QStringList buffer)
|
void CppPreprocessor::preprocess(const QString &fileName)
|
||||||
{
|
{
|
||||||
clearTempResults();
|
clearTempResults();
|
||||||
mFileName = fileName;
|
mFileName = fileName;
|
||||||
mDefines = mHardDefines;
|
mDefines = mHardDefines;
|
||||||
openInclude(fileName, buffer);
|
openInclude(fileName);
|
||||||
// StringsToFile(mBuffer,"f:\\buffer.txt");
|
// StringsToFile(mBuffer,"f:\\buffer.txt");
|
||||||
preprocessBuffer();
|
preprocessBuffer();
|
||||||
// StringsToFile(mBuffer,"f:\\buffer.txt");
|
// StringsToFile(mBuffer,"f:\\buffer.txt");
|
||||||
|
@ -456,11 +456,7 @@ void CppPreprocessor::handleInclude(const QString &line, bool fromNext)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PFileIncludes oldCurrentIncludes = mCurrentIncludes;
|
PFileIncludes oldCurrentIncludes = mCurrentIncludes;
|
||||||
QStringList buffer;
|
openInclude(fileName);
|
||||||
if (mOnGetFileStream) {
|
|
||||||
mOnGetFileStream(fileName,buffer);
|
|
||||||
}
|
|
||||||
openInclude(fileName, buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::handlePreprocessor(const QString &value)
|
void CppPreprocessor::handlePreprocessor(const QString &value)
|
||||||
|
@ -659,7 +655,7 @@ void CppPreprocessor::removeGCCAttribute(const QString &line, QString &newLine,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CppPreprocessor::openInclude(const QString &fileName, QStringList bufferedText)
|
void CppPreprocessor::openInclude(const QString &fileName)
|
||||||
{
|
{
|
||||||
if (mIncludes.size()>0) {
|
if (mIncludes.size()>0) {
|
||||||
PParsedFile topFile = mIncludes.front();
|
PParsedFile topFile = mIncludes.front();
|
||||||
|
@ -719,7 +715,8 @@ void CppPreprocessor::openInclude(const QString &fileName, QStringList bufferedT
|
||||||
// Only load up the file if we are allowed to parse it
|
// Only load up the file if we are allowed to parse it
|
||||||
bool isSystemFile = isSystemHeaderFile(fileName, mIncludePaths) || isSystemHeaderFile(fileName, mProjectIncludePaths);
|
bool isSystemFile = isSystemHeaderFile(fileName, mIncludePaths) || isSystemHeaderFile(fileName, mProjectIncludePaths);
|
||||||
if ((mParseSystem && isSystemFile) || (mParseLocal && !isSystemFile)) {
|
if ((mParseSystem && isSystemFile) || (mParseLocal && !isSystemFile)) {
|
||||||
if (!bufferedText.isEmpty()) {
|
QStringList bufferedText;
|
||||||
|
if (mOnGetFileStream && mOnGetFileStream(fileName,bufferedText)) {
|
||||||
parsedFile->buffer = bufferedText;
|
parsedFile->buffer = bufferedText;
|
||||||
} else {
|
} else {
|
||||||
parsedFile->buffer = readFileToLines(fileName);
|
parsedFile->buffer = readFileToLines(fileName);
|
||||||
|
|
|
@ -70,7 +70,7 @@ public:
|
||||||
void getDefineParts(const QString& input, QString &name, QString &args, QString &value);
|
void getDefineParts(const QString& input, QString &name, QString &args, QString &value);
|
||||||
void addHardDefineByLine(const QString& line);
|
void addHardDefineByLine(const QString& line);
|
||||||
void setScanOptions(bool parseSystem, bool parseLocal);
|
void setScanOptions(bool parseSystem, bool parseLocal);
|
||||||
void preprocess(const QString& fileName, QStringList buffer = QStringList());
|
void preprocess(const QString& fileName);
|
||||||
|
|
||||||
void dumpDefinesTo(const QString& fileName) const;
|
void dumpDefinesTo(const QString& fileName) const;
|
||||||
void dumpIncludesListTo(const QString& fileName) const;
|
void dumpIncludesListTo(const QString& fileName) const;
|
||||||
|
@ -122,7 +122,7 @@ private:
|
||||||
PParsedFile getInclude(int index) const {
|
PParsedFile getInclude(int index) const {
|
||||||
return mIncludes[index];
|
return mIncludes[index];
|
||||||
}
|
}
|
||||||
void openInclude(const QString& fileName, QStringList bufferedText=QStringList());
|
void openInclude(const QString& fileName);
|
||||||
void closeInclude();
|
void closeInclude();
|
||||||
|
|
||||||
// branch stuff
|
// branch stuff
|
||||||
|
|
|
@ -921,6 +921,13 @@ bool Project::assignTemplate(const std::shared_ptr<ProjectTemplate> aTemplate, b
|
||||||
updateCompilerSetType();
|
updateCompilerSetType();
|
||||||
mOptions.icon = aTemplate->icon();
|
mOptions.icon = aTemplate->icon();
|
||||||
|
|
||||||
|
QTextCodec* codec=QTextCodec::codecForName(mOptions.encoding);
|
||||||
|
if (!codec)
|
||||||
|
mOptions.encoding=ENCODING_SYSTEM_DEFAULT;
|
||||||
|
codec=QTextCodec::codecForName(mOptions.execEncoding);
|
||||||
|
if (!codec)
|
||||||
|
mOptions.execEncoding=ENCODING_SYSTEM_DEFAULT;
|
||||||
|
|
||||||
// Copy icon to project directory
|
// Copy icon to project directory
|
||||||
if (!mOptions.icon.isEmpty()) {
|
if (!mOptions.icon.isEmpty()) {
|
||||||
QString originIcon = cleanPath(QFileInfo(aTemplate->fileName()).absoluteDir().absoluteFilePath(mOptions.icon));
|
QString originIcon = cleanPath(QFileInfo(aTemplate->fileName()).absoluteDir().absoluteFilePath(mOptions.icon));
|
||||||
|
|
|
@ -4992,6 +4992,10 @@
|
||||||
<source>Please check detail info in "Tools Output" panel.</source>
|
<source>Please check detail info in "Tools Output" panel.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>GNU Assembler Manual</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewClassDialog</name>
|
<name>NewClassDialog</name>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4781,6 +4781,10 @@
|
||||||
<source>Please check detail info in "Tools Output" panel.</source>
|
<source>Please check detail info in "Tools Output" panel.</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>GNU Assembler Manual</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>NewClassDialog</name>
|
<name>NewClassDialog</name>
|
||||||
|
|
|
@ -260,14 +260,13 @@ PClassBrowserNode ClassBrowserModel::addChild(ClassBrowserNode *node, const PSta
|
||||||
.arg(statement->noNameArgs)
|
.arg(statement->noNameArgs)
|
||||||
.arg((int)statement->kind),newNode);
|
.arg((int)statement->kind),newNode);
|
||||||
mProcessedStatements.insert(statement.get());
|
mProcessedStatements.insert(statement.get());
|
||||||
if (statement->kind == StatementKind::skClass
|
if (isScopeStatement(statement)) {
|
||||||
|| statement->kind == StatementKind::skNamespace) {
|
|
||||||
mScopeNodes.insert(statement->fullName,newNode);
|
mScopeNodes.insert(statement->fullName,newNode);
|
||||||
}
|
}
|
||||||
//don't show enum type's children values (they are displayed in parent scope)
|
//don't show enum type's children values (they are displayed in parent scope)
|
||||||
if (statement->kind != StatementKind::skEnumType) {
|
// if (statement->kind != StatementKind::skEnumType) {
|
||||||
filterChildren(newNode.get(), statement->children);
|
filterChildren(newNode.get(), statement->children);
|
||||||
}
|
// }
|
||||||
return newNode;
|
return newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +372,7 @@ void ClassBrowserModel::filterChildren(ClassBrowserNode *node, const StatementMa
|
||||||
if (dummyNode)
|
if (dummyNode)
|
||||||
parentNode = dummyNode;
|
parentNode = dummyNode;
|
||||||
}
|
}
|
||||||
if (statement->kind == StatementKind::skNamespace || statement->kind == StatementKind::skClass) {
|
if (isScopeStatement(statement)) {
|
||||||
//PStatement dummy = mDummyStatements.value(statement->fullName,PStatement());
|
//PStatement dummy = mDummyStatements.value(statement->fullName,PStatement());
|
||||||
PClassBrowserNode scopeNode = mScopeNodes.value(statement->fullName,PClassBrowserNode());
|
PClassBrowserNode scopeNode = mScopeNodes.value(statement->fullName,PClassBrowserNode());
|
||||||
if (!scopeNode) {
|
if (!scopeNode) {
|
||||||
|
@ -415,8 +414,7 @@ ClassBrowserNode* ClassBrowserModel::getParentNode(const PStatement &parentState
|
||||||
return nullptr;
|
return nullptr;
|
||||||
if (!parentStatement)
|
if (!parentStatement)
|
||||||
return mRoot;
|
return mRoot;
|
||||||
if (parentStatement->kind!=skClass
|
if (!isScopeStatement(parentStatement)) {
|
||||||
&& parentStatement->kind!=skNamespace) {
|
|
||||||
return mRoot;
|
return mRoot;
|
||||||
}
|
}
|
||||||
PClassBrowserNode parentNode = mScopeNodes.value(parentStatement->fullName,PClassBrowserNode());
|
PClassBrowserNode parentNode = mScopeNodes.value(parentStatement->fullName,PClassBrowserNode());
|
||||||
|
@ -428,6 +426,19 @@ ClassBrowserNode* ClassBrowserModel::getParentNode(const PStatement &parentState
|
||||||
return parentNode.get();
|
return parentNode.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClassBrowserModel::isScopeStatement(const PStatement &statement)
|
||||||
|
{
|
||||||
|
switch(statement->kind) {
|
||||||
|
case StatementKind::skClass:
|
||||||
|
case StatementKind::skNamespace:
|
||||||
|
case StatementKind::skEnumClassType:
|
||||||
|
case StatementKind::skEnumType:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QModelIndex ClassBrowserModel::modelIndexForStatement(const QString &key)
|
QModelIndex ClassBrowserModel::modelIndexForStatement(const QString &key)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&mMutex);
|
QMutexLocker locker(&mMutex);
|
||||||
|
|
|
@ -75,6 +75,7 @@ private:
|
||||||
void filterChildren(ClassBrowserNode * node, const StatementMap& statements);
|
void filterChildren(ClassBrowserNode * node, const StatementMap& statements);
|
||||||
PStatement createDummy(const PStatement& statement);
|
PStatement createDummy(const PStatement& statement);
|
||||||
ClassBrowserNode* getParentNode(const PStatement &parentStatement, int depth);
|
ClassBrowserNode* getParentNode(const PStatement &parentStatement, int depth);
|
||||||
|
bool isScopeStatement(const PStatement& statement);
|
||||||
private:
|
private:
|
||||||
ClassBrowserNode * mRoot;
|
ClassBrowserNode * mRoot;
|
||||||
QHash<QString,PStatement> mDummyStatements;
|
QHash<QString,PStatement> mDummyStatements;
|
||||||
|
|
|
@ -1615,14 +1615,13 @@ int QSynEdit::calcIndentSpaces(int line, const QString& lineText, bool addIndent
|
||||||
QString firstToken = mSyntaxer->getToken();
|
QString firstToken = mSyntaxer->getToken();
|
||||||
PTokenAttribute attr = mSyntaxer->getTokenAttribute();
|
PTokenAttribute attr = mSyntaxer->getTokenAttribute();
|
||||||
if (
|
if (
|
||||||
( (attr->tokenType() == TokenType::Keyword
|
(attr->tokenType() == TokenType::Keyword
|
||||||
&& (
|
&& (
|
||||||
firstToken == "public" || firstToken == "private"
|
firstToken == "public" || firstToken == "private"
|
||||||
|| firstToken == "protected" || firstToken == "case"
|
|| firstToken == "protected" || firstToken == "case"
|
||||||
|| firstToken == "default"
|
|| firstToken == "default"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|| (attr->tokenType() == TokenType::Identifier))
|
|
||||||
&& lineText.endsWith(':')
|
&& lineText.endsWith(':')
|
||||||
) {
|
) {
|
||||||
// public: private: protecte: case: should indents like it's parent statement
|
// public: private: protecte: case: should indents like it's parent statement
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
[Template]
|
||||||
|
Ver = 3
|
||||||
|
Name = Inline ASM
|
||||||
|
Category = Assembly
|
||||||
|
Description = A simple c program with inline assembly instructions
|
||||||
|
Name[zh_CN] = 内联汇编
|
||||||
|
Category[zh_CN] = 汇编
|
||||||
|
Description[zh_CN] = 简单的C内联汇编程序示例
|
||||||
|
Icon = app.ico
|
||||||
|
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
Type = 1
|
||||||
|
IsCpp = 0
|
||||||
|
Encoding = SYSTEM
|
||||||
|
ClassBrowserType = 0
|
||||||
|
UnitCount = 1
|
||||||
|
|
||||||
|
|
||||||
|
[Unit0]
|
||||||
|
CName=main.c
|
||||||
|
C=main.c
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int add(int x,int y) {
|
||||||
|
int result;
|
||||||
|
asm (
|
||||||
|
"movl %%eax, %1 \n"
|
||||||
|
"addl %%eax, %2 \n"
|
||||||
|
"movl %0, %%eax \n"
|
||||||
|
:"=m"(result) //output operands used in the instructions
|
||||||
|
:"m"(x),"m"(y) //input operands used in the instructions
|
||||||
|
:"eax" //registers changed by the assembler instructions
|
||||||
|
);
|
||||||
|
return x+y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int a,b,c;
|
||||||
|
scanf("%d,%d",&a,&b);
|
||||||
|
c=a+b;
|
||||||
|
printf("%d\n",c);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -2,13 +2,19 @@
|
||||||
|
|
||||||
.text:
|
.text:
|
||||||
main:
|
main:
|
||||||
# the x64 calling convention requires you to allocate 32 bytes of shadow space before each call
|
# Microsoft X86_64 Calling convention:
|
||||||
# https://stackoverflow.com/questions/30190132/what-is-the-shadow-space-in-x64-assembly/
|
# - The first four integer or pointer parameters are passed in the rcx, rdx, r8, and r9 registers.
|
||||||
sub $32, %rsp # allocate shadow space
|
# - The first four floating-point parameters are passed in the first four SSE registers, xmm0-xmm3.
|
||||||
|
# - The caller reserves space on the stack for arguments passed in registers. The called function can use this space to spill the contents of registers to the stack.
|
||||||
|
# - Any additional arguments are passed on the stack.
|
||||||
|
# - An integer or pointer return value is returned in the rax register, while a floating-point return value is returned in xmm0.
|
||||||
|
# see https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture
|
||||||
|
|
||||||
|
sub $32, %rsp # reserve stack space for the call
|
||||||
leaq fmt(%rip), %rcx # first parameter
|
leaq fmt(%rip), %rcx # first parameter
|
||||||
leaq msg(%rip), %rdx # second parameter
|
leaq msg(%rip), %rdx # second parameter
|
||||||
call printf
|
call printf
|
||||||
add $32, %rsp # remove shadow space
|
add $32, %rsp # restore stack space
|
||||||
|
|
||||||
xor %eax,%eax # set 0 as exit code
|
xor %eax,%eax # set 0 as exit code
|
||||||
ret
|
ret
|
||||||
|
|
|
@ -8,13 +8,19 @@ fmt: db "%s", 10, 0 ; The printf format, "\n",'0'
|
||||||
|
|
||||||
section .text:
|
section .text:
|
||||||
main:
|
main:
|
||||||
; the x64 calling convention requires you to allocate 32 bytes of shadow space before each call
|
; Microsoft X86_64 Calling convention:
|
||||||
; https://stackoverflow.com/questions/30190132/what-is-the-shadow-space-in-x64-assembly/
|
; - The first four integer or pointer parameters are passed in the rcx, rdx, r8, and r9 registers.
|
||||||
sub rsp, 32 ; allocate shadow space
|
; - The first four floating-point parameters are passed in the first four SSE registers, xmm0-xmm3.
|
||||||
|
; - The caller reserves space on the stack for arguments passed in registers. The called function can use this space to spill the contents of registers to the stack.
|
||||||
|
; - Any additional arguments are passed on the stack.
|
||||||
|
; - An integer or pointer return value is returned in the rax register, while a floating-point return value is returned in xmm0.
|
||||||
|
; see https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture
|
||||||
|
|
||||||
|
sub rsp, 32 ; reserve stack space for call
|
||||||
lea rcx, [rel fmt] ; first parameter
|
lea rcx, [rel fmt] ; first parameter
|
||||||
lea rdx, [rel msg] ; secodng parameter
|
lea rdx, [rel msg] ; secodng parameter
|
||||||
call printf
|
call printf
|
||||||
|
add rsp,32 ; restore stack
|
||||||
|
|
||||||
add rsp,32 ; remove shadow space
|
|
||||||
mov eax,0 ; exit code
|
mov eax,0 ; exit code
|
||||||
ret
|
ret
|
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
|
@ -0,0 +1,22 @@
|
||||||
|
[Template]
|
||||||
|
Ver = 3
|
||||||
|
Name = Inline ASM
|
||||||
|
Category = Assembly
|
||||||
|
Description = A simple c program with inline assembly instructions
|
||||||
|
Name[zh_CN] = 内联汇编
|
||||||
|
Category[zh_CN] = 汇编
|
||||||
|
Description[zh_CN] = 简单的C内联汇编程序示例
|
||||||
|
Icon = app.ico
|
||||||
|
|
||||||
|
|
||||||
|
[Project]
|
||||||
|
Type = 1
|
||||||
|
IsCpp = 0
|
||||||
|
Encoding = SYSTEM
|
||||||
|
ClassBrowserType = 0
|
||||||
|
UnitCount = 1
|
||||||
|
|
||||||
|
|
||||||
|
[Unit0]
|
||||||
|
CName=main.c
|
||||||
|
C=main.c
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int add(int x,int y) {
|
||||||
|
int result;
|
||||||
|
asm (
|
||||||
|
"movl %%eax, %1 \n"
|
||||||
|
"addl %%eax, %2 \n"
|
||||||
|
"movl %0, %%eax \n"
|
||||||
|
:"=m"(result) //output operands used in the instructions
|
||||||
|
:"m"(x),"m"(y) //input operands used in the instructions
|
||||||
|
:"eax" //registers changed by the assembler instructions
|
||||||
|
);
|
||||||
|
return x+y;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int a,b,c;
|
||||||
|
scanf("%d,%d",&a,&b);
|
||||||
|
c=a+b;
|
||||||
|
printf("%d\n",c);
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue