s502 assembler
A very simple assembler for the 6502 line of processors written in C
Functions
pass_one.c File Reference

implement pass one More...

#include <stdlib.h>
#include <string.h>
#include "tokenslist.h"
#include "istack.h"
#include "state.h"
#include "pass_one.h"
#include "directive.h"
#include "logging.h"
#include "tokenFunc.h"
#include "addressmode.h"

Go to the source code of this file.

Functions

int pass_one (State *s)
 Compilation pass 1. More...
 

Detailed Description

implement pass one

See also
pass_one.h

Definition in file pass_one.c.

Function Documentation

◆ pass_one()

int pass_one ( State s)

Compilation pass 1.

Parameters
scompiler state
Returns
0 on success, -1 on error

First pass processing for directives, instructions and labels
See documentation on steps for further info!

Definition at line 19 of file pass_one.c.

19  {
20  TokensListElement* ptr = s->tokens->head;
21 
22  // stack to store state of conditionals
23  // top of stack is the current value
24  // 1 means we disabled compilation
25  // in that case we do not generate anything
26  // but still process conditional compilation directives
27  // so we can get the matching endif
28  istack_ptr ifstack = istack_new();
29 
30  if (!ifstack) {
31  FAIL("Pass 1 init failed!\n");
32  return -1;
33  }
34 
35  // return value from directive processing
36  enum DIRCommand p;
37 
38  // on all tokens
39  while (ptr != NULL) {
40  LOG(4, "Processing token:\n");
41  LOGDO(4, token_print(ptr->token));
42 
44  // DIRECTIVE //
46  if (ptr->token->type == TT_DIRECTIVE) {
47  // call processor
48  p = do_directive_token(s, ptr, istack_top(ifstack, 0));
49 
50  // do returned command
51  if (p == DIR_IF_TRUE)
52  // AND the condition, so a true inside a false is false
53  if (istack_push(ifstack, istack_top(ifstack, 0)) < 0) goto ERR_FREE;
54  if (p == DIR_IF_FALSE)
55  // a false is always false
56  if (istack_push(ifstack, 1) < 0) goto ERR_FREE;
57 
58  // pop stack
59  if (p == DIR_ENDIF)
60  if (istack_pop(ifstack) < 0) {
61  ERROR("More endif's than if's!\n");
62  token_print(ptr->token);
63  goto ERR_FREE;
64  }
65 
66  // stop on error
67  if (p == DIR_STOP) goto ERR_FREE;
68  }
69 
71  // INSTRUCTION //
73  if (ptr->token->type == TT_INSTR) {
74  // analyze
75 
76  ptr->token->instr.address = s->PC;
77 
78  if (token_analyze_instruction(s, ptr->token) < 0) goto ERR_FREE;
79  if (token_get_operand(s, ptr->token) < 0) goto ERR_FREE;
80 
81  LOGDO(3, token_print(ptr->token));
82  LOG(3, "Instruction: \n");
83  LOGDO(3, instruction_print(ptr->token->instr.inst));
84  LOG(3, "A-mode: %s\n", ADRM_NAMES[ptr->token->instr.addressmode]);
85  }
86 
88  // LABEL //
90  if (ptr->token->type == TT_LABEL) {
91  // set address
92 
93  if (ptr->token->len >= MAP_MAX_KEY_LEN) {
94  ERROR("Label is too long!");
95  token_print(ptr->token);
96  goto ERR_FREE;
97  }
98 
99  char labelname[MAP_MAX_KEY_LEN];
100  // pragmas are here because GCC would generate a warning
101  // (thus an error)
102  // that I truncate the string
103  // it's right of course, but also that's my intetntion
104 #pragma GCC diagnostic push
105 #pragma GCC diagnostic ignored "-Wstringop-truncation"
106  strncpy(labelname, ptr->token->stripped, MAP_MAX_KEY_LEN - 1);
107  labelname[ptr->token->len - 1] = 0;
108 #pragma GCC diagnostic pop
109  LOG(5, "Label: %s\n", labelname);
110 
111  if (map_get(s->labels, labelname) >= 0) {
112  ERROR("Can not re-define label '%s'\n", labelname);
113  ERROR("(prev. value: $%x = %d)\n", map_get(s->labels, labelname), map_get(s->labels, labelname));
114  token_print(ptr->token);
115  goto ERR_FREE;
116  }
117 
118  map_set(s->labels, labelname, s->PC);
119  LOG(3, "Set label: '%s' to %d\n", labelname, s->PC);
120  }
121 
123  // COMMON //
125 
126  // drop if false conditional or 0>=binsize
127  if (istack_top(ifstack, 0) || ptr->token->binSize <= 0) {
128  ptr = tokenslist_remove(s->tokens, ptr);
129  } else {
130  // increment PC, get next token
131  s->PC += ptr->token->binSize;
132  ptr = ptr->next;
133  }
134  }
135  istack_free(ifstack);
136  return 0;
137 
138 
139 ERR_FREE:
140  FAIL("Pass 1 failed!\n");
141  istack_free(ifstack);
142  return -1;
143 }

