Compare commits

...

32 Commits

Author SHA1 Message Date
Renan Ribeiro 7a3762148f
Merge e8e0c41f87 into b1e1c13d4b 2024-05-01 00:19:45 +03:00
Bob Andrews b1e1c13d4b
Merge pull request #2437 from bbbradsmith/sim65-examples
provide simple examples for using sim65 with C and assembly code
2024-04-25 23:52:08 +02:00
bbbradsmith 8804dc7a58 give cl65 alternative 2024-04-16 16:56:13 -04:00
bbbradsmith 4bc726ebe2 clarify the meaning of the exit code unsigned limitation 2024-04-16 16:41:00 -04:00
bbbradsmith fa1a426c29 add -t sim6502 to cc65 and ca65 examples 2024-04-16 14:06:45 -04:00
bbbradsmith 89b709c7f8 make it clearer that explicit lib is required, note that exit is from stdlib.h, exit codes are unsigned, tweak "see below" for spacing, clarify that assembly can be used with C tests as well 2024-03-28 16:55:55 -04:00
bbbradsmith 79585194e6 provide simple examples for using sim65 with C and assembly code 2024-03-28 16:33:20 -04:00
cosineblast e8e0c41f87 Fix style issue in preproc.c 2024-01-19 21:21:46 -03:00
cosineblast 8e17cc2692 Remove useless function prototype in pathutil.c 2024-01-19 13:06:11 -03:00
cosineblast 7a5526b19e Remove symlink from tests 2024-01-18 20:13:47 -03:00
cosineblast d4c7cba521 Update documentation tt tag 2024-01-17 20:36:28 -03:00
cosineblast 9c877fa529 Fix documentation label issue 2024-01-17 19:36:25 -03:00
cosineblast e10647dca6 Add pathutil.c comments and improve version macros 2024-01-17 19:23:09 -03:00
cosineblast dfbfe79c71 Add minimum version for pathutil.c 2024-01-17 19:15:59 -03:00
cosineblast 6e203ab2d2 Improve pathutil.c style 2024-01-17 17:47:08 -03:00
cosineblast 57e6c2a4f9 Make pragma once work even in .c files 2024-01-17 17:45:11 -03:00
cosineblast 98208e7e95 Add pragma once to the documentation 2024-01-17 16:49:47 -03:00
cosineblast 30ff2bdc6b Add pragma once tests 2024-01-17 15:05:27 -03:00
cosineblast 167c31c148 Update FindRealPath function object name 2024-01-17 00:47:53 -03:00
cosineblast a6f207a2a5 Improve FindAbsolutePath documentation and API 2024-01-17 00:33:49 -03:00
cosineblast 346dd7df85 Remove symlink resolve from searchpath to maintain behaviour 2024-01-17 00:07:07 -03:00
cosineblast aa47b6c1c7 Refactor include file searching 2024-01-16 19:49:47 -03:00
cosineblast 085509c2e1 Improve FindAbsolutePath implementation 2024-01-16 16:02:57 -03:00
cosineblast d34a6df002 Improve preprocessor pragma once implementation
Pragma once checking now happens in #include
2024-01-14 19:43:34 -03:00
cosineblast 42a93f00d4 Add StrPool lookup 2024-01-14 19:43:05 -03:00
cosineblast acf9676c0f Move FindAbsolutePath to another .c 2024-01-13 00:30:58 -03:00
cosineblast 7798c7a471 Include corret header for windows 2024-01-12 20:48:05 -03:00
cosineblast fc619573b4 Add <windef.h> on windows 2024-01-12 18:36:38 -03:00
cosineblast 9d50090769 Update windows build FindAbsolutePath bug 2024-01-12 18:29:54 -03:00
cosineblast c0285cadc8 Update style to conform to rules 2024-01-12 11:45:59 -03:00
cosineblast 6a276ccac3 Implement pragma once 2024-01-12 10:07:13 -03:00
cosineblast 9d32a84f69 Add pragma result status enum
Makes so that preprocessing a pragma yields a status flag with additional information on how to handle that particular #pragma.
Mostly a prepraration for #pragma once.
2024-01-10 20:19:04 -03:00
14 changed files with 393 additions and 25 deletions

View File

