s502 assembler
A very simple assembler for the 6502 line of processors written in C
loadfile.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <stdlib.h>
5 
6 #include "loadfile.h"
7 #include "token_t.h"
8 #include "tokenFunc.h"
9 #include "logging.h"
10 
33 int read_token(FILE* f, Token* t) {
34  t->binSize = 0;
35 
36  int seen_whitespace = 1, eol = 0;
37  int ptr, c;
38 
39  // -1 for trailing nullbyte
40  for (ptr = 0; ptr < TOKEN_BUFFER_SIZE - 1;) {
41  // read char
42  c = fgetc(f);
43 
44  // stop condition
45  if (c == EOF || c == '\n') {
46  break;
47  }
48 
49  if (c == '\r') continue; // damn line endings!
50 
51  // don't write if already reached a comment
52  if (eol)
53  continue;
54 
55  // whitespace handling
56  if (c == '\t' || c == ' ') {
57  if (!seen_whitespace) {
58  c = ' ';
59  seen_whitespace = 1;
60  } else {
61  continue;
62  }
63  } else { // all othet chars
64  seen_whitespace = 0;
65 
66  // mark comment
67  if (c == ';') {
68  eol = 1;
69  continue;
70  }
71  }
72 
73  // tha actual write
74  // continues skipt this
75  t->stripped[ptr++] = c;
76  }
77 
78  // too long line
79  if (ptr == TOKEN_BUFFER_SIZE - 1) {
80  t->len = ptr;
81  return -1;
82  }
83 
84  // kill trailing whitespace
85  if (t->stripped[ptr - 1] == ' ')
86  ptr--;
87 
88  // zero-terminate
89  t->stripped[ptr] = 0;
90  // len
91  t->len = ptr;
92  t->instr.number = 0;
93 
94  // log
95  if (ptr > 0) {
96  LOG(5, "READ TOKEN:\n");
97  LOGDO(5, token_print(t));
98  }
99 
100  // EOF return
101  if (c == EOF)
102  return 0;
103 
104  return 1;
105 }
106 
119 TokensList* read_file(char* name) {
120 
121  // basic file open
122  FILE* f = fopen(name, "r");
123  if (f == NULL) {
124  ERROR("An error occured opening the file %s!\n", name);
125  ERROR("Error opening file: %s\n", strerror(errno));
126  return NULL;
127  }
128 
129  TokensList* tokenslist = tokenslist_new();
130  if (tokenslist == NULL) goto ERR_MEM;
131  Token tok;
132  int lineno = 1;
133  int res;
134 
135  // reading tokens while possible
136  do {
137  res = read_token(f, &tok);
138  if (tok.len > 0) {
139  strncpy(tok.source.fname, name, TOKEN_SOURCE_FILE_SIZE - 1);
140  tok.source.fname[TOKEN_SOURCE_FILE_SIZE - 1] = 0;
141  tok.source.lineno = lineno;
142  if (tokenslist_add(tokenslist, tok) < 0) goto ERR_MEM;
143  }
144  lineno++;
145  } while (res > 0);
146 
147  fclose(f);
148 
149  // return error if stopped due to reading error
150  if (res < 0) {
151  ERROR("line is too long!\n");
152  token_print(&tok);
153  tokenslist_free(tokenslist);
154  return NULL;
155  }
156  return tokenslist;
157 ERR_MEM:
158 
159  FAIL("read_file() failed!\n");
160  fclose(f);
161  tokenslist_free(tokenslist);
162  return NULL;
163 }
164 
165 // documented in header
166 TokensList* load_file(char* name) {
167  LOG(3, "Reading file...\n");
168 
169  TokensList* list = read_file(name);
170  if (list == NULL)
171  goto ERROR;
172 
173  LOG(3, "Running first analysis...\n");
174  if (tokenslist_recognize(list) < 0)
175  goto ERROR;
176 
177  return list;
178 
179 ERROR:
180  FAIL("Failed to load file contents: '%s'\n", name);
181  tokenslist_free(list);
182  return NULL;
183 }
TokensList::tokenslist_free
void tokenslist_free(TokensList *list)
free ALL memory associated with the TokensList object
Definition: tokenslist.c:78
read_file
TokensList * read_file(char *name)
read all tokens from a file
Definition: loadfile.c:119
Token::instr
struct Token::@1 instr
instruction data. Not used if token type is not TT_INSTR
Token::stripped
char stripped[TOKEN_BUFFER_SIZE]
stripped text from source file
Definition: token_t.h:55
load_file
TokensList * load_file(char *name)
load and parse one file
Definition: loadfile.c:166
TokensList::tokenslist_add
int tokenslist_add(TokensList *list, Token t)
Append a token to the list.
Definition: tokenslist.c:31
TOKEN_SOURCE_FILE_SIZE
@ TOKEN_SOURCE_FILE_SIZE
source filename max length. Longer strings will get truncated.
Definition: token_t.h:15
loadfile.h
File reading step.
LOG
#define LOG(LVL,...)
logging macro - works like printf
Definition: logging.h:28
TOKEN_BUFFER_SIZE
@ TOKEN_BUFFER_SIZE
Token max length.
Definition: token_t.h:13
LOGDO
#define LOGDO(LVL, x)
Conditional macro. Wraps contents into a conditional based on log level.
Definition: logging.h:35
Token
Token type to store token information.
Definition: token_t.h:37
Token::binSize
int binSize
number of bytes this token will generate
Definition: token_t.h:39
token_t.h
token type struct
TokensList::tokenslist_recognize
int tokenslist_recognize(TokensList *t)
Do token recognition on all tokens in a list.
Definition: tokenslist.c:117
tokenFunc.h
Token type member methods.
TokensList
A doubly-linked list for storing Tokens.
Definition: tokenslist.h:29
Token::token_print
void token_print(Token *token)
Pretty-print one token, with its source and length.
Definition: tokenFunc.c:20
logging.h
logging and fancy-printing
Token::source
struct Token::@2 source
source of this token
Token::len
int len
length of stripped text
Definition: token_t.h:57
read_token
int read_token(FILE *f, Token *t)
magic token reader function
Definition: loadfile.c:33
TokensList::tokenslist_new
TokensList * tokenslist_new()
Create a new (empty) TokensList object.
Definition: tokenslist.c:17
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