References ADRM_NAMES, Token::binSize, DIR_ENDIF, DIR_IF_FALSE, DIR_IF_TRUE, DIR_STOP, do_directive_token(), ERROR, FAIL, TokensList::head, Token::instr, Instruction::instruction_print(), istack_el::istack_free(), istack_el::istack_new(), istack_el::istack_pop(), istack_el::istack_push(), istack_el::istack_top(), State::labels, Token::len, LOG, LOGDO, Map::map_get(), MAP_MAX_KEY_LEN, Map::map_set(), TokensListElement::next, State::PC, Token::stripped, TokensListElement::token, Token::token_analyze_instruction(), Token::token_get_operand(), Token::token_print(), State::tokens, TokensList::tokenslist_remove(), TT_DIRECTIVE, TT_INSTR, TT_LABEL, and Token::type.

Referenced by main().

State::labels
Map * labels
label locations
Definition: state.h:36
TT_INSTR
@ TT_INSTR
instruction token
Definition: token_t.h:26
Token::instr
struct Token::@1 instr
instruction data. Not used if token type is not TT_INSTR
ADRM_NAMES
const char * ADRM_NAMES[]
Human-readable names of address modes.
Definition: addressmode.c:16
Token::stripped
char stripped[TOKEN_BUFFER_SIZE]
stripped text from source file
Definition: token_t.h:55
DIR_STOP
@ DIR_STOP
An error occured, stop compilation.
Definition: directive.h:21
Map::map_set
int map_set(Map *map, char *name, int value)
Sets a key in the map.
Definition: map.c:43
TokensListElement::token
Token * token
Token value.
Definition: tokenslist.h:18
istack_el
very simple int stack
Definition: istack.h:16
LOG
#define LOG(LVL,...)
logging macro - works like printf
Definition: logging.h:28
istack_el::istack_push
int istack_push(istack_ptr istack, int val)
push one element to the istack
Definition: istack.c:31
State::tokens
TokensList * tokens
tokens
Definition: state.h:38
LOGDO
#define LOGDO(LVL, x)
Conditional macro. Wraps contents into a conditional based on log level.
Definition: logging.h:35
DIR_ENDIF
@ DIR_ENDIF
An endif was encountered, should pop from state stack.
Definition: directive.h:29
Token::token_analyze_instruction
int token_analyze_instruction(State *s, Token *t)
analyze instruction token (instruction, addressmode & operand)
Definition: tokenFunc.c:224
istack_el::istack_free
void istack_free(istack_ptr istack)
free all memory associated with a istack
Definition: istack.c:59
TokensListElement::next
struct TokensListElement * next
next element in list or NULL
Definition: tokenslist.h:20
Token::binSize
int binSize
number of bytes this token will generate
Definition: token_t.h:39
Instruction::instruction_print
void instruction_print(Instruction *instr)
fancy-print one instruction data
Definition: instructions.c:132
istack_el::istack_pop
int istack_pop(istack_ptr istack)
pop the top of the istack
Definition: istack.c:44
TokensList::head
TokensListElement * head
head (first element) of the list
Definition: tokenslist.h:31
TokensListElement
An element of a TokensList.
Definition: tokenslist.h:16
do_directive_token
enum DIRCommand do_directive_token(State *s, TokensListElement *ptr, int skip)
process a directive token
Definition: directive.c:362
DIRCommand
DIRCommand
Internal command type for directives.
Definition: directive.h:19
DIR_IF_FALSE
@ DIR_IF_FALSE
A conditional evaluated to false.
Definition: directive.h:27
TT_DIRECTIVE
@ TT_DIRECTIVE
directive token
Definition: token_t.h:28
Token::type
enum tokenType type
type of this token
Definition: token_t.h:41
Token::token_print
void token_print(Token *token)
Pretty-print one token, with its source and length.
Definition: tokenFunc.c:20
DIR_IF_TRUE
@ DIR_IF_TRUE
A conditional evaluated to true.
Definition: directive.h:25
TT_LABEL
@ TT_LABEL
label token
Definition: token_t.h:30
Map::map_get
int map_get(Map *map, char *name)
Get the value of a key.
Definition: map.c:75
Token::len
int len
length of stripped text
Definition: token_t.h:57
MAP_MAX_KEY_LEN
@ MAP_MAX_KEY_LEN
Key buffer size for Map.
Definition: map.h:14
Token::token_get_operand
int token_get_operand(State *s, Token *t)
parse the operand of the instruction as a number
Definition: tokenFunc.c:287
istack_el::istack_top
int istack_top(istack_ptr istack, int def)
get the top element of the istack
Definition: istack.c:53
istack_el::istack_new
istack_ptr istack_new()
create an empty istack
Definition: istack.c:15
State::PC
int PC
PC (starts at 0)
Definition: state.h:42
TokensList::tokenslist_remove
TokensListElement * tokenslist_remove(TokensList *list, TokensListElement *el)
remove a token from the list
Definition: tokenslist.c:60
FAIL
#define FAIL(...)
Fancy-print a fail (failed step). Works like printf.
Definition: logging.h:45
ERROR
#define ERROR(...)
Fancy-print an error (cause of faliure). Works like printf.
Definition: logging.h:40