Les membres ayant 30 points peuvent parler sur les canaux annonces, projets et hs du chat.
La shoutbox n'est pas chargée par défaut pour des raisons de performances. Cliquez pour charger.

Forum Casio - Projets de programmation


Index du Forum » Projets de programmation » B2C : Convertisseur Basic en C
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

B2C : Convertisseur Basic en C

Posté le 02/07/2016 11:24

Mon nouveau projet est donc de faire un convertisseur basic -> C

Ce serait possible parce que toutes les fonctions du basic sont transposables en C (même les gotos), par exemple Locate(x, y, str) est remplacé par locate(x,y);Print(str), F-line remplacé par ML_line(), etc.

Par contre là où ça diffère de AldeBasicLib c'est que ce sera un convertisseur total. Par exemple si le programme voit "Mat M" il génèrera une matrice M adéquate. Le but étant de lancer le programme, de sélectionner un .g1r, et d'avoir un fichier .c prêt à compiler.

Cela pourrait être utile pour les gros jeux qui prennent toutes la mémoire principale et qui seraient mieux en C (je pense à CloneLab, Arkenstone, peut être Calcraft...)

Utilisation
Nécessite : Java, le SDK casio (ou un truc permettant de compiler des addins)

Clonez le repo http://git.planet-casio.com/Zezombye/B2C/ et exécutez B2C.java en remplaçant les arguments si besoin.
À noter que B2C n'étant pas fini, il est très probable que le programme que vous essayez de convertir vous fasse plein d'erreurs, que ce soit de B2C ou du SDK.

Programmes basic déjà convertis
NOTE: Ces programmes sont compatibles SH3. Si vous voulez les tester, convertissez les en SH4 si besoin !
Je n'ai absolument rien changé dans ces programmes (à part l'icône et le nom) donc le code est celui qu'on obtient avec B2C.

Démineur de Cakeisalie5 : http://www.mediafire.com/file/z6t5jmfh72wfnag/DEMNR.G1A (original)
Puissance 4 de Zezombye : http://www.mediafire.com/file/i1ucweo66ibjy67/PUISS4.G1A (original)

Fonctions actuellement implémentées :

