Skip to content

Update to Merlin32 1.2 - #6

Open
artlogic wants to merge 1 commit into
digarok:mainfrom
artlogic:update-merlin-source
Open

Update to Merlin32 1.2#6
artlogic wants to merge 1 commit into
digarok:mainfrom
artlogic:update-merlin-source

Conversation

@artlogic

@artlogic artlogic commented Apr 1, 2026

Copy link
Copy Markdown

No description provided.

Copilot AI review requested due to automatic review settings April 1, 2026 21:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Merlin32 assembler to the 1.2 codebase, including API reshaping and internal refactors across parsing, macro/LUP handling, file/OMF project modeling, and output generation.

Changes:

  • Simplifies CLI handling in Main.c and updates the assembly/link entrypoint signature.
  • Refactors source/macro loading and output generation (text output + new symbols export).
  • Restructures OMF project representation (project → files → segments) and updates related headers.

Reviewed changes

Copilot reviewed 19 out of 21 changed files in this pull request and generated 13 comments.

Show a summary per file
File Description
Source/Main.c Updates CLI parsing, init/teardown, and calls into the new AssembleLink65c816() signature.
Source/Dc_Library.h Updates constants, parameter structure, and declares new path helper APIs.
Source/a65816_OMF.h Introduces new OMF project/file structures and updates OMF builder API signatures.
Source/a65816_Macro.h Updates macro APIs (notably LoadSourceMacroFile and IsMacroFile signatures).
Source/a65816_Macro.c Refactors macro loading and substitution flow; switches path building to project helpers.
Source/a65816_Lup.h Header comment updates only.
Source/a65816_Lup.c Refactors includes and adapts to updated memory/file APIs.
Source/a65816_Link.h Updates AssembleLink65c816() signature.
Source/a65816_Line.h Updates structures/field names and comments for the line model.
Source/a65816_File.h Updates file/output APIs (text output, symbol export, fixed-address output).
Source/a65816_File.c Refactors source loading and rewrites output generation (text output + symbols + fixed-address binary output).
Source/a65816_Data.h Header comment updates only.
Source/a65816_Data.c Refactors includes and adapts to updated memory/file APIs; some comment modernization.
Source/a65816_Cond.h Header comment updates only.
Source/a65816_Cond.c Refactors includes and adapts to updated memory/file APIs.
Source/a65816_Code.h Header comment updates only.
Comments suppressed due to low confidence (1)

Source/Dc_Library.h:16

  • Dc_Library.h relies on types like uint32_t, int64_t, and size_t but does not include the standard headers that define them. This makes the header non-self-contained and can cause compilation failures depending on include order. Add the appropriate standard includes (e.g., <stdint.h> and <stddef.h>).
#if defined(WIN32)
typedef unsigned long       DWORD;    /* Unsigned 32 bit */
#else
typedef uint32_t            DWORD;    /* Unsigned 32 bit */
#endif
typedef unsigned short      WORD;     /* Unsigned 16 bit */
typedef unsigned char       BYTE;     /* Unsigned 8 bit */


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread Source/Main.c
Comment on lines +144 to +145
/* OK */
return(0);

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

error from AssembleLink65c816() is computed but ignored; main always returns 0. This prevents CI/scripts from detecting assembly/link failures. Propagate the error code (e.g., return non-zero when error != 0).

Suggested change
/* OK */
return(0);
/* Retourne le code d'erreur de l'assemblage / linkage (0 si succès) */
return(error);

Copilot uses AI. Check for mistakes.
Comment thread Source/Main.c
Comment on lines +112 to +113
/* Lib�ration des ressources */
my_Memory(MEMORY_FREE,NULL,NULL,NULL);

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the setjmp error path, only my_Memory(MEMORY_FREE, ...) is called before returning. Resources initialized earlier (e.g., my_File(FILE_INIT_DIRECTORY, ...) and the error system) are not closed/ended, which can leak handles/state across runs. Ensure the same teardown (my_File(FILE_CLOSE_DIRECTORY, ...) and my_RaiseError(ERROR_END, ...)) happens in the error path before returning.

