@@ -91,6 +91,7 @@ typedef enum Mode
9191typedef struct SemanticState
9292{
9393 cc_bool success ;
94+ const TextInput * input_callbacks ;
9495 const BinaryOutput * output_callbacks ;
9596 const TextOutput * listing_callbacks ;
9697 const TextOutput * error_callbacks ;
@@ -155,7 +156,7 @@ typedef struct Macro
155156} Macro ;
156157
157158/* Some forward declarations that are needed because some functions recurse into each other. */
158- static void AssembleFile (SemanticState * state , const TextInput * input_callbacks );
159+ static void AssembleFile (SemanticState * state );
159160static void AssembleLine (SemanticState * state , const char * source_line );
160161
161162/* Prevent errors when '__attribute__((format(printf, X, X)))' is not supported. */
@@ -1020,35 +1021,8 @@ static cc_bool ResolveExpression(SemanticState *state, Expression *expression, u
10201021
10211022static void TerminateRept (SemanticState * state )
10221023{
1023- unsigned long countdown ;
1024-
1025- /* Back-up some state into local variables, in case a nested REPT statement clobbers it. */
1026- unsigned long starting_line_number = state -> shared .rept .line_number ;
1027- SourceLineListNode * const source_line_list_head = state -> shared .rept .source_line_list .head ;
1028-
1029- /* Exit REPT mode before we recurse into the REPT's nested statements. */
1024+ /* Exit REPT mode. */
10301025 state -> mode = MODE_NORMAL ;
1031-
1032- /* Repeat the statements as many times as requested. */
1033- countdown = state -> shared .rept .repetitions ;
1034- /* TODO - Nested REPTs! Put the 'state->shared.rept' stuff in local variables! */
1035-
1036- while (countdown -- != 0 )
1037- {
1038- SourceLineListNode * source_line_list_node ;
1039-
1040- /* Rewind back to the line number of the start of the REPT. */
1041- state -> location -> line_number = starting_line_number ;
1042-
1043- /* Process the REPT's nested statements. */
1044- for (source_line_list_node = source_line_list_head ; source_line_list_node != NULL ; source_line_list_node = source_line_list_node -> next )
1045- AssembleLine (state , source_line_list_node -> source_line );
1046- }
1047-
1048- /* Increment past the ENDR line number. */
1049- ++ state -> location -> line_number ;
1050-
1051- FreeSourceLineList (source_line_list_head );
10521026}
10531027
10541028static void TerminateMacro (SemanticState * state )
@@ -4168,7 +4142,9 @@ static void ProcessInclude(SemanticState *state, const StatementInclude *include
41684142 }
41694143 else
41704144 {
4171- ClownAssembler_TextInput input_callbacks = {
4145+ const TextInput * const previous_input_callbacks = state -> input_callbacks ;
4146+
4147+ TextInput input_callbacks = {
41724148 input_file ,
41734149 ReadCharacter ,
41744150 ReadLine
@@ -4183,7 +4159,11 @@ static void ProcessInclude(SemanticState *state, const StatementInclude *include
41834159 location .previous = state -> location ;
41844160 state -> location = & location ;
41854161
4186- AssembleFile (state , & input_callbacks );
4162+ state -> input_callbacks = & input_callbacks ;
4163+
4164+ AssembleFile (state );
4165+
4166+ state -> input_callbacks = previous_input_callbacks ;
41874167
41884168 state -> location = state -> location -> previous ;
41894169
@@ -4253,8 +4233,114 @@ static void ProcessIncbin(SemanticState *state, StatementIncbin *incbin)
42534233 }
42544234}
42554235
4236+ static cc_bool ReadSourceLine (SemanticState * state )
4237+ {
4238+ char * line_buffer_write_pointer ;
4239+
4240+ line_buffer_write_pointer = state -> line_buffer ;
4241+
4242+ /* Read lines one at a time, feeding them to the 'AssembleLine' function. */
4243+ while (TextInput_fgets (line_buffer_write_pointer , & state -> line_buffer [sizeof (state -> line_buffer )] - line_buffer_write_pointer , state -> input_callbacks ) != NULL )
4244+ {
4245+ size_t newline_index ;
4246+ char newline_character ;
4247+
4248+ /* Find the end of the line. We terminate on '\0', '\r', '\n', and ';'.
4249+ Note that terminating at ';' prevents a trailing '&' from being recognised
4250+ and causing a line to be continued on the next line.
4251+ This is needed for compatibility with S.N. 68k (asm68k). */
4252+ {
4253+ char quote_character = '\0' ;
4254+ for (newline_index = 0 ; ; ++ newline_index )
4255+ {
4256+ const char character = state -> line_buffer [newline_index ];
4257+
4258+ if (character == '\0' || character == '\r' || character == '\n' )
4259+ break ;
4260+
4261+ if (quote_character == '\0' )
4262+ {
4263+ if (character == '"' || character == '\'' )
4264+ quote_character = character ;
4265+ else if (character == ';' )
4266+ break ;
4267+ }
4268+ else if (character == quote_character )
4269+ {
4270+ quote_character = '\0' ;
4271+ }
4272+ }
4273+ }
4274+
4275+ newline_character = state -> line_buffer [newline_index ];
4276+
4277+ line_buffer_write_pointer = state -> line_buffer ;
4278+
4279+ /* If there is no newline, then we've either reached the end of the file,
4280+ or the source line was too long to fit in the buffer. */
4281+ /* TODO: Is there no way to remove this limit? */
4282+ if (newline_character == '\0' )
4283+ {
4284+ int character = TextInput_fgetc (state -> input_callbacks );
4285+
4286+ if (character != -1 )
4287+ {
4288+ InternalError (state , "The source line was too long to fit in the internal buffer." );
4289+
4290+ /* Fast-forward through until the end of the line. */
4291+ while (character != '\r' && character != '\n' && character != -1 )
4292+ character = TextInput_fgetc (state -> input_callbacks );
4293+ }
4294+ }
4295+ else if (newline_index != 0 && state -> line_buffer [newline_index - 1 ] == '&' )
4296+ {
4297+ /* An '&' at the end of a line is like a '\' at the end of a line in C:
4298+ it signals that the current line is continued on the next line. */
4299+
4300+ /* Go back and get another line. */
4301+ line_buffer_write_pointer = & state -> line_buffer [newline_index - 1 ];
4302+ continue ;
4303+ }
4304+
4305+ /* Remove newlines from the string, so that they don't appear in the error message. */
4306+ state -> line_buffer [newline_index ] = '\0' ;
4307+
4308+ return cc_true ;
4309+ }
4310+
4311+ return cc_false ;
4312+ }
4313+
4314+ static void AssembleAndListLine (SemanticState * state )
4315+ {
4316+ /* Output program counter to listing file. */
4317+ if (TextOutput_exists (state -> listing_callbacks ))
4318+ {
4319+ state -> listing_counter = 0 ;
4320+ TextOutput_fprintf (state -> listing_callbacks , "%08lX" , state -> program_counter );
4321+ }
4322+
4323+ AssembleLine (state , state -> line_buffer );
4324+
4325+ /* Output line to listing file. */
4326+ if (TextOutput_exists (state -> listing_callbacks ))
4327+ {
4328+ unsigned int i ;
4329+
4330+ for (i = state -> listing_counter * 2 + state -> listing_counter / 2 ; i < 28 ; ++ i )
4331+ TextOutput_fputc (' ' , state -> listing_callbacks );
4332+
4333+ TextOutput_fprintf (state -> listing_callbacks , "%s\n" , state -> line_buffer );
4334+ }
4335+ }
4336+
42564337static void ProcessRept (SemanticState * state , StatementRept * rept )
42574338{
4339+ const Mode previous_mode = state -> mode ;
4340+ const unsigned long previous_repetitions = state -> shared .rept .repetitions ;
4341+ const unsigned long previous_line_number = state -> location -> line_number ;
4342+ const SourceLineList previous_source_line_list = state -> shared .rept .source_line_list ;
4343+
42584344 /* Enter REPT mode. */
42594345 state -> mode = MODE_REPT ;
42604346
@@ -4268,6 +4354,57 @@ static void ProcessRept(SemanticState *state, StatementRept *rept)
42684354
42694355 state -> shared .rept .source_line_list .head = NULL ;
42704356 state -> shared .rept .source_line_list .tail = NULL ;
4357+
4358+ for (;;)
4359+ {
4360+ if (!ReadSourceLine (state ))
4361+ {
4362+ /* The file ended before an 'ENDR' could be found! */
4363+
4364+ /* Terminate the REPT to hopefully avoid future complications. */
4365+ TerminateRept (state );
4366+
4367+ SemanticError (state , "REPT statement beginning at line %lu is missing its ENDR." , state -> shared .rept .line_number );
4368+ }
4369+ else
4370+ {
4371+ AssembleLine (state , state -> line_buffer );
4372+ }
4373+
4374+ if (state -> mode != MODE_REPT )
4375+ {
4376+ /* An 'ENDR' must have been encountered. */
4377+
4378+ /* Revert back to the previous state. */
4379+ unsigned long repetitions = state -> shared .rept .repetitions ;
4380+ const unsigned long line_number = state -> location -> line_number ;
4381+ const SourceLineList source_line_list = state -> shared .rept .source_line_list ;
4382+
4383+ state -> mode = previous_mode ;
4384+ state -> shared .rept .repetitions = previous_repetitions ;
4385+ state -> location -> line_number = previous_line_number ;
4386+ state -> shared .rept .source_line_list = previous_source_line_list ;
4387+
4388+ while (repetitions -- != 0 )
4389+ {
4390+ SourceLineListNode * source_line_list_node ;
4391+
4392+ /* Rewind back to the line number of the start of the REPT. */
4393+ state -> location -> line_number = line_number ;
4394+
4395+ /* Process the REPT's nested statements. */
4396+ for (source_line_list_node = source_line_list .head ; source_line_list_node != NULL ; source_line_list_node = source_line_list_node -> next )
4397+ AssembleLine (state , source_line_list_node -> source_line );
4398+ }
4399+
4400+ /* Increment past the ENDR line number. */
4401+ ++ state -> location -> line_number ;
4402+
4403+ FreeSourceLineList (source_line_list .head );
4404+
4405+ break ;
4406+ }
4407+ }
42714408}
42724409
42734410static void ProcessMacro (SemanticState * state , StatementMacro * macro , const char * label , cc_bool is_short )
@@ -5323,7 +5460,7 @@ static void AssembleLine(SemanticState *state, const char *source_line)
53235460
53245461 case MODE_REPT :
53255462 /* If this line is an 'ENDR' directive, then exit REPT mode. Otherwise, add the line to the REPT. */
5326- if (directive_length != 0 && strncmpci (source_line_pointer , "endr" , directive_length ) == 0 )
5463+ if (directive_length != 0 && ( strncmpci (source_line_pointer , "rept" , directive_length ) == 0 || strncmpci ( source_line_pointer , " endr" , directive_length ) == 0 ) )
53275464 {
53285465 /* TODO - Detect code after the keyword and error if any is found. */
53295466 ParseLine (state , source_line , label , source_line_pointer );
@@ -5387,98 +5524,10 @@ static void AssembleLine(SemanticState *state, const char *source_line)
53875524 free (label );
53885525}
53895526
5390- static void AssembleFile (SemanticState * state , const TextInput * const input_callbacks )
5527+ static void AssembleFile (SemanticState * state )
53915528{
5392- char * line_buffer_write_pointer ;
5393-
5394- line_buffer_write_pointer = state -> line_buffer ;
5395-
5396- /* Read lines one at a time, feeding them to the 'AssembleLine' function. */
5397- while (!state -> end && TextInput_fgets (line_buffer_write_pointer , & state -> line_buffer [sizeof (state -> line_buffer )] - line_buffer_write_pointer , input_callbacks ) != NULL )
5398- {
5399- size_t newline_index ;
5400- char newline_character ;
5401-
5402- /* Find the end of the line. We terminate on '\0', '\r', '\n', and ';'.
5403- Note that terminating at ';' prevents a trailing '&' from being recognised
5404- and causing a line to be continued on the next line.
5405- This is needed for compatibility with S.N. 68k (asm68k). */
5406- {
5407- char quote_character = '\0' ;
5408- for (newline_index = 0 ; ; ++ newline_index )
5409- {
5410- const char character = state -> line_buffer [newline_index ];
5411-
5412- if (character == '\0' || character == '\r' || character == '\n' )
5413- break ;
5414-
5415- if (quote_character == '\0' )
5416- {
5417- if (character == '"' || character == '\'' )
5418- quote_character = character ;
5419- else if (character == ';' )
5420- break ;
5421- }
5422- else if (character == quote_character )
5423- {
5424- quote_character = '\0' ;
5425- }
5426- }
5427- }
5428-
5429- newline_character = state -> line_buffer [newline_index ];
5430-
5431- line_buffer_write_pointer = state -> line_buffer ;
5432-
5433- /* If there is no newline, then we've either reached the end of the file,
5434- or the source line was too long to fit in the buffer. */
5435- /* TODO: Is there no way to remove this limit? */
5436- if (newline_character == '\0' )
5437- {
5438- int character = TextInput_fgetc (input_callbacks );
5439-
5440- if (character != -1 )
5441- {
5442- InternalError (state , "The source line was too long to fit in the internal buffer." );
5443-
5444- /* Fast-forward through until the end of the line. */
5445- while (character != '\r' && character != '\n' && character != -1 )
5446- character = TextInput_fgetc (input_callbacks );
5447- }
5448- }
5449- else if (newline_index != 0 && state -> line_buffer [newline_index - 1 ] == '&' )
5450- {
5451- /* An '&' at the end of a line is like a '\' at the end of a line in C:
5452- it signals that the current line is continued on the next line. */
5453-
5454- /* Go back and get another line. */
5455- line_buffer_write_pointer = & state -> line_buffer [newline_index - 1 ];
5456- continue ;
5457- }
5458-
5459- /* Remove newlines from the string, so that they don't appear in the error message. */
5460- state -> line_buffer [newline_index ] = '\0' ;
5461-
5462- /* Output program counter to listing file. */
5463- if (TextOutput_exists (state -> listing_callbacks ))
5464- {
5465- state -> listing_counter = 0 ;
5466- TextOutput_fprintf (state -> listing_callbacks , "%08lX" , state -> program_counter );
5467- }
5468-
5469- AssembleLine (state , state -> line_buffer );
5470-
5471- /* Output line to listing file. */
5472- if (TextOutput_exists (state -> listing_callbacks ))
5473- {
5474- unsigned int i ;
5475-
5476- for (i = state -> listing_counter * 2 + state -> listing_counter / 2 ; i < 28 ; ++ i )
5477- TextOutput_fputc (' ' , state -> listing_callbacks );
5478-
5479- TextOutput_fprintf (state -> listing_callbacks , "%s\n" , state -> line_buffer );
5480- }
5481- }
5529+ while (!state -> end && ReadSourceLine (state ))
5530+ AssembleAndListLine (state );
54825531
54835532 /* If we're not in normal mode when a file ends, then something is wrong. */
54845533 switch (state -> mode )
@@ -5614,6 +5663,7 @@ cc_bool ClownAssembler_Assemble(
56145663
56155664 /* Initialise the state's non-default values. */
56165665 state .success = cc_true ;
5666+ state .input_callbacks = input_callbacks ;
56175667 state .output_callbacks = output_callbacks ;
56185668 state .error_callbacks = error_callbacks ;
56195669 state .listing_callbacks = listing_callbacks ;
@@ -5662,7 +5712,7 @@ cc_bool ClownAssembler_Assemble(
56625712 #endif
56635713
56645714 /* Perform first pass of assembly, creating a list of fix-ups. */
5665- AssembleFile (& state , input_callbacks );
5715+ AssembleFile (& state );
56665716
56675717 /* Destroy the lexer, as we no longer need it. */
56685718 if (m68kasm_lex_destroy (state .flex_state ) != 0 )
0 commit comments