- Commentaires
- Gotos&Lbls (heureusement que ça marche exactement de la même façon en C qu'en basic)
- If, Then, Else, IfEnd, ⇒
- Do, LpWhile
- While, WhileEnd
- For, To, Step, Next
- Prog, Return, Break, Stop
- Locate
- GetKey
- -> (assignement de variable/matrice/liste/dim)
- Dim, Mat, List
- L'opérateur '~'
- Variables A-Z, r, theta, Ans
- Opérateurs de calcul : + (unaire et binaire), - (unaire et binaire), *, /, ^, sqrt, racine n-ième
- Multiplication implicite (normalement)
- Opérateurs de comparaison : <, >, ≤, ≥, =, ≠
- Opérateurs logiques : And, Not, Or, Xor
- Ran# (fonction de la libc), RanInt# (par l'interpréteur casio actuellement, à changer)
- Int
- Fill(), ClrMat, ClrText
- Str, StrCmp, StrInv, StrJoin, StrLeft, StrRight, StrLen, StrLwr, StrUpr, StrMid, StrRotate, StrSrc, StrShift

Fonctions à implémenter :
- Nombres complexes
- Fonctions graphiques
- Gestion des pictures et captures
- Sauvegarde des variables

Note : les 3 fonctions suivantes ne seront pas implémentées fidèlement, il n'y aura qu'une implémentation rudimentaire.
- Les strings sans assignement (écrire "TEST" puis une nouvelle ligne)
- La fonction disp (◢)
- L'opérateur ?-> pour l'input de l'utilisateur

Fonctions qui ne seront peut être pas implémentées :
- L'écriture d'un nombre via la console (par exemple écrire "2+3" comme seule instruction affiche "5" sur l'interpréteur basic, mais il est difficile de savoir s'il faut l'afficher ou seulement la mettre dans Ans)

Comment B2C optimise le programme (autre qu'en compilant au lieu d'interpréter) par rapport à Casio

- Les opérations sont implémentées (enfin pour l'instant il n'y a que l'addition et la soustraction pour les nombres non complexes) nativement au lieu de passer par l'interpréteur; ainsi, additionner 10000x des nombres prend 1.5s pour l'implémentation de l'addition, et 4.4s si on passe par l'interpréteur.

- Les listes de Casio séparent les parties imaginaires et réelles. Par exemple, pour la liste {3, 1+2i, -4i, 6}, Casio la stockera en {3, 1, 0, 6, ?, 2, -4, ?} avec '?' 12 octets de padding. B2C ne fait pas cette séparation et stocke la partie imaginaire à côté de la partie réelle, ce qui fait qu'une fonction peut appeler directement "list_1" au lieu de passer par une fonction intermédiaire qui recolle les 2 parties.
L'inconvénient est que les listes ne possédant pas de complexes sont 2 fois plus grandes. (en fait, si le programme possède des nombres complexes, la taille du BCDvar est de 24 octets, et sinon 12)

- Pour les matrices : même chose qu'avec les listes.

- Les strings de Casio implémentent des caractères, qui peuvent être sur 1 ou 2 octets. Cette différence fait qu'on ne peut pas avoir un accès en O(1) car on ne peut pas savoir directement la position du i-ème caractère du string en calculant. Si on veut accéder à str_1[255], l'interpréteur casio doit itérer sur tout le string.
B2C permet un accès beaucoup plus rapide en stockant chaque caractère, multi-byte ou non, sur 2 octets. Ainsi, les fonctions des strings qui travaillent sur les caractères casio (toutes sauf StrCmp) sont plus rapides. StrCmp est possiblement plus lent que si B2C implémentait les strings comme le fait casio, mais la différence est négligeable.

Pour résumer : B2C bouffe un peu plus de RAM, mais il est beaucoup plus rapide.



Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 07/07/2016 22:32 | #


Tout ligne de code est un calcul en fait... si tu es assez malin pour généraliser la notion.

Si tu veux faire plus simple, tout est un calcul, sauf les statements : If, For, Do, While et affiliés, et quelques cas particuliers comme les Goto. Certains de ces calculs ne renvoient rien, comme l'appel à la fonction sans argument ClrText ; d'autres renvoient des valeurs, que l'on peut placer dans une variable et à défaut dans Ans.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 07/07/2016 22:38 | #


Donc tu voudrais juste enlever la condition ? Hmm c'est ce que j'avais pensé à faire aussi, mais j'aimerais bien afficher une erreur lorsque le parseur rencontre une fonction inconnue (parce qu'il est censé avoir return lorsqu'il rencontre une fonction interprétée). Je vais faire ça du coup, et je me fierai aux logs
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 07/07/2016 22:45 | #


Ben c'est pas un problème. Si tu rencontres une fonction inconnue tu démarres une analyse de calcul et tôt un tard tu vas l'isoler pour la calculer. À ce moment-là, tu pourras émettre une erreur.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 08/07/2016 21:16 | #


Un dernier problème avant de finir l'alpha (cad : pouvoir parser mon puissance 4) est de pouvoir allouer les matrices et listes.

Pour les matrices : je n'ai aucune idée de comment faire l'initialisation (est ce que je fais double** mat_M = NULL ou double mat_M[][] = NULL ?), ni l'allocation de mémoire (je fais malloc(x*y*sizeof(double)), je l'assigne à &mat_M ?).

Pour les listes c'est pareil, j'avais pensé au début à faire un grand array List[][], le premier argument représentant le numéro de la liste (pour qu'on puisse faire List A+1 par exemple) mais ça se monte à 200 ko si on met le nombre maximal de variables par liste à 999. Donc je devrai faire List_1, List_2... et faire une fonction B2C_List() qui les met en rapport. Sauf que ça me pose un autre problème : les listes ne sont pas forcément initialisées (si on fait ClrList 1 puis A->List 1[0] ça fonctionne). Il faut donc gérer la taille de chaque liste qui va peut être grandir au cours du temps (et qui n'est pas forcément définie en "dur" dans une assignation à Dim comme les matrices). Là je suis bloqué :/

Dernier problème : comment parser les listes (délimitées par des accolades), par exemple {3,4}->Dim Mat M ? Mon parseur le traduit comme "Dim Mat M = {3,4}", je peux remplacer ça par "Dim_M = {3,4}", Dim_M étant une structure de type Dim (qui contient deux ints pour les dimensions), mais comment parser {3,4}? Que faire pour les listes qui ont un nombre illimité d'arguments (je peux pas faire List_1 = {3,4,5,6} ) ?
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 08/07/2016 22:27 | #


Faut que tu retravailles ton allocation dynamique. Pour les matrices, autant y aller à fond.
#include <stdlib.h>

struct Matrix
{
        int width, height;
        double *data;
};

struct Matrix *matrix_alloc(int width, int height)
{
        struct Matrix m = { width, height, NULL };
        m.data = calloc(width * height, sizeof(double));
        if(!m.data) raise_memory_error(); // par exemple
        return m;
}

// Pas necessaire d'utiliser une fonction... c'est pour illustrer
double matrix_get(struct Matrix m, int x, int y)
{
        if(!m.data) raise_memory_error(); // ne devrait pas se produire si tu codes bien
        if(x > m.width || y > m.height) raise_dimension_error();
        return m.data[y * m.width + x];
}

void matrix_free(struct Matrix m)
{
        if(m.data) free(m.data);
}

Pour les listes dynamiques faut allouer dynamiquement et libérer, réallouer et copier. Pense à utiliser realloc() mais attention au piège : si la réallocation échoue, les données d'origine ne sont pas libérées et realloc() renvoie NULL. Il ne faut donc jamais écrire « ptr = realloc(ptr, ...) » mais toujours utiliser un pointeur temporaire pour éviter de perdre l'adresse d'origine.

Pour ta syntaxe, il faut définir « { ... } » comme une expression de construction de liste, et la parser récursivement sur chacun de ses éléments pour les construire. Dans la structure d'arbre (tu devrais... -_- ), pense à indiquer le nombre d'éléments pour pouvoir allouer dynamiquement.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 09/07/2016 08:33 | #


Hmm, pour les listes je pensais faire des listes chaînées : https://openclassrooms.com/courses/apprenez-a-programmer-en-c/les-listes-chainees mais c'est vrai qu'un simple realloc est bien plus rapide o_o

Après je pense pas que ce soit utile de passer par un pointeur intermédiaire, parce que si le realloc ne marche pas j'affiche "Erreur mémoire" et j'arrête le programme, du coup je n'ai pas besoin de garder l'adresse d'origine.

Ptite question sur le code pour la matrice : le "if (m.data)" prend bien en condition l'adresse du pointeur ? Mais du coup ça retournerait pas false si le pointeur était à l'adresse 0, on devrait pas plutôt faire "if (m.data != NULL)" ?

Par contre pour les listes en dur (avec des accolades) même avec un arbre je sais pas trop comment les convertir :/ je pourrais faire une fonction B2C_addToList(List list, double d) mais comment ajouter une par une les variables (je fais un for, mais sur quoi)? Est ce que c'est propre de générer les addToList ("{1,2,3}->List 1" devient B2C_addToList(1, 1); B2C_addToList(1, 2); etc) ?

Alternativement, je pourrais mettre un nombre infini d'arguments, par exemple B2C_newList(1, 3,4,5,6...) qui retourne un objet de type List, et ça ce serait facile à faire, mais est ce que c'est possible ? Si non, ils font comment pour printf et ses dérivés ? Si c'était possible ce serait franchement le truc le plus propre pour gérer les listes (parce que je dois aussi gérer les listes qui ne sont pas forcément assignées à des listes, par exemple {3,4}->Dim Mat M mais aussi le Graph(X,Y), et peut être d'autres fonctions).

Sinon merci pour ton code sur les matrices
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 09/07/2016 08:56 | #


Tu vas perdre de la place si tu fais des listes chaînées. Je te rappelle que tu as moins de mémoire allouable que de mémoire principale. Les double ne font que 8 octets là où le type de variable du système en fait 12, donc tu peux t'en sortir, mais faut être économe. Les listes chaînées c'est bon pour l'insertion mais ça va te prendre trop de mémoire je pense.

Si, tu as besoin de garder l'adresse d'origine parce qu'il faut que tu libères les données si tu arrêtes le programme.

Alors en effet « if(m.data) » signifie « if(m.data != 0) » mais il faut savoir que NULL vaut 0. Par convention, déréférencer le pointeur nul est interdit. Il n'y a donc rien à l'adresse 0, la mémoire commence toujours à l'adresse 1. Mais sinon, c'est bien ce que tu dis.

Non, tu ne peux pas générer des append() pour chaque élément. Rappelle-toi qu'en C tu devras réallouer à chaque fois. Il faut que tu alloues directement les n éléments de ta liste et que tu remplisses directement après tes calculs : list[0] = val0, etc.

Oui, tu peux mettre un nombre « infini » d'arguments... à condition de savoir combien tu en a mis. Lis la documentation du module stdarg, tu trouveras tout ça facilement. C'est le fonctionnement de printf() en fait. Quand tu utilises printf(), le nombre d'arguments passés à la fonction après le format est indiqué par le nombre de "%" dans le texte. Ici, il faudra que tu utilises quelque chose comme :
#include <stdarg.h>

struct List
{
        int element_count;
        double *data;
};

struct List list_new(int element_count, ...)
{
        va_list args;
        // les arguments variables sont apres 'element_count'
        va_start(args, element_count);

        struct List list = { element_count, NULL };
        list.data = malloc(element_count * sizeof(double));
        if(!list.data) raise_memory_error();

        int i;
        for(i = 0; i < element_count; i++)
        {
                // recuperer un argument en tant que double
                double element = va_arg(args, double);
                list.data[i] = element;
        }

        va_end(args);
        return list;
}

Pour le coup des dimensions de matrice t'as définitivement envie de remplacer
{ W, H } → Dim Mat M

par
matrix_free(Mat_M); // toujours liberer
Mat_M = matrix_new(W, H);

C'est bien mieux. Et vérifie que W et H sont des entiers d'abord...
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 10/07/2016 23:48 | #


Je suis un peu confus concernant le formattage d'un .g1m, en particulier la délimitation de programmes.

J'ai testé avec mon puissance 4, qui contient 3 programmes. Le premier programme commence à 0x56, ce qui semble être constant (en tout cas avec les programmes que j'ai testés jusqu'à maintenant). La délimitation avec le second programme se fait avec 4 0x00 :



Mais la délimitation entre le second et le troisième programme se fait avec un set un peu différent d'octets, avec l'insertion d'un 0x10 (qui est le "data link escape", je sais absolument pas à quoi ça sert) :



Le fichier se termine ensuite par 4 0x00 que j'enlève à coups de regex.

Donc ma question est : pourquoi cette insertion de 0x10 ? Y a-t-il toujours 4 octets qui séparent les programmes ? Est ce qu'il y a une doc plus approfondie sur ça (celle de SimLo ne traite apparemment que du header) ?
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 11/07/2016 08:14 | #


D'après la doc, toujours, le programme commence bien à 0x56 ; pas de doute là-dessus.

Pour le 0x10, ça pourrait être un compteur indiquant la position de la ressource dans le fichier ?

Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 11/07/2016 11:53 | #


En fait il commence pas toujours à 0x56, en regardant Clonelab les captures et pictures commencent à 0x20 (et elles sont dans un format bizarre d'ailleurs, je m'attendais à y trouver seulement du 0x00 et 0xFF mais on y trouve entre les deux) donc je ne peux me fier pour délimiter les programmes qu'à un 0x00 qui n'est pas précédé d'un caractère multi-byte. D'ailleurs les octets varient entre 1 et 4.

En regardant clonelab je n'ai trouvé que des 0x00, mais sur un programme d'Ice Slider il y a 0x00, 2 0x49 (I) et après "PROGRAM". (d'ailleurs sur Ice Slider les pictures sont à la fin des programmes au lieu d'être au début), dans Eon the Dragon (un .g2m) il y a un 0x0D, bref ça semble ne pas suivre de logique. J'ai aussi trouvé la différence entre les g1m et g2m, c'est la présence de l'alpha mem et d'un truc "global setup" au début, donc le header est pas exactement le même (ça explique pourquoi l'émulateur les rejette à chaque fois).
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 11/07/2016 12:00 | #


Non mais que du 0x00 et du 0xff ? Avec ça les pictures prendraient 16000 octets... un peu de tenue, on a inventé le bitmap monochrome quand même.

Qui t'a dit que ce n'était pas le début du code ? Faut creuser un peu plus. Regarde l'en-tête de SimLo, vois s'il manque des infos, regarde si tu peux influencer ces octets... l'interprétation ne va pas tomber du ciel.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 20/07/2016 16:20 | #


Après une semaine de glandouille j'ai repris sérieusement mon projet et il parse sans problème mon puissance 4 (bon pour le truc du format, pour l'instant je fais juste un split() sur "PROGRAM........system.." pour avoir les différents programmes et je place la fin du programme au premier octet nul dans les 4 derniers caractères).

Par contre le programme n'est pas encore à l'état de marche, car aucune fonction n'est implémentée. Mon premier problème, outre les listes et matrices, est tout simplement le calcul. Les gens sur stackoverflow m'ont fait comprendre à coup de downvotes que 0.3 n'est qu'une illusion et qu'il n'y a pas de cuillère, du coup je suis obligé de mettre un format en BCD.

- Comment je convertis un double en BCD ? (sachant que je ne comprends rien au code de SimLo, qui est d'ailleurs du C++ et pas du C)

- Comment je fais des opérations sur les nombres BCD ? Selon wikipédia, l'addition se fait en traitant les nombres comme du binaire et en ajoutant 6, mais je suis obligé de stocker ça dans des arrays de char, est ce qu'on peut additionner des arrays de char ?

- Pour le format, comment je gère le signe, l'exposant et le signe de l'exposant ?
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 20/07/2016 18:41 | #


Pour convertir le double en BCD, utilise le code de SimLo (fiable, je peux t'expliquer les parties C++), ou bien regarde s'il y a un syscall qui traîne. Mais t'as pas envie de passer par un double. À quel moment tu veux utiliser un double ? Jamais. Encode directement les constantes en BCD.

Pour les opérations ? Utilise d'abord les syscalls de l'ALPHA MEM pour changer dans la mémoire principale la valeur des variables A-Z, r, θ, etc. Ensuite... ben, il y a un syscall qui calculera tout pour toi. Effet garanti.

Pour le format, regarde la doc de SimLo. Il a détaillé la structure.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 21/07/2016 09:26 | #


Donc, si j'ai bien compris :

- Pour les syscalls : je dois générer ce fichier en remplaçant bien sûr les syscalls par ceux utilisés pour les calculs BCD. Est ce que je dois absolument garder les tabs et les \n ?

- Pour convertir un string vers un nombre BCD, j'utilise 0x4F0: int BCD_ToStrAsNumber0(char *data, char *string) et lorsque le parseur rencontre un litéral (0.3 par exemple) il le convertit en string puis le convertit en BCD avec ce syscall. D'ailleurs est ce qu'il y a une quelconque différence avec le 1 et le 2 ? Et le résultat est stocké dans data, l'int ne sert qu'en cas d'erreur ?

- Pour afficher un nombre BCD, j'utilise Num_DataToStr.

- Pour faire les calculs, j'utilise CalculateExpression( char**formula, char opcode[2], TBCDvalue*result, int P4 ) même si je comprends pas trop comment ça marche (c'est quoi les pointeurs de pointeurs ? je fais comment pour faire 3+4.3 par exemple ?)

Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 21/07/2016 10:10 | #


Oui alors non, pour les syscalls va falloir que t'apprennes à les utiliser. On va faire ça proprement. Tu vas ajouter à ton projet généré un fichier avec les sycalls nécessaires. En l'occurrence tu n'as pas besoin de grand chose. Tu dois suivre la syntaxe suivante :
    .export    _syscall

_syscall:
    mov.l    syscall_table, r2
    mov.l    _syscall_code, r0
    jmp    @r2
    nop
_syscall_code:
    .data.l    <syscall_id>

syscall_table:
    .data.l    H'80010070

    .end

Ça fait des plombes que j'ai pas travaillé avec l'assembleur d'Hitachi, mais ça doit être bon. Voilà par exemple un fichier qui définit les sycalls malloc(), calloc() et free(). J'ai pris les numéros dans la documentation.

    .export    _malloc
    .export    _calloc
    .export    _free

_malloc:
    mov.l    syscall_table, r2
    mov.l    _malloc_code, r0
    jmp    @r2
    nop
_malloc_code:
    .data.l    H'ACD

_calloc:
    mov.l    syscall_table, r2
    mov.l    _calloc_code, r0
    jmp    @r2
    nop
_calloc_code:
    .data.l    H'E6B

_free:
    mov.l    syscall_table, r2
    mov.l    _free_code, r0
    jmp    @r2
    nop
_free_code:
    .data.l    H'ACC

syscall_table:
    .data.l    H'80010070

    .end


Tout ce que tu as à faire est, pour chaque syscall :
- Ajouter un .export avec le nom du symbole (le nom de la fonction précédé d'un underscore)
- Ajouter les 7 lignes de « _syscall: » à « .data.l <syscall_id> » (premier morceau de mon post)
- Remplacer « _syscall » par le nom du symbole, « _syscall_id » par n'importe quoi tant que c'est unique et « <syscall_id> » par le numéro.
Tu devrais t'en sortir avec ça.



C'est pas malin ce que tu racontes : BCD_ToStrAsNumber0() convertit comme son nom l'indique un BCD en Str. Ça fait une sorte de printf() quoi. C'est la fonction opposée que tu cherches. En plus il est dit dans la doc que ce syscall est basé sur 0x4f7, tu peux pas utiliser 0x4f7 pour convertir BCD → Str et un dérivé de 0x4f7 pour convertir dans l'autre sens.


Je n'ai jamais utilisé CalculateExpression() mais je pense que le code suivant peut marcher :
const char *formula = "3+4.3";
char opcode[2] = { '\n', 0 };
TBCDvalue result;
CalculateExpression(&formula, opcode, &result, 1);

En gros opcode existe pour ajouter un préfixe, mais on doit toujours pouvoir s'en passer. J'ai mis '\n' parce que la doc indique que ça ne doit pas être 0.
Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 21/07/2016 14:41 | #


Ha oui j'avais lu trop vite le nom de la méthode mais du coup c'est plus rapide d'utiliser Num_DataToStr() non ? Et c'est quoi le syscall 0x510 sur lequel BCD_ToStrAsNumber1/2() sont basées (je l'ai trouvé nulle part) ?

Aussi, pour la structure TBCDvalue on a juste besoin d'un char[24] ? La partie complexe elle est stockée à la suite ou il y a un délimiteur ?

Sinon j'ai testé le code et bien que ça compile ça ne m'affiche rien :/
typedef struct {
    char bytes[24];
} TBCDvalue;

int AddIn_main(int isAppli, unsigned short OptionNum) {
    char *function = "123";
    char result[10] = {0};
    TBCDvalue test;
    calcExp(&function, "\n", &test, 1);
    
    bcdToStr(&result, &test);
    locate(1,1);
    Print(result);
    GetKey(&key);
    return 1;
}

Et le fichier .src est normalement correct :
    .export    _bcdToStr
    .export    _calcExp

_bcdToStr:
    mov.l    syscall_table, r2
    mov.l    _bcdToStr_code, r0
    jmp    @r2
    nop
_bcdToStr_code:
    .data.l    H'4F0

_calcExp:
    mov.l    syscall_table, r2
    mov.l    _calcExp_code, r0
    jmp    @r2
    nop
_calcExp_code:
    .data.l    H'645

syscall_table:
    .data.l    H'80010070

    .end

Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Lephenixnoir Hors ligne Administrateur Points: 24145 Défis: 170 Message

Citer : Posté le 21/07/2016 14:57 | #


Plus rapide ? Non c'est complètement négligeable. Totalement, absolument avec une probabilité de plus de 90%. Je ne sais pas pour 0x510, je n'ai pas trouvé de référence dans ma table de syscalls et la seule apparition de cette valeur dans la doc est à cet endroit.

Techniquement, 12 octets, comme le Basic nous l'apprend. Si tu comptes c'est ça. Et oui, si la valeur est complexe il y a juste deux structures accolées, c'est sans doute indiqué dans le membre flags.

Si ta fonction ne fonctionne pas, essaie de comprendre mieux la doc et fais des tests. Il n'y a pas de magie. Par ailleurs, utiliser "\n" est une erreur. La doc indique que si le dernier paramètre est non nul, « formula is used, the first opcode of formula is copied to opcode » (en changeant un if en of, cela semble raisonnable étant donné que la phrase d'origine n'avait pas de sens particulier), donc le pointeur est modifié. Tu dois passer par un tableau statique et c'est pour ça que je l'ai fait.

Ce n'est sans doute pas la source du problème. Tu ne peux pas espérer faire fonctionner deux syscalls d'un coup. Commence par afficher les différents champs de ta structure TBCD calculée pour voir si elle vaut bien ce que tu cherches.

Mon graphe (24 Mars): (gint#27 ; (Rogue Life || HH2) ; PythonExtra ; serial gint ; Boson X ; ...) || (shoutbox v5 ; v5)
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 27/07/2016 22:04 | #


Une p'tite question (je suis pas vraiment bloqué, c'est juste un truc que je me demandais), quel est le mieux pour une fonction qui crée une liste : retourner une liste ou un pointeur vers une liste ? Est ce qu'il y a une quelconque différence ?
Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Cakeisalie5 En ligne Ancien administrateur Points: 1896 Défis: 11 Message

Citer : Posté le 27/07/2016 22:15 | #


Si tu fais référence au "est-ce que je dois retourner un int[] ou un int*", les deux sont exactement pareil (c'est quand tu mets une valeur dans les crochets que ça devient plus chaud).

(bon, excepté lors d'une déclaration)

Promotion ordinaire sur les inscriptions sur Planète Casio : en ce moment, c'est gratuit !

Mon blogBesoin d'utilitaires de transfert vers et depuis la calculatrice sous GNU/Linux ?
Zezombye Hors ligne Rédacteur Points: 1756 Défis: 13 Message

Citer : Posté le 27/07/2016 22:19 | #


Nan, on peut pas retourner un int[] mais ma question c'est, est ce que je fais :

List createNewList(int nbElements, ...) {
    List list;    
    //...
    return list;
}

ou
List *createNewList(int nbElements, ...) {
    List list;
    //...
    return &list;
}

Divers jeux : Puissance 4 - Chariot Wars - Sokoban
Ecrivez vos programmes basic sur PC avec BIDE
Cakeisalie5 En ligne Ancien administrateur Points: 1896 Défis: 11 Message

Citer : Posté le 27/07/2016 22:27 | #


Détailles le typedef de List ?

Promotion ordinaire sur les inscriptions sur Planète Casio : en ce moment, c'est gratuit !

Mon blogBesoin d'utilitaires de transfert vers et depuis la calculatrice sous GNU/Linux ?

LienAjouter une imageAjouter une vidéoAjouter un lien vers un profilAjouter du codeCiterAjouter un spoiler(texte affichable/masquable par un clic)Ajouter une barre de progressionItaliqueGrasSoulignéAfficher du texte barréCentréJustifiéPlus petitPlus grandPlus de smileys !
Cliquez pour épingler Cliquez pour détacher Cliquez pour fermer
Alignement de l'image: Redimensionnement de l'image (en pixel):
Afficher la liste des membres
:bow: :cool: :good: :love: ^^
:omg: :fusil: :aie: :argh: :mdr:
:boulet2: :thx: :champ: :whistle: :bounce:
valider
 :)  ;)  :D  :p
 :lol:  8)  :(  :@
 0_0  :oops:  :grr:  :E
 :O  :sry:  :mmm:  :waza:
 :'(  :here:  ^^  >:)

Σ π θ ± α β γ δ Δ σ λ
Veuillez donner la réponse en chiffre
Vous devez activer le Javascript dans votre navigateur pour pouvoir valider ce formulaire.

Si vous n'avez pas volontairement désactivé cette fonctionnalité de votre navigateur, il s'agit probablement d'un bug : contactez l'équipe de Planète Casio.

Planète Casio v4.3 © créé par Neuronix et Muelsaco 2004 - 2024 | Il y a 91 connectés | Nous contacter | Qui sommes-nous ? | Licences et remerciements

Planète Casio est un site communautaire non affilié à Casio. Toute reproduction de Planète Casio, même partielle, est interdite.
Les programmes et autres publications présentes sur Planète Casio restent la propriété de leurs auteurs et peuvent être soumis à des licences ou copyrights.
CASIO est une marque déposée par CASIO Computer Co., Ltd