Hi,
I'm new to SDCC. I'm getting the following error when porting an app from GCC:
firstchess.c:499: error 25: Structure/Union expected left of '.->'
at least it happens 10 times.
I'm attaching the sources, so you can check them. Thanks!!
You did read the warnings, did you?
SDCC changed structures as function arguments into pointers to
structures, but did not adapt the references to them... Not too clever,
but it warned you...
I attached a compiling variant of your source to guide you:
* Do not pass structures around, only pointers to them
(SDCC limitation?)
* Do not assign structures to one another, use memcpy instead
(SDCC limitation?)
* Do not use scanf(), not in SDCC libraries, or write one of your own.
Good luck,
Raphael
PS: Are you sure you want to play chess on a small/embedded device with
probably tight memory constraints (HIST hist[6000]; int piece[64]; int
color[64]; char s[256]; MOVE movebuf[200];)?!?
/*
FirstChess - Freeware, by Pham Hong Nguyen
Version: beta
*/
/*
* BASIC PARTS: *
* Some definitions *
* Board representation and main varians *
* Move generator *
* Evaluation for current position *
* Make and Take back a move, IsInCheck *
* Search function - a typical alphabeta *
* Utility *
* Main program *
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
/*
****************************************************************************
* Some definitions *
****************************************************************************
*/
#define PAWN 0
#define KNIGHT 1
#define BISHOP 2
#define ROOK 3
#define QUEEN 4
#define KING 5
#define EMPTY 6
#define WHITE 0
#define BLACK 1
#define VALUE_PAWN 100
#define VALUE_KNIGHT 300
#define VALUE_BISHOP 300
#define VALUE_ROOK 500
#define VALUE_QUEEN 900
#define VALUE_KING 10000
#define MATE 10000 /* equal value of King, losing King==mate */
#define COL(pos) ((pos)&7)
#define ROW(pos) (((unsigned)pos)>>3)
#define FALSE 0
#define TRUE 1
/*
****************************************************************************
* Board representation and main varians *
****************************************************************************
*/
/* Board representation */
int piece[64] = {
ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK,
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN, PAWN,
ROOK, KNIGHT, BISHOP, QUEEN, KING, BISHOP, KNIGHT, ROOK
};
int color[64] = {
BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK, BLACK,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY,
WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE,
WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE, WHITE
};
int side; /* side to move, value = BLACK or WHITE */
/* For move generation */
#define MOVE_TYPE_NONE 0
#define MOVE_TYPE_NORMAL 1
#define MOVE_TYPE_CASTLE 2
#define MOVE_TYPE_ENPASANT 3
#define MOVE_TYPE_PROMOTION_TO_QUEEN 4
#define MOVE_TYPE_PROMOTION_TO_ROOK 5
#define MOVE_TYPE_PROMOTION_TO_BISHOP 6
#define MOVE_TYPE_PROMOTION_TO_KNIGHT 7
typedef struct tag_MOVE {
int from,
dest,
type;
} MOVE;
/* For storing all moves of game */
typedef struct tag_HIST {
MOVE m;
int cap;
} HIST;
HIST hist[6000]; /* Game length < 6000 */
int hdp; /* Current move order */
/* For searching */
int nodes; /* Count all visited nodes when searching */
int ply; /* ply of search */
/*
****************************************************************************
* Move generator *
* Lack: no enpassant, no castle *
****************************************************************************
*/
void Gen_Push(int from, int dest, int type, MOVE * pBuf, int *pMCount)
{
MOVE move;
move.from = from;
move.dest = dest;
move.type = type;
//pBuf[*pMCount] = move;
pBuf[*pMCount].from = move.from;
pBuf[*pMCount].dest = move.dest;
pBuf[*pMCount].type = move.type;
*pMCount = *pMCount + 1;
}
void Gen_PushNormal(int from, int dest, MOVE * pBuf, int *pMCount)
{
Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
}
/* Pawn can promote */
void Gen_PushPawn(int from, int dest, MOVE * pBuf, int *pMCount)
{
if (dest > 7 && dest < 56)
Gen_Push(from, dest, MOVE_TYPE_NORMAL, pBuf, pMCount);
else {
Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_QUEEN, pBuf, pMCount);
Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_ROOK, pBuf, pMCount);
Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_BISHOP, pBuf, pMCount);
Gen_Push(from, dest, MOVE_TYPE_PROMOTION_TO_KNIGHT, pBuf, pMCount);
}
}
/* Gen all moves of current_side to move and push them to pBuf, return number of moves */
int Gen(int current_side, MOVE * pBuf)
{
int i,
k,
y,
row,
col,
movecount;
movecount = 0;
for (i = 0; i < 64; i++) /* Scan all board */
if (color[i] == current_side) {
switch (piece[i]) {
case PAWN:
col = COL(i);
row = ROW(i);
if (current_side == BLACK) {
if (color[i + 8] == EMPTY)
Gen_PushPawn(i, i + 8, pBuf, &movecount);
if (row == 1 && color[i + 8] == EMPTY && color[i + 16] == EMPTY)
Gen_PushNormal(i, i + 16, pBuf, &movecount);
if (col && color[i + 7] == WHITE)
Gen_PushNormal(i, i + 7, pBuf, &movecount);
if (col < 7 && color[i + 9] == WHITE)
Gen_PushNormal(i, i + 9, pBuf, &movecount);
} else {
if (color[i - 8] == EMPTY)
Gen_PushPawn(i, i - 8, pBuf, &movecount);
if (row == 6 && color[i - 8] == EMPTY && color[i - 16] == EMPTY)
Gen_PushNormal(i, i - 16, pBuf, &movecount);
if (col && color[i - 9] == BLACK)
Gen_PushNormal(i, i - 9, pBuf, &movecount);
if (col < 7 && color[i - 7] == BLACK)
Gen_PushNormal(i, i - 7, pBuf, &movecount);
}
break;
case QUEEN: /* == BISHOP+ROOK */
case BISHOP:
for (y = i - 9; y >= 0 && COL(y) != 7; y -= 9) { /* go left up */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
for (y = i - 7; y >= 0 && COL(y) != 0; y -= 7) { /* go right up */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
for (y = i + 9; y < 64 && COL(y) != 0; y += 9) { /* go right down */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
for (y = i + 7; y < 64 && COL(y) != 7; y += 7) { /* go right down */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
if (piece[i] == BISHOP)
break;
/* FALL THROUGH FOR QUEEN {I meant to do that!} ;-) */
case ROOK:
col = COL(i);
for (k = i - col, y = i - 1; y >= k; y--) { /* go left */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
for (k = i - col + 7, y = i + 1; y <= k; y++) { /* go right */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
for (y = i - 8; y >= 0; y -= 8) { /* go up */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
for (y = i + 8; y < 64; y += 8) { /* go down */
if (color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
if (color[y] != EMPTY)
break;
}
break;
case KNIGHT:
col = COL(i);
y = i - 6;
if (y >= 0 && col < 6 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
y = i - 10;
if (y >= 0 && col > 1 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
y = i - 15;
if (y >= 0 && col < 7 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
y = i - 17;
if (y >= 0 && col > 0 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
y = i + 6;
if (y < 64 && col > 1 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
y = i + 10;
if (y < 64 && col < 6 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
y = i + 15;
if (y < 64 && col > 0 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
y = i + 17;
if (y < 64 && col < 7 && color[y] != current_side)
Gen_PushNormal(i, y, pBuf, &movecount);
break;
case KING:
col = COL(i);
if (col && color[i - 1] != current_side)
Gen_PushNormal(i, i - 1, pBuf, &movecount); /* left */
if (col < 7 && color[i + 1] != current_side)
Gen_PushNormal(i, i + 1, pBuf, &movecount); /* right */
if (i > 7 && color[i - 8] != current_side)
Gen_PushNormal(i, i - 8, pBuf, &movecount); /* up */
if (i < 56 && color[i + 8] != current_side)
Gen_PushNormal(i, i + 8, pBuf, &movecount); /* down */
if (col && i > 7 && color[i - 9] != current_side)
Gen_PushNormal(i, i - 9, pBuf, &movecount); /* left up */
if (col < 7 && i > 7 && color[i - 7] != current_side)
Gen_PushNormal(i, i - 7, pBuf, &movecount); /* right up */
if (col && i < 56 && color[i + 7] != current_side)
Gen_PushNormal(i, i + 7, pBuf, &movecount); /* left down */
if (col < 7 && i < 56 && color[i + 9] != current_side)
Gen_PushNormal(i, i + 9, pBuf, &movecount); /* right down */
break;
default:
puts("piece type unknown");
assert(FALSE);
}
}
return movecount;
}
/*
****************************************************************************
* Evaluation for current position - main "brain" function *
* Lack: almost no knowlegde *
****************************************************************************
*/
int Eval()
{
int value_piece[6] = {VALUE_PAWN, VALUE_KNIGHT, VALUE_BISHOP, VALUE_ROOK, VALUE_QUEEN, VALUE_KING};
int i,
score = 0;
for (i = 0; i < 64; i++) {
if (color[i] == WHITE)
score += value_piece[piece[i]];
else if (color[i] == BLACK)
score -= value_piece[piece[i]];
}
if (side == WHITE)
return score;
return -score;
}
/*
****************************************************************************
* Make and Take back a move, IsInCheck *
****************************************************************************
*/
/* Check and return 1 if side is in check */
int IsInCheck(int current_side)
{
int k,
h,
y,
row,
col,
xside;
xside = (WHITE + BLACK) - current_side; /* opposite current_side, who may be checking */
/* Find King */
for (k = 0; k < 64; k++)
if (piece[k] == KING && color[k] == current_side)
break;
row = ROW(k), col = COL(k);
/* Check attacking of Knight */
if (col > 0 && row > 1 && color[k - 17] == xside && piece[k - 17] == KNIGHT)
return 1;
if (col < 7 && row > 1 && color[k - 15] == xside && piece[k - 15] == KNIGHT)
return 1;
if (col > 1 && row > 0 && color[k - 10] == xside && piece[k - 10] == KNIGHT)
return 1;
if (col < 6 && row > 0 && color[k - 6] == xside && piece[k - 6] == KNIGHT)
return 1;
if (col > 1 && row < 7 && color[k + 6] == xside && piece[k + 6] == KNIGHT)
return 1;
if (col < 6 && row < 7 && color[k + 10] == xside && piece[k + 10] == KNIGHT)
return 1;
if (col > 0 && row < 6 && color[k + 15] == xside && piece[k + 15] == KNIGHT)
return 1;
if (col < 7 && row < 6 && color[k + 17] == xside && piece[k + 17] == KNIGHT)
return 1;
/* Check horizontal and vertical lines for attacking of Queen, Rook, King */
/* go down */
y = k + 8;
if (y < 64) {
if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] == EMPTY)
for (y += 8; y < 64; y += 8) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] != EMPTY)
break;
}
}
/* go left */
y = k - 1;
h = k - col;
if (y >= h) {
if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] == EMPTY)
for (y--; y >= h; y--) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] != EMPTY)
break;
}
}
/* go right */
y = k + 1;
h = k - col + 7;
if (y <= h) {
if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] == EMPTY)
for (y++; y <= h; y++) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] != EMPTY)
break;
}
}
/* go up */
y = k - 8;
if (y >= 0) {
if (color[y] == xside && (piece[y] == KING || piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] == EMPTY)
for (y -= 8; y >= 0; y -= 8) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == ROOK))
return 1;
if (piece[y] != EMPTY)
break;
}
}
/* Check diagonal lines for attacking of Queen, Bishop, King, Pawn */
/* go right down */
y = k + 9;
if (y < 64 && COL(y) != 0) {
if (color[y] == xside) {
if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
return 1;
if (current_side == BLACK && piece[y] == PAWN)
return 1;
}
if (piece[y] == EMPTY)
for (y += 9; y < 64 && COL(y) != 0; y += 9) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
return 1;
if (piece[y] != EMPTY)
break;
}
}
/* go left down */
y = k + 7;
if (y < 64 && COL(y) != 7) {
if (color[y] == xside) {
if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
return 1;
if (current_side == BLACK && piece[y] == PAWN)
return 1;
}
if (piece[y] == EMPTY)
for (y += 7; y < 64 && COL(y) != 7; y += 7) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
return 1;
if (piece[y] != EMPTY)
break;
}
}
/* go left up */
y = k - 9;
if (y >= 0 && COL(y) != 7) {
if (color[y] == xside) {
if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
return 1;
if (current_side == WHITE && piece[y] == PAWN)
return 1;
}
if (piece[y] == EMPTY)
for (y -= 9; y >= 0 && COL(y) != 7; y -= 9) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
return 1;
if (piece[y] != EMPTY)
break;
}
}
/* go right up */
y = k - 7;
if (y >= 0 && COL(y) != 0) {
if (color[y] == xside) {
if (piece[y] == KING || piece[y] == QUEEN || piece[y] == BISHOP)
return 1;
if (current_side == WHITE && piece[y] == PAWN)
return 1;
}
if (piece[y] == EMPTY)
for (y -= 7; y >= 0 && COL(y) != 0; y -= 7) {
if (color[y] == xside && (piece[y] == QUEEN || piece[y] == BISHOP))
return 1;
if (piece[y] != EMPTY)
break;
}
}
return 0;
}
int MakeMove(MOVE *m)
{
int r;
//hist[hdp].m = m;
hist[hdp].m.type = m->type;
hist[hdp].m.dest = m->dest;
hist[hdp].m.from = m->from;
hist[hdp].cap = piece[m->dest];
piece[m->dest] = piece[m->from];
piece[m->from] = EMPTY;
color[m->dest] = color[m->from];
color[m->from] = EMPTY;
if (m->type >= MOVE_TYPE_PROMOTION_TO_QUEEN) { /* Promotion */
switch (m->type) {
case MOVE_TYPE_PROMOTION_TO_QUEEN:
piece[m->dest] = QUEEN;
break;
case MOVE_TYPE_PROMOTION_TO_ROOK:
piece[m->dest] = ROOK;
break;
case MOVE_TYPE_PROMOTION_TO_BISHOP:
piece[m->dest] = BISHOP;
break;
case MOVE_TYPE_PROMOTION_TO_KNIGHT:
piece[m->dest] = KNIGHT;
break;
default:
puts("impossible to get here...");
assert(0);
}
}
ply++;
hdp++;
r = !IsInCheck(side);
side = (WHITE + BLACK) - side; /* After making move, give turn to
* opponent */
return r;
}
void TakeBack() /* undo what MakeMove did */
{
side = (WHITE + BLACK) - side;
hdp--;
ply--;
piece[hist[hdp].m.from] = piece[hist[hdp].m.dest];
piece[hist[hdp].m.dest] = hist[hdp].cap;
color[hist[hdp].m.from] = side;
if (hist[hdp].cap != EMPTY)
color[hist[hdp].m.dest] = (WHITE + BLACK) - side;
else
color[hist[hdp].m.dest] = EMPTY;
if (hist[hdp].m.type >= MOVE_TYPE_PROMOTION_TO_QUEEN) /* Promotion */
piece[hist[hdp].m.from] = PAWN;
}
/*
****************************************************************************
* Search function - a typical alphabeta, main search function *
* Lack: no any technique for move ordering *
****************************************************************************
*/
int Search(int alpha, int beta, int depth, MOVE * pBestMove)
{
int i,
value,
havemove,
movecnt;
MOVE moveBuf[200],
tmpMove;
nodes++; /* visiting a node, count it */
havemove = 0;
pBestMove->type = MOVE_TYPE_NONE;
movecnt = Gen(side, moveBuf); /* generate all moves for current position */
/* loop through the moves */
for (i = 0; i < movecnt; ++i) {
if (!MakeMove(&moveBuf[i])) {
TakeBack();
continue;
}
havemove = 1;
if (depth - 1 > 0) /* If depth is still, continue to search deeper */
value = -Search(-beta, -alpha, depth - 1, &tmpMove);
else /* If no depth left (leaf node), go to evalute that position */
value = Eval();
TakeBack();
if (value > alpha) {
/* This move is so good and caused a cutoff */
if (value >= beta)
return beta;
alpha = value;
/* so far, current move is the best reaction for current position */
memcpy (pBestMove, &moveBuf[i], sizeof(MOVE));
}
}
if (!havemove) { /* If no legal moves, that is checkmate or
* stalemate */
if (IsInCheck(side))
return -MATE + ply; /* add ply to find the longest path to lose or shortest path to win */
else
return 0;
}
return alpha;
}
MOVE *ComputerThink(int max_depth)
{
static MOVE m;
int score;
/* reset some values before searching */
ply = 0;
nodes = 0;
/* search now */
score = Search(-MATE, MATE, max_depth, &m);
/* after searching, print results */
printf("Search result: move = %c%d%c%d; nodes = %d, score = %d\n",
'a' + COL(m.from),
8 - ROW(m.from),
'a' + COL(m.dest),
8 - ROW(m.dest),
nodes,
score
);
return &m;
}
/*
****************************************************************************
* Utilities *
****************************************************************************
*/
void PrintBoard()
{
char pieceName[] = "PNBRQKpnbrqk";
int i;
for (i = 0; i < 64; i++) {
if ((i & 7) == 0) {
printf(" +---+---+---+---+---+---+---+---+\n");
if (i <= 56) {
printf(" %d |", 8 - (((unsigned)i) >> 3));
}
}
if (piece[i] == EMPTY)
printf(" |");
else {
printf(" %c |", pieceName[piece[i] + (color[i] == WHITE ? 0 : 6)]);
}
if ((i & 7) == 7)
printf("\n");
}
printf(" +---+---+---+---+---+---+---+---+\n a b c d e f g h\n");
}
/*
****************************************************************************
* Main program *
****************************************************************************
*/
void main()
{
char s[256];
int from,
dest,
i;
int computer_side;
int max_depth; /* max depth to search */
MOVE moveBuf[200];
int movecnt;
printf("First Chess, by Pham Hong Nguyen\n");
printf("Help\n d: display board\n MOVE: make a move (e.g. b1c3, a7a8q)\n quit: exit\n\n");
side = WHITE;
computer_side = BLACK; /* Human is white side */
max_depth = 5;
hdp = 0;
for (;;) {
if (side == computer_side) { /* computer's turn */
/* Find out the best move to react the current position */
MOVE *bestMove = ComputerThink(max_depth);
MakeMove(bestMove);
continue;
}
/* get user input */
printf("fc> ");
#if 0
if (scanf("%s", s) == EOF) /* close program */
return;
#endif
if (!strcmp(s, "d")) {
PrintBoard();
continue;
}
if (!strcmp(s, "quit")) {
printf("Good bye!\n");
return;
}
/* maybe the user entered a move? */
from = s[0] - 'a';
from += 8 * (8 - (s[1] - '0'));
dest = s[2] - 'a';
dest += 8 * (8 - (s[3] - '0'));
ply = 0;
movecnt = Gen(side, moveBuf);
/* loop through the moves to see if it's legal */
for (i = 0; i < movecnt; i++)
if (moveBuf[i].from == from && moveBuf[i].dest == dest) {
if (piece[from] == PAWN && (dest < 8 || dest > 55)) { /* Promotion move? */
switch (s[4]) {
case 'q':
moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
break;
case 'r':
moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_ROOK;
break;
case 'b':
moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_BISHOP;
break;
case 'n':
moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_KNIGHT;
break;
default:
puts("promoting to a McGuffin..., I'll give you a queen");
moveBuf[i].type = MOVE_TYPE_PROMOTION_TO_QUEEN;
}
}
if (!MakeMove(&moveBuf[i])) {
TakeBack();
printf("Illegal move.\n");
}
break;
}
}
}
-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/
_______________________________________________
Sdcc-user mailing list
Sdcc-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sdcc-user