Suggested change
/* Lib�ration des ressources */
my_Memory(MEMORY_FREE,NULL,NULL,NULL);
/* Libération des ressources */
my_File(FILE_CLOSE_DIRECTORY,NULL);
my_Memory(MEMORY_FREE,NULL,NULL,NULL);
my_RaiseError(ERROR_END,NULL);

Copilot uses AI. Check for mistakes.
Comment thread Source/Main.c
Comment on lines +62 to +123
/* D�codage des param�tres */
if(argc == 3)
{
verbose_mode = 0;
strcpy(macro_folder_path,argv[1]);
strcpy(source_file_path,argv[2]);
}
else
{
verbose_mode = 1;
strcpy(macro_folder_path,argv[2]);
strcpy(source_file_path,argv[3]);
}

*verbose = -1;
*symbols = 0;
ClearString(macro_dir);
ClearString(source_file);
/* Initialisation */
my_Memory(MEMORY_INIT,NULL,NULL,NULL);
my_File(FILE_INIT_DIRECTORY,NULL);

for(int i = 1; i < argc; i++)
/* Initialisation du m�canisme de gestion d'erreurs */
my_RaiseError(ERROR_INIT,NULL);
context_value = setjmp(context);
if(context_value)
{
char* curArg = argv[i];
/* R�cup�ration de la chaine contenant le message d'erreur */
my_RaiseError(ERROR_GET_STRING,&error_string);

if(my_strnicmp(curArg,"-v",2)==0)
{
if( strlen(curArg) > 2 )
{
columns = atoi(&curArg[2]);
if( !columns )
columns = SYMBOL_COLUMNS;
*verbose = columns;
}
else
*verbose = 0;
}
else if(my_strnicmp(curArg,"--verbose",8)==0)
{
if( strlen(curArg) > 8 )
{
columns = atoi(&curArg[8]);
if( !columns )
columns = SYMBOL_COLUMNS;
*verbose = columns;
}
else
*verbose = 0;
}
else if(my_strnicmp(curArg,"-s",2)==0)
{
if( strlen(curArg) > 2 )
columns = atoi(&curArg[2]);
*symbols = columns ? columns : SYMBOL_COLUMNS;
}
else if(my_stricmp(curArg,"-h")==0 || my_stricmp(curArg,"--help")==0)
/* Message d'erreur et fin */
if(error_string)
{
Usage();
exit(EXIT_SUCCESS);
printf(" => [Error] %s.\n",error_string);
free(error_string);
}
else if(IsDirectory(curArg)) /* Dir arg is macro lib */
{
if(IsEmpty(macro_dir) && IsEmpty(source_file))
CopyString(macro_dir,curArg,STR_SIZE);
else
FailWithUsage(curArg,"Too many macro directories");
}
else /* Non-dir arg is source file */

/* On r�cup�re le OMF Segment courant (s'il existe) */
my_Memory(MEMORY_GET_CURR_ERROR_SEGMENT,&current_omfsegment,NULL,NULL);

/** On essaye de Dumper qqchose dans le fichier <ProjectFolderPath>Error_Output.txt **/
if(current_omfsegment != NULL)
{
if(IsEmpty(source_file)) /* Accept only if not yet provided */
CopyString(source_file,curArg,STR_SIZE);
else
FailWithUsage(curArg,"Too many source files");
/* Chemin du fichier Error */
strcpy(file_error_path,"error_output.txt");
my_Memory(MEMORY_GET_PARAM,&param,NULL,NULL);
if(param != NULL)
if(strlen(param->project_folder_path) > 0)
sprintf(file_error_path,"%serror_output.txt",param->project_folder_path);

/* Cr�ation du fichier Output Error */
CreateTextOutputFile(file_error_path,current_omfsegment,NULL);
}

/* Lib�ration des ressources */
my_Memory(MEMORY_FREE,NULL,NULL,NULL);

/* Error */
return(1);
}
my_RaiseError(ERROR_INIT,&context);