@ -1681,6 +1681,16 @@ void somefunc2(int, char *);
</verb></tscreen>
<sect1><tt>#pragma once</tt><label id="pragma-once"><p>
This pragma is used to prevent multiple inclusion of a header file.
If this pragma is preprocessed in a file, any posterior
<tt>#include</tt> which targets the current file will be ignored.
Two files are considered to be the same by this directive if they
share the same absolute path. In the case of symbolic links,
the canonical, resolved path is considered instead.
<sect>Register variables<label id="register-vars"><p>

View File

@ -115,37 +115,78 @@ PVExit ($01)
<sect>Creating a Test in C<p>
For a C test compiled and linked with <tt/--target sim6502/ the
For a C test linked with <tt/--target sim6502/ and the <tt/sim6502.lib/ library,
command line arguments to <tt/sim65/ will be passed to <tt/main/,
and the return value from <tt/main/ will become sim65's exit code.
The <tt/exit/ function may also be used to terminate with an exit code.
The <tt/stdlib.h/ <tt/exit/ function may also be used to terminate with an exit code.
Exit codes are limited to 8 bits.
Exit codes are limited to an unsigned 8 bit value. (E.g. returning -1 will give an exit code of 255.)
The standard C library high level file input and output is functional.
A sim65 application can be written like a command line application,
providing arguments to <tt/main/ and using the <tt/stdio.h/ interfaces.
providing command line arguments to <tt/main/ and using the <tt/stdio.h/ interfaces
to interact with the console or access files.
Internally, file input and output is provided at a lower level by
a set of built-in paravirtualization functions (<ref id="paravirt-internal" name="see below">).
a set of built-in paravirtualization functions (see <ref id="paravirt-internal" name="below">).
Example:
<tscreen><verb>
#include <stdio.h>
int main()
{
printf("Hello!\n");
return 5;
}
// Build and run:
// cl65 -t sim6502 -o example.prg example.c
// sim65 example.prg
// Build and run, separate steps:
// cc65 -t sim6502 -o example.s example.c
// ca65 -t sim6502 -o example.o example.s
// ld65 -t sim6502 -o example.prg example.o sim6502.lib
// sim65 example.prg
</verb></tscreen>
<sect>Creating a Test in Assembly<p>
Assembly tests may similarly be assembled and linked with
<tt/--target sim6502/ or <tt/--target sim65c02/.
Define and export <tt/_main/ as an entry point,
Though a C test may also link with assembly code,
a pure assembly test can also be created.
Link with <tt/--target sim6502/ or <tt/--target sim65c02/ and the corresponding library,
define and export <tt/_main/ as an entry point,
and the sim65 library provides two ways to return an 8-bit exit code:
<itemize>
<item>Return from <tt/_main/ with the exit code in <tt/A/.
<item><tt/jmp exit/ with the code in <tt/A/.
<item><tt/jmp exit/ with the code in <tt/A/. (<tt/.import exit/ from the sim65 library.)
</itemize>
The binary file has a 12 byte header:
Example:
<tscreen><verb>
.export _main
_main:
lda #5
rts
; Build and run:
; cl65 -t sim6502 -o example.prg example.s
; sim65 example.prg
; Build and run, separate steps:
; ca65 -t sim6502 -o example.o example.s
; ld65 -t sim6502 -o example.prg example.o sim6502.lib
; sim65 example.prg
</verb></tscreen>
Internally, the binary program file has a 12 byte header provided by the library:
<itemize>
@ -182,6 +223,9 @@ These use cc65 calling conventions, and are intended for use with the sim65 targ
<item><tt/IRQ/ and <tt/NMI/ events will not be generated, though <tt/BRK/
can be used if the IRQ vector at <tt/$FFFE/ is manually prepared by the test code.
<item>The <tt/sim6502/ or <tt/sim65c02/ targets provide a default configuration,
but if customization is needed <tt/sim6502.cfg/ or <tt/sim65c02.cfg/ might be used as a template.
</itemize>

View File

