forked from KolibriOS/kolibrios
574 lines
14 KiB
C
574 lines
14 KiB
C
/***********************************************************************
|
||
*
|
||
* avra - Assembler for the Atmel AVR microcontroller series
|
||
*
|
||
* Copyright (C) 1998-2004 Jon Anders Haugum, Tobias Weber
|
||
*
|
||
* This program is free software; you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation; either version 2 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* This program is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with this program; see the file COPYING. If not, write to
|
||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||
* Boston, MA 02111-1307, USA.
|
||
*
|
||
*
|
||
* Authors of avra can be reached at:
|
||
* email: jonah@omegav.ntnu.no, tobiw@suprafluid.com
|
||
* www: http://sourceforge.net/projects/avra
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
|
||
#include "misc.h"
|
||
#include "avra.h"
|
||
#include "device.h"
|
||
|
||
#define IS_UNARY(x) ((x == '!') || (x == '-') || (x == '~'))
|
||
#define IS_OPERATOR(x) ((x == '+') || (x == '-') || (x == '*') || (x == '/') || (x == '%') || (x == '<') || (x == '>') || (x == '=') || (x == '!') || (x == '&') || (x == '^') || (x == '|'))
|
||
#define IS_2ND_OPERATOR(x) ((x == '<') || (x == '>') || (x == '=') || (x == '&') || (x == '|'))
|
||
|
||
enum {
|
||
OPERATOR_ERROR = 0,
|
||
OPERATOR_MUL,
|
||
OPERATOR_DIV,
|
||
OPERATOR_MOD,
|
||
OPERATOR_ADD,
|
||
OPERATOR_SUB,
|
||
OPERATOR_SHIFT_LEFT,
|
||
OPERATOR_SHIFT_RIGHT,
|
||
OPERATOR_LESS_THAN,
|
||
OPERATOR_LESS_OR_EQUAL,
|
||
OPERATOR_GREATER_THAN,
|
||
OPERATOR_GREATER_OR_EQUAL,
|
||
OPERATOR_EQUAL,
|
||
OPERATOR_NOT_EQUAL,
|
||
OPERATOR_BITWISE_AND,
|
||
OPERATOR_BITWISE_XOR,
|
||
OPERATOR_BITWISE_OR,
|
||
OPERATOR_LOGICAL_AND,
|
||
OPERATOR_LOGICAL_OR
|
||
};
|
||
|
||
enum {
|
||
FUNCTION_LOW = 0,
|
||
FUNCTION_BYTE1,
|
||
FUNCTION_HIGH,
|
||
FUNCTION_BYTE2,
|
||
FUNCTION_BYTE3,
|
||
FUNCTION_BYTE4,
|
||
FUNCTION_LWRD,
|
||
FUNCTION_HWRD,
|
||
FUNCTION_PAGE,
|
||
FUNCTION_EXP2,
|
||
FUNCTION_LOG2,
|
||
FUNCTION_COUNT
|
||
};
|
||
|
||
struct element
|
||
{
|
||
struct element *next;
|
||
int data;
|
||
};
|
||
|
||
char *function_list[] = {
|
||
/*
|
||
** allow whitespace between function name
|
||
** and opening brace...
|
||
*/
|
||
"low",
|
||
"byte1",
|
||
"high",
|
||
"byte2",
|
||
"byte3",
|
||
"byte4",
|
||
"lwrd",
|
||
"hwrd",
|
||
"page",
|
||
"exp2",
|
||
"log2"
|
||
};
|
||
|
||
int log_2(int value)
|
||
{
|
||
int i = 0;
|
||
while(value >>= 1)
|
||
i++;
|
||
return(i);
|
||
}
|
||
|
||
int get_operator(char *op)
|
||
{
|
||
switch(op[0]) {
|
||
case '*':
|
||
return(OPERATOR_MUL);
|
||
case '/':
|
||
return(OPERATOR_DIV);
|
||
case '%':
|
||
return(OPERATOR_MOD);
|
||
case '+':
|
||
return(OPERATOR_ADD);
|
||
case '-':
|
||
return(OPERATOR_SUB);
|
||
case '<':
|
||
switch(op[1]) {
|
||
case '<':
|
||
return(OPERATOR_SHIFT_LEFT);
|
||
case '=':
|
||
return(OPERATOR_LESS_OR_EQUAL);
|
||
default:
|
||
return(OPERATOR_LESS_THAN);
|
||
}
|
||
case '>':
|
||
switch(op[1]) {
|
||
case '>':
|
||
return(OPERATOR_SHIFT_RIGHT);
|
||
case '=':
|
||
return(OPERATOR_GREATER_OR_EQUAL);
|
||
default:
|
||
return(OPERATOR_GREATER_THAN);
|
||
}
|
||
case '=':
|
||
if(op[1] == '=')
|
||
return(OPERATOR_EQUAL);
|
||
case '!':
|
||
if(op[1] == '=')
|
||
return(OPERATOR_NOT_EQUAL);
|
||
case '&':
|
||
if(op[1] == '&')
|
||
return(OPERATOR_LOGICAL_AND);
|
||
else
|
||
return(OPERATOR_BITWISE_AND);
|
||
case '^':
|
||
return(OPERATOR_BITWISE_XOR);
|
||
case '|':
|
||
if(op[1] == '|')
|
||
return(OPERATOR_LOGICAL_OR);
|
||
else
|
||
return(OPERATOR_BITWISE_OR);
|
||
}
|
||
return(OPERATOR_ERROR);
|
||
}
|
||
|
||
|
||
|
||
|
||
int test_operator_at_precedence(int operator, int precedence)
|
||
{
|
||
switch(precedence) {
|
||
case 13:
|
||
return((operator == OPERATOR_MUL) || (operator == OPERATOR_DIV)
|
||
|| (operator == OPERATOR_MOD));
|
||
case 12:
|
||
return((operator == OPERATOR_ADD) || (operator == OPERATOR_SUB));
|
||
case 11:
|
||
return((operator == OPERATOR_SHIFT_LEFT) || (operator == OPERATOR_SHIFT_RIGHT));
|
||
case 10:
|
||
return((operator == OPERATOR_LESS_THAN) || (operator == OPERATOR_LESS_OR_EQUAL)
|
||
|| (operator == OPERATOR_GREATER_THAN) || (operator == OPERATOR_GREATER_OR_EQUAL));
|
||
case 9:
|
||
return((operator == OPERATOR_EQUAL) || (operator == OPERATOR_NOT_EQUAL));
|
||
case 8:
|
||
return(operator == OPERATOR_BITWISE_AND);
|
||
case 7:
|
||
return(operator == OPERATOR_BITWISE_XOR);
|
||
case 6:
|
||
return(operator == OPERATOR_BITWISE_OR);
|
||
case 5:
|
||
return(operator == OPERATOR_LOGICAL_AND);
|
||
default: /* Makes the compiler shut up */
|
||
case 4:
|
||
return(operator == OPERATOR_LOGICAL_OR);
|
||
}
|
||
}
|
||
|
||
|
||
int calc(struct prog_info *pi, int left, int operator, int right) // TODO: Sjekk litt resultater
|
||
{
|
||
switch(operator) {
|
||
case OPERATOR_MUL:
|
||
return(left * right);
|
||
case OPERATOR_DIV:
|
||
if(right == 0) {
|
||
print_msg(pi, MSGTYPE_ERROR, "Division by zero");
|
||
return(0);
|
||
}
|
||
return(left / right);
|
||
case OPERATOR_MOD:
|
||
if(right == 0) {
|
||
print_msg(pi, MSGTYPE_ERROR, "Division by zero (modulus operator)");
|
||
return(0);
|
||
}
|
||
return(left % right);
|
||
case OPERATOR_ADD:
|
||
return(left + right);
|
||
case OPERATOR_SUB:
|
||
return(left - right);
|
||
case OPERATOR_SHIFT_LEFT:
|
||
return(left << right);
|
||
case OPERATOR_SHIFT_RIGHT:
|
||
return((unsigned)left >> right);
|
||
case OPERATOR_LESS_THAN:
|
||
return(left < right);
|
||
case OPERATOR_LESS_OR_EQUAL:
|
||
return(left <= right);
|
||
case OPERATOR_GREATER_THAN:
|
||
return(left > right);
|
||
case OPERATOR_GREATER_OR_EQUAL:
|
||
return(left >= right);
|
||
case OPERATOR_EQUAL:
|
||
return(left == right);
|
||
case OPERATOR_NOT_EQUAL:
|
||
return(left != right);
|
||
case OPERATOR_BITWISE_AND:
|
||
return(left & right);
|
||
case OPERATOR_BITWISE_XOR:
|
||
return(left ^ right);
|
||
case OPERATOR_BITWISE_OR:
|
||
return(left | right);
|
||
case OPERATOR_LOGICAL_AND:
|
||
return(left && right);
|
||
default: /* Make the compiler shut up */
|
||
case OPERATOR_LOGICAL_OR:
|
||
return(left || right);
|
||
}
|
||
}
|
||
|
||
/* If found, return the ID of the internal function */
|
||
int get_function(char *function)
|
||
{
|
||
int i;
|
||
|
||
for(i = 0; i < FUNCTION_COUNT; i++) {
|
||
if(!nocase_strncmp(function, function_list[i], strlen(function_list[i])))
|
||
{
|
||
/*
|
||
** some more checks to allow whitespace between function name
|
||
** and opening brace...
|
||
*/
|
||
char *tmp = function + strlen(function_list[i]);
|
||
while (*tmp <= ' ')
|
||
tmp++;
|
||
if (*tmp != '(')
|
||
continue;
|
||
|
||
return(i);
|
||
}
|
||
}
|
||
return(-1);
|
||
}
|
||
|
||
unsigned int do_function(int function, int value)
|
||
{
|
||
switch(function) {
|
||
case FUNCTION_LOW:
|
||
case FUNCTION_BYTE1:
|
||
return(value & 0xFF);
|
||
case FUNCTION_HIGH:
|
||
case FUNCTION_BYTE2:
|
||
return((value >> 8) & 0xff);
|
||
case FUNCTION_BYTE3:
|
||
return((value >> 16) & 0xff);
|
||
case FUNCTION_BYTE4:
|
||
return((value >> 24) & 0xff);
|
||
case FUNCTION_LWRD:
|
||
return(value & 0xffff);
|
||
case FUNCTION_HWRD:
|
||
return((value >> 16) & 0xffff);
|
||
case FUNCTION_PAGE:
|
||
return((value >> 16) & 0xff);
|
||
case FUNCTION_EXP2:
|
||
return(1 << value);
|
||
case FUNCTION_LOG2:
|
||
return(log_2(value));
|
||
default:
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
|
||
int get_symbol(struct prog_info *pi, char *label_name, int *data)
|
||
{
|
||
struct label *label;
|
||
struct macro_call *macro_call;
|
||
|
||
if(get_constant(pi,label_name,data)) return(True);
|
||
if(get_variable(pi,label_name,data)) return(True);
|
||
|
||
for(macro_call = pi->macro_call; macro_call; macro_call = macro_call->prev_on_stack) {
|
||
for(label = pi->macro_call->first_label; label; label = label->next)
|
||
if(!nocase_strcmp(label->name, label_name)) {
|
||
if(data)
|
||
*data = label->value;
|
||
return(True);
|
||
}
|
||
}
|
||
|
||
if(get_label(pi,label_name,data)) return(True);
|
||
return(False);
|
||
}
|
||
|
||
|
||
int par_length(char *data)
|
||
{
|
||
int i = 0, b_count = 1;
|
||
|
||
for(;;) {
|
||
if(data[i] == ')') {
|
||
b_count--;
|
||
if(!b_count)
|
||
return(i);
|
||
}
|
||
else if(data[i] == '(')
|
||
b_count++;
|
||
else if(data[i] == '\0')
|
||
return(-1);
|
||
i++;
|
||
}
|
||
}
|
||
|
||
int get_expr(struct prog_info *pi, char *data, int *value) {
|
||
/* Definition */
|
||
int ok, end, i, count, first_flag, length, function;
|
||
char unary, *label;
|
||
struct element *element, *first_element = NULL, *temp_element;
|
||
struct element **last_element = &first_element;
|
||
|
||
/* Initialisation */
|
||
first_flag = True;
|
||
ok = True;
|
||
end = False;
|
||
count = 0;
|
||
unary = 0;
|
||
/* the expression parser loop */
|
||
for(i = 0; ; i++) {
|
||
/* horizontal space is just skipped */
|
||
if(IS_HOR_SPACE(data[i]));
|
||
/* test for clean or premature end */
|
||
else if(IS_END_OR_COMMENT(data[i])) {
|
||
if((count % 2) != 1)
|
||
print_msg(pi, MSGTYPE_ERROR, "Missing value in expression");
|
||
else
|
||
end = True;
|
||
break;
|
||
}
|
||
else if(first_flag && IS_UNARY(data[i])) {
|
||
unary = data[i];
|
||
first_flag = False;
|
||
}
|
||
else if((count % 2) == 1) {
|
||
if(!IS_OPERATOR(data[i])) {
|
||
print_msg(pi, MSGTYPE_ERROR, "Illegal operator '%c'", data[i]);
|
||
break;
|
||
}
|
||
element = malloc(sizeof(struct element));
|
||
if(!element) {
|
||
print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
|
||
ok = False;
|
||
break;
|
||
}
|
||
element->next = NULL;
|
||
element->data = get_operator(&data[i]);
|
||
if(element->data == OPERATOR_ERROR) {
|
||
if(IS_2ND_OPERATOR(data[i + 1]))
|
||
print_msg(pi, MSGTYPE_ERROR, "Unknown operator %c%c", data[i], data[i + 1]);
|
||
else
|
||
print_msg(pi, MSGTYPE_ERROR, "Unknown operator %c", data[i]);
|
||
break;
|
||
}
|
||
*last_element = element;
|
||
last_element = &element->next;
|
||
if(IS_2ND_OPERATOR(data[i + 1]))
|
||
i++;
|
||
count++;
|
||
first_flag = True;
|
||
unary = 0;
|
||
}
|
||
else {
|
||
element = malloc(sizeof(struct element));
|
||
if(!element) {
|
||
print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
|
||
ok = False;
|
||
break;
|
||
}
|
||
element->next = NULL;
|
||
length = 0;
|
||
if(isdigit(data[i])) {
|
||
if(tolower(data[i + 1]) == 'x') {
|
||
i += 2;
|
||
while(isxdigit(data[i + length])) length++; // TODO: Sjekk overflow
|
||
element->data = atox_n(&data[i], length);
|
||
}
|
||
else if(tolower(data[i + 1]) == 'b') {
|
||
i += 2;
|
||
element->data = 0;
|
||
while((data[i + length] == '1') || (data[i + length] == '0')) {
|
||
element->data <<= 1;
|
||
element->data |= data[i + length++] - '0'; // TODO: Sjekk overflow
|
||
}
|
||
}
|
||
else {
|
||
while(isdigit(data[i + length])) length++;
|
||
element->data = atoi_n(&data[i], length); // TODO: Sjekk overflow
|
||
}
|
||
}
|
||
else if(data[i] == '$') {
|
||
i++;
|
||
while(isxdigit(data[i + length])) length++;
|
||
element->data = atox_n(&data[i], length); // TODO: Sjekk overflow
|
||
}
|
||
else if(data[i] == '\'') {
|
||
i++;
|
||
if(data[i+1] != '\'') {
|
||
print_msg(pi, MSGTYPE_ERROR, "Not a correct character ! Use 'A' !");
|
||
break;
|
||
}
|
||
element->data = data[i];
|
||
length = 2;
|
||
}
|
||
else if(data[i] == '(') {
|
||
i++;
|
||
length = par_length(&data[i]);
|
||
if(length == -1) {
|
||
print_msg(pi, MSGTYPE_ERROR, "Missing ')'");
|
||
break;
|
||
}
|
||
data[i + length++] = '\0';
|
||
ok = get_expr(pi, &data[i], &element->data);
|
||
if(!ok)
|
||
break;
|
||
}
|
||
/* test for internal function */
|
||
else if((function = get_function(&data[i])) != -1) {
|
||
while(data[i] != '(')
|
||
i++;
|
||
i++;
|
||
length = par_length(&data[i]);
|
||
if(length == -1) {
|
||
print_msg(pi, MSGTYPE_ERROR, "Missing ')'");
|
||
break;
|
||
}
|
||
data[i + length++] = '\0';
|
||
ok = get_expr(pi, &data[i], &element->data);
|
||
if(!ok)
|
||
break;
|
||
element->data = do_function(function, element->data);
|
||
}
|
||
else if(!nocase_strncmp(&data[i], "defined(", 8)) {
|
||
i += 8;
|
||
length = par_length(&data[i]);
|
||
if(length == -1) {
|
||
print_msg(pi, MSGTYPE_ERROR, "Missing ')'");
|
||
break;
|
||
}
|
||
data[i + length++] = '\0';
|
||
if(get_symbol(pi, &data[i], NULL))
|
||
element->data = 1;
|
||
else
|
||
element->data = 0;
|
||
}
|
||
else if(!nocase_strncmp(&data[i], "supported(", 10)) {
|
||
i += 10;
|
||
length = par_length(&data[i]);
|
||
if(length == -1) {
|
||
print_msg(pi, MSGTYPE_ERROR, "Missing ')'");
|
||
break;
|
||
}
|
||
data[i + length++] = '\0';
|
||
element->data=is_supported(pi, &data[i]);
|
||
if (element->data<0) {
|
||
if (toupper(data[i])=='X') {
|
||
if (pi->device->flag&DF_NO_XREG) element->data = 0;
|
||
else element->data = 1;
|
||
}
|
||
else if (toupper(data[i])=='Y') {
|
||
if (pi->device->flag&DF_NO_YREG) element->data = 0;
|
||
else element->data = 1;
|
||
}
|
||
else if (toupper(data[i])=='Z')
|
||
element->data = 1;
|
||
else {
|
||
print_msg(pi, MSGTYPE_ERROR, "Unknown mnemonic: %s",&data[i]);
|
||
element->data = 0;
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
while(IS_LABEL(data[i + length])) length++;
|
||
if((length == 2) && !nocase_strncmp(&data[i], "PC", 2))
|
||
element->data = pi->cseg_addr;
|
||
else {
|
||
label = malloc(length + 1);
|
||
if(!label) {
|
||
print_msg(pi, MSGTYPE_OUT_OF_MEM, NULL);
|
||
ok = False;
|
||
break;
|
||
}
|
||
strncpy(label, &data[i], length);
|
||
label[length] = '\0';
|
||
if(get_symbol(pi, label, &element->data))
|
||
free(label);
|
||
else {
|
||
print_msg(pi, MSGTYPE_ERROR, "Found no label/variable/constant named %s", label);
|
||
free(label);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
/* now the expression has been evaluated */
|
||
i += length - 1;
|
||
switch(unary) { // TODO: F<> den til <20> takle flere unary p<> rad.
|
||
case '-':
|
||
element->data = -element->data;
|
||
break;
|
||
case '!':
|
||
element->data = !element->data;
|
||
break;
|
||
case '~':
|
||
element->data = ~element->data;
|
||
}
|
||
*last_element = element;
|
||
last_element = &element->next;
|
||
count++;
|
||
first_flag = False;
|
||
}
|
||
}
|
||
if(end) {
|
||
for(i = 13; (i >= 4) && (count != 1); i--) {
|
||
for(element = first_element; element->next;) {
|
||
if(test_operator_at_precedence(element->next->data, i)) { // TODO: Vurder en hi_i for kjapphet
|
||
element->data = calc(pi, element->data, element->next->data, element->next->next->data);
|
||
temp_element = element->next->next->next;
|
||
free(element->next->next);
|
||
free(element->next);
|
||
count -= 2;
|
||
element->next = temp_element;
|
||
}
|
||
else
|
||
element = element->next->next;
|
||
}
|
||
}
|
||
*value = first_element->data;
|
||
}
|
||
for(element = first_element; element;) {
|
||
temp_element = element;
|
||
element = element->next;
|
||
free(temp_element);
|
||
}
|
||
return(ok);
|
||
}
|
||
|
||
|
||
/* end of expr.c */
|
||
|