if(IsEmpty(macro_dir))
CopyString(macro_dir,MACRO_DIR,STR_SIZE);
/** Pr�paration du dossier Macro **/
if(strlen(macro_folder_path) > 0)
if(macro_folder_path[strlen(macro_folder_path)-1] != '\\' && macro_folder_path[strlen(macro_folder_path)-1] != '/')
strcat(macro_folder_path,FOLDER_SEPARATOR);

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Command-line arguments are copied/concatenated with strcpy/strcat into fixed-size buffers (macro_folder_path, source_file_path) without length checks. A long argv value can overflow these buffers. Use bounded copies/concats (e.g., snprintf/strlcpy where available) and validate lengths before appending the folder separator.

Copilot uses AI. Check for mistakes.
Comment thread Source/a65816_File.c
/* Fin de ligne */
end_line = strchr(begin_line,'\n');
if(end_line != NULL)
*end_line = '\0';

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When splitting lines, only \n is replaced with \0; Windows CRLF files will leave a trailing \r at end-of-line, which can break opcode/operand parsing and string comparisons. Strip an optional \r before terminating the line.

Suggested change
*end_line = '\0';
{
/* Handle optional '\r' before '\n' (CRLF) */
if(end_line > begin_line && *(end_line - 1) == '\r')
*(end_line - 1) = '\0';
*end_line = '\0';
}

Copilot uses AI. Check for mistakes.
Comment thread Source/a65816_Macro.c
/* Fin de la ligne */
end_line = strchr(begin_line,'\n');
if(end_line)
*end_line = '\0';

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Macro file line splitting only terminates on \n and does not remove a preceding \r. If macro files are CRLF, parsed tokens can include \r and fail opcode matching (e.g., "MAC\r"). Strip an optional \r before \0 termination.

Suggested change
*end_line = '\0';
{
*end_line = '\0';
/* Handle optional '\r' in CRLF line endings */
if(end_line > begin_line && *(end_line - 1) == '\r')
*(end_line - 1) = '\0';
}

Copilot uses AI. Check for mistakes.
Comment thread Source/a65816_File.c
Comment on lines +515 to +519
#if defined(WIN32) || defined(WIN64)
fd = fopen(file_path,"wb+");
#else
fd = fopen(file_path,"w+");
#endif

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuildFixedAddressBinaryOutputFile opens the output in text mode ("w+") on non-Windows builds. Since this function writes raw binary data, it should use binary mode ("wb+") consistently for correctness and portability.

Suggested change
#if defined(WIN32) || defined(WIN64)
fd = fopen(file_path,"wb+");
#else
fd = fopen(file_path,"w+");
#endif
fd = fopen(file_path,"wb+");

Copilot uses AI. Check for mistakes.
Comment thread Source/a65816_File.c
my_Memory(MEMORY_GET_PARAM,&param,NULL,NULL);

/* Chemin du fichier Symbols.txt */
sprintf(output_file_path,"%s%s_Symbols.txt",param->project_folder_path,file_name);

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sprintf(output_file_path, "%s%s_Symbols.txt", ...) can overflow output_file_path if project_folder_path and/or file_name are long. Use snprintf (and handle truncation) to avoid buffer overflow.

Suggested change
sprintf(output_file_path,"%s%s_Symbols.txt",param->project_folder_path,file_name);
{
int written = snprintf(output_file_path, sizeof(output_file_path),
"%s%s_Symbols.txt", param->project_folder_path, file_name);
if (written < 0 || written >= (int)sizeof(output_file_path))
{
fprintf(stderr, "Error: Symbol file path is too long.\n");
return(1);
}
}