@ -45,6 +45,7 @@
#include "print.h"
#include "strbuf.h"
#include "xmalloc.h"
#include "pathutil.h"
/* cc65 */
#include "codegen.h"
@ -296,10 +297,11 @@ void OpenMainFile (const char* Name)
void OpenIncludeFile (const char* Name, InputType IT)
void OpenIncludeFile (const char* Name, InputType IT, StringPool *FilesToIgnore)
/* Open an include file and insert it into the tables. */
{
char* N;
char* M;
FILE* F;
IFile* IF;
AFile* AF;
@ -317,6 +319,23 @@ void OpenIncludeFile (const char* Name, InputType IT)
return;
}
/* Resolve real path of file in case of a symlink */
M = FindRealPath(N);
if (M == 0) {
PPError ("Cannot resolve absolute path of '%s'", N);
xfree (N);
return;
}
if (SP_LookupStr(FilesToIgnore, M) != 0) {
/* This file should not be included. */
xfree (M);
xfree (N);
return;
}
xfree (M);
/* Search the list of all input files for this file. If we don't find
** it, create a new IFile object.
*/

View File

@ -43,6 +43,7 @@
/* common */
#include "coll.h"
#include "strbuf.h"
#include "strpool.h"
@ -83,8 +84,10 @@ extern char NextC;
void OpenMainFile (const char* Name);
/* Open the main file. Will call Fatal() in case of failures. */
void OpenIncludeFile (const char* Name, InputType IT);
/* Open an include file and insert it into the tables. */
void OpenIncludeFile (const char* Name, InputType IT, StringPool* FilesToIgnore);
/* Open an include file and insert it into the tables.
** Does nothing if the resolved file is present in the pool.
*/
void CloseIncludeFile (void);
/* Close an include file and switch to the higher level file. Set Input to

View File

@ -44,6 +44,9 @@
#include "inline.h"
#include "print.h"
#include "xmalloc.h"
#include "strpool.h"
#include "abend.h"
#include "pathutil.h"
/* cc65 */
#include "codegen.h"
@ -113,6 +116,8 @@ static StrBuf* PLine; /* Buffer for macro expansion */
static StrBuf* MLine; /* Buffer for macro expansion in #pragma */
static StrBuf* OLine; /* Buffer for #pragma output */
static StringPool* PragmaOnceSeenFiles;
/* Newlines to be added to preprocessed text */
static unsigned PendingNewLines;
static unsigned ContinuedLines;
@ -2804,7 +2809,6 @@ static int DoIfDef (int skip, int flag)
}
static void DoInclude (void)
/* Open an include file. */
{
@ -2854,8 +2858,8 @@ static void DoInclude (void)
NextChar ();
/* Check for extra tokens following the filename */
CheckExtraTokens ("include");
/* Open the include file */
OpenIncludeFile (SB_GetConstBuf (&Filename), IT);
/* Open the include file, if it is not marked with #pragma once */
OpenIncludeFile (SB_GetConstBuf (&Filename), IT, PragmaOnceSeenFiles);
} else {
/* No terminator found */
PPError ("#include expects \"FILENAME\" or <FILENAME>");
@ -2963,14 +2967,28 @@ static void DoLine (void)
MLine = InitLine (MLine);
}
static void DoPragmaOnce (void)
/* Marks the current file as seen by #pragma once. */
{
const char * const Filename = GetCurrentFilename ();
char * const FullPath = FindRealPath (Filename);
if (FullPath == NULL) {
AbEnd ("Failed to find the real path for the file %s", Filename);
}
SP_AddStr (PragmaOnceSeenFiles, FullPath);
free (FullPath);
}
static void DoPragma (void)
/* Handle a #pragma line by converting the #pragma preprocessor directive into
** the _Pragma() compiler operator.
*/
{
StrBuf* PragmaLine = OLine;
StrBuf* const PragmaLine = OLine;
PRECONDITION (PragmaLine != 0);
@ -2981,11 +2999,16 @@ static void DoPragma (void)
SB_Clear (MLine);
PreprocessDirective (Line, MLine, MSM_NONE);
/* Convert #pragma to _Pragma () */
SB_AppendStr (PragmaLine, "_Pragma (");
SB_Reset (MLine);
Stringize (MLine, PragmaLine);
SB_AppendChar (PragmaLine, ')');
if (SB_CompareStr(MLine, "once") == 0) {
DoPragmaOnce ();
}
else {
/* Convert #pragma to _Pragma () */
SB_AppendStr (PragmaLine, "_Pragma (");
SB_Reset (MLine);
Stringize (MLine, PragmaLine);
SB_AppendChar (PragmaLine, ')');
}
/* End this line */
SB_SetIndex (PragmaLine, SB_GetLen (PragmaLine));
@ -3157,6 +3180,7 @@ static int ParseDirectives (unsigned ModeFlags)
if (!PPSkip) {
if ((ModeFlags & MSM_IN_ARG_LIST) == 0) {
DoPragma ();
return Whitespace;
} else {
PPError ("Embedded #pragma directive within macro arguments is unsupported");
@ -3348,6 +3372,9 @@ void InitPreprocess (void)
/* Create the output buffers */
MLine = NewStrBuf ();
PLine = NewStrBuf ();
/* 64 is a sensible number of slots for the hash table */
PragmaOnceSeenFiles = NewStringPool(64);
}
@ -3358,6 +3385,7 @@ void DonePreprocess (void)
/* Done with the output buffers */
SB_Done (MLine);
SB_Done (PLine);
FreeStringPool(PragmaOnceSeenFiles);
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
@ -110,6 +110,7 @@
<ClInclude Include="common\objdefs.h" />
<ClInclude Include="common\optdefs.h" />
<ClInclude Include="common\print.h" />
<ClInclude Include="common\pathutil.h" />
<ClInclude Include="common\scopedefs.h" />
<ClInclude Include="common\searchpath.h" />
<ClInclude Include="common\segdefs.h" />
@ -155,6 +156,7 @@
<ClCompile Include="common\matchpat.c" />
<ClCompile Include="common\mmodel.c" />
<ClCompile Include="common\print.c" />
<ClCompile Include="common\pathutil.c" />
<ClCompile Include="common\searchpath.c" />
<ClCompile Include="common\segnames.c" />
<ClCompile Include="common\shift.c" />
@ -171,4 +173,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

119
src/common/pathutil.c Normal file
View File

@ -0,0 +1,119 @@
/*****************************************************************************/
/* */
/* pathutil.c */
/* Path manipulation utilities */
/* */
/* */
/* */
/* (C) 2003-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#if defined(_WIN32)
#if !defined(_WIN32_WINNT) && !defined(NTDDI_VERSION)
/* Set minimum windows version for GetFinalPathNameByHandleA */
/* NTDDI_VISTA */
#define NTDDI_VERSION 0x06000000
/* _WIN32_WINNT_VISTA */
#define _WIN32_WINNT 0x600
#endif
#include "xmalloc.h"
#include <windows.h>
#include <fileapi.h>
#endif
#include <stdlib.h>
/*****************************************************************************/
/* code */
/*****************************************************************************/
#if defined(_WIN32)
char *FindRealPath (const char *Path)
/*
** Returns a malloced buffer containing the canonical path of the given path.
** If the path points to a non-existent file, or if any error occurs, NULL is returned.
** If the path points to a symlink, the resolved symlink path is returned.
** Note: The returned path's separator is system specific.
*/
{
HANDLE Handle = CreateFileA (Path,
FILE_READ_ATTRIBUTES,
FILE_SHARE_READ |
FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (Handle == INVALID_HANDLE_VALUE) {
return NULL;
}
size_t BufferSize = MAX_PATH + 10;
char* Buffer = xmalloc (BufferSize);
DWORD Status = GetFinalPathNameByHandleA (Handle,
Buffer,
BufferSize,
FILE_NAME_NORMALIZED
| VOLUME_NAME_DOS);
if (Status == 0) {
xfree (Buffer);
CloseHandle (Handle);
return NULL;
}
CloseHandle (Handle);
return Buffer;
}
#else
char* FindRealPath (const char* path)
/*
** Returns a malloced buffer containing the canonical path of the given path.
** If the path points to a non-existent file, or if any error occurs, NULL is returned.
** If the path points to a symlink, the resolved symlink path is returned.
** Note: The returned path's separator is system specific.
*/
{
return realpath (path, NULL);
}
#endif

55
src/common/pathutil.h Normal file
View File

@ -0,0 +1,55 @@
/*****************************************************************************/
/* */
/* pathutil.h */
/* Path manipulation utilities */
/* */
/* */
/* */
/* (C) 2003-2008 Ullrich von Bassewitz */
/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
/* */
/* This software is provided 'as-is', without any expressed or implied */
/* warranty. In no event will the authors be held liable for any damages */
/* arising from the use of this software. */
/* */
/* Permission is granted to anyone to use this software for any purpose, */
/* including commercial applications, and to alter it and redistribute it */
/* freely, subject to the following restrictions: */
/* */
/* 1. The origin of this software must not be misrepresented; you must not */
/* claim that you wrote the original software. If you use this software */
/* in a product, an acknowledgment in the product documentation would be */
/* appreciated but is not required. */
/* 2. Altered source versions must be plainly marked as such, and must not */
/* be misrepresented as being the original software. */
/* 3. This notice may not be removed or altered from any source */
/* distribution. */
/* */
/*****************************************************************************/
#ifndef PATHUTIL_H
#define PATHUTIL_H
/*****************************************************************************/
/* Code */
/*****************************************************************************/
char *FindRealPath (const char *path);
/*
** Returns a malloced buffer containing the canonical path of the given path.
** If the path points to a non-existent file, or if any error occurs, NULL is returned.
** If the path points to a symlink, the resolved symlink path is returned.
** Note: The returned path's separator is system specific.
*/
/* End of pathutil.h */
#endif

View File

@ -377,6 +377,7 @@ char* SearchFile (const SearchPaths* P, const char* File)
SB_AppendStr (&PathName, File);
SB_Terminate (&PathName);
/* Check if this file exists */
if (access (SB_GetBuf (&PathName), 0) == 0) {
/* The file exists, we're done */

View File

@ -281,3 +281,22 @@ unsigned SP_GetCount (const StringPool* P)
{
return CollCount (&P->Entries);
}
unsigned SP_Lookup(StringPool *P, const StrBuf *S)
/*
** Determine whether the given string is in the pool.
** Returns 1 if the string is in the pool, 0 otherwise.
*/
{
return HT_Find (&P->Tab, S) != 0;
}
unsigned SP_LookupStr(StringPool *P, const char *S)
/*
** Determine whether the given string is in the pool.
** Returns 1 if the string is in the pool, 0 otherwise.
*/
{
StrBuf Buf;
return SP_Lookup (P, SB_InitFromString (&Buf, S));
}

View File

@ -84,7 +84,7 @@ const StrBuf* SP_Get (const StringPool* P, unsigned Index);
unsigned SP_Add (StringPool* P, const StrBuf* S);
/* Add a string buffer to the buffer and return the index. If the string does
** already exist in the pool, SP_AddBuf will just return the index of the
** already exist in the pool, SP_Add will just return the index of the
** existing string.
*/
@ -96,6 +96,18 @@ unsigned SP_AddStr (StringPool* P, const char* S);
unsigned SP_GetCount (const StringPool* P);
/* Return the number of strings in the pool */
unsigned SP_Lookup(StringPool *P, const StrBuf *S);
/*
** Determine whether the given string is in the pool.
** Returns 1 if the string is in the pool, 0 otherwise.
*/
unsigned SP_LookupStr(StringPool *P, const char *S);
/*
** Determine whether the given string is in the pool.
** Returns 1 if the string is in the pool, 0 otherwise.
*/
/* End of strpool.h */

View File

@ -0,0 +1,8 @@
/*
** !!DESCRIPTION!! Simple #pragma once directive tests
** !!ORIGIN!! cc65 regression tests
** !!LICENCE!! Public Domain
*/
#include "pragma-once-sample.h";

View File

@ -0,0 +1,21 @@
/*
** !!DESCRIPTION!! Simple #pragma once directive tests
** !!ORIGIN!! cc65 regression tests
** !!LICENCE!! Public Domain
*/
#ifdef FILE_INCLUDED
#error "This file should not have been included twice"
#define INCLUDED_TWICE
#else
#define FILE_INCLUDED
#endif
/* a pragma once directive should work regardless of where it is located in
the file, as long as it is seen by the preprocessor */
#pragma once

View File

@ -0,0 +1,27 @@
/*
** !!DESCRIPTION!! Simple #pragma once directive tests
** !!ORIGIN!! cc65 regression tests
** !!LICENCE!! Public Domain
*/
#pragma once
#include "pragma-once-sample-2.h"
#include "pragma-once-sample-2.h"
#include "pragma-once-sample.h"
#include "pragma-once-sample.h"
#include <stdio.h>
int main() {
#ifdef INCLUDED_TWICE
printf("pragma-once-sample.h included more than once\n");
return 1;
#else
printf("pragma-once-sample included once\n");
return 0;
#endif
}