Copilot uses AI. Check for mistakes.
Comment thread Source/a65816_Data.c
/***********************************************************************/
/* */
/* a65816_Code.c : Module for generation of Data. */
/* a65816_Data.c : Module pour la g�n�ration du code objet. */

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

File header comment says this module is for generating object code, but this is a65816_Data.c (data generation). This mismatch makes the file-level documentation misleading; update the header comment to reflect the module's purpose.

Suggested change
/* a65816_Data.c : Module pour la g�n�ration du code objet. */
/* a65816_Data.c : Module pour la génération des données (lignes DATA). */

Copilot uses AI. Check for mistakes.
Comment thread Source/a65816_Macro.c
Comment on lines +732 to +747
/* Construit le chemin du fichier Macro */
file_path = BuildProjectFilePath(file_name,"USE");
if(file_path != NULL)
{
/** We add a .S at the end **/
strcat(file_path,".s");
macro_file = LoadOneSourceFile(file_path,file_name,0);

/** We will clean the File name **/
if(macro_file == NULL)
{
/* We will extract the File name: 4 / Locator.Macs => Locator.Macs.s */
for(i=(int)strlen(file_name); i>=0; i--)
if(file_name[i] == '/' || file_name[i] == ':')
break;
strcpy(param->buffer_file_name,&file_name[i+1]);

/* Add the final .s */
if(my_stricmp(&param->buffer_file_name[strlen(param->buffer_file_name)-2],".s"))
strcat(param->buffer_file_name,".s");

/* We try to open the File with his name */
sprintf(file_path,"%s%s",macro_folder_path,param->buffer_file_name);
macro_file = LoadOneSourceFile(file_path,param->buffer_file_name,0);
}
strcpy(full_file_path,file_path);
free(file_path);
}
else
return(1); /* Impossible de construire le chemin du fichier */

/* On essaye d'ouvrir le fichier avec son nom */
macro_file = LoadOneSourceFile(full_file_path,file_name,0);

/* We have failed to open the File, we declare it as a File Macro and we leave the following code to declare it not available. */
if(macro_file == NULL)
return(1);
/* On a pas r�ussi � ouvrir le fichier, on le d�clare comme un fichier Macro et on laisse le code suivant le d�clarer non disponble */
if(macro_file == NULL)
return(1);

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IsMacroFile() returns 1 (treats as a macro file) when BuildProjectFilePath() fails or when the file cannot be opened. In LoadAllSourceFile(), a true result causes the USE include to be skipped entirely, which can silently hide missing/typoed includes. Consider returning 0 on path/open failures (so the normal include logic can raise an error), and only return 1 when the file is confirmed to contain a MAC definition (or matches the .Macs[.s] heuristic).

Copilot uses AI. Check for mistakes.
Comment thread Source/a65816_File.c
Comment on lines +64 to 71
if((!my_stricmp(current_line->opcode_txt,"PUT") || !my_stricmp(current_line->opcode_txt,"PUTBIN") || !my_stricmp(current_line->opcode_txt,"USE")) && strlen(current_line->operand_txt) > 0)
{
/* If the inclusion is done by a Use on check if we are dealing with a File of Macro */
if(!my_stricmp(current_line->opcode_txt,"USE") && IsMacroFile(current_line->operand_txt,param->source_folder_path,macro_folder_path))
/* Si l'inclusion se fait par un Use on v�rifie si on a affaire � un fichier de Macro */
if(!my_stricmp(current_line->opcode_txt,"USE") && IsMacroFile(current_line->operand_txt))
{
current_line = current_line->next;
continue;
current_line = current_line->next;
continue;
}

Copilot AI Apr 1, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoadAllSourceFile() skips USE directives when IsMacroFile() returns true. Since IsMacroFile() currently returns true on path/open failure, this can cause missing USE includes to be silently ignored. Ensure missing/invalid USE targets still produce an error (e.g., only skip when the macro file is successfully found and identified as a macro container).

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants