几周前,我为我的Ti-84+CE计算器编写了一个反向波兰符号程序。它是我不久前用TI-BASIC编写的一个程序的继承者,但由于输入滞后太大,无法使用,所以我决定用C编写这个程序,并将其编译成本机z80程序集。
我是在比赛前一天晚上写的这个程序,我打算在比赛中使用它(事实上,我在开始考试前几分钟就对它做了最后的润色),所以请记住,我正处于时间紧缺的状态,所以我不会去寻找最干净的代码库。不过,由于我对C不太熟悉,所以我想知道我可以对代码做什么样的改进。
下面是这个程序的演示GIF,该程序用于查找一个示例数字计算器问题的答案:

我在https://github.com/arjvik/RPN-Ti84上发布了一个带有程序的git存储库
这是代码:
#include <tice.h>
real_t stack[99];
char buffer[50];
uint8_t idx;
bool decimal;
bool negative;
bool constantsmode = false;
bool scimode = true;
bool radians = true;
real_t decimalfactor;
real_t r_0, r_1, r_2, r_3, r_4, r_5, r_6, r_7, r_8, r_9, r_10, r_ln10, r_pi, r_e;
void init_real_constants() {
r_0 = os_Int24ToReal(0);
r_1 = os_Int24ToReal(1);
r_2 = os_Int24ToReal(2);
r_3 = os_Int24ToReal(3);
r_4 = os_Int24ToReal(4);
r_5 = os_Int24ToReal(5);
r_6 = os_Int24ToReal(6);
r_7 = os_Int24ToReal(7);
r_8 = os_Int24ToReal(8);
r_9 = os_Int24ToReal(9);
r_10 = os_Int24ToReal(10);
r_ln10 = os_FloatToReal(2.30258509299);
r_pi = os_FloatToReal(3.14159265359);
r_e = os_FloatToReal(2.71828182846);
}
void draw_line_clear(bool clear) {
os_RealToStr(buffer, &stack[idx], 0, 1, -1);
if (clear) {
os_SetCursorPos(9, 0);
os_PutStrFull(" ");
}
os_SetCursorPos(9, 0);
os_PutStrFull(buffer);
}
#define OVERDRAW_IS_REDRAW 0
#if OVERDRAW_IS_REDRAW
void draw_line() {
draw_line_clear(true);
}
#else
void draw_line() {
draw_line_clear(false);
}
#endif
void drawdecimal_line() {
os_SetCursorPos(9, 0);
os_PutStrFull(buffer);
os_PutStrFull(".");
}
void draw_stack_clear(uint8_t row, bool clear) {
if (row >= 9) {
os_SetCursorPos(8, 0);
os_PutStrFull("... ");
real_t len = os_Int24ToReal((int24_t) idx);
os_RealToStr(buffer, &len, 0, 1, -1);
os_SetCursorPos(8, 4);
os_PutStrFull(buffer);
} else {
if (scimode) {
os_RealToStr(buffer, &stack[row], 0, 2, 2);
} else {
os_RealToStr(buffer, &stack[row], 0, 1, -1);
}
if (clear) {
os_SetCursorPos(row, 0);
os_PutStrFull(" ");
}
os_SetCursorPos(row, 0);
os_PutStrFull(buffer);
}
}
void draw_stack(uint8_t row) {
draw_stack_clear(row, false);
}
void draw_full_stack() {
for (uint8_t row = 0; row < idx && row <= 9; row++)
draw_stack_clear(row, true);
}
void delete_stack(uint8_t row) {
if (row < 9) {
os_SetCursorPos(row, 0);
os_PutStrFull(" ");
}
}
void new_entry() {
decimal = false;
negative = false;
stack[idx] = r_0;
draw_line_clear(true);
}
void new_problem() {
idx = 0;
os_ClrHome();
buffer[0] = 0;
constantsmode = false;
new_entry();
}
#define BINARY_OP(os_func) \
do { \
if (os_RealCompare(&stack[idx], &r_0) != 0) { \
if (idx >= 1) { \
stack[idx-1] = os_func(&stack[idx-1], &stack[idx]); \
draw_stack_clear(idx-1, true); \
new_entry(); \
} \
} else { \
if (idx >= 2) { \
stack[idx-2] = os_func(&stack[idx-2], &stack[idx-1]); \
draw_stack_clear(idx-2, true); \
delete_stack(idx-1); \
idx--; \
new_entry(); \
} \
} \
} while (false);
#define UNARY_OP(os_func) \
do { \
if (os_RealCompare(&stack[idx], &r_0) != 0) { \
stack[idx] = os_func(&stack[idx]); \
draw_line_clear(true); \
} else { \
if (idx >= 1) { \
stack[idx-1] = os_func(&stack[idx-1]); \
draw_stack_clear(idx-1, true); \
new_entry(); \
} \
} \
} while (false);
#define REAL_TRIG(name, os_func) \
real_t name(real_t *a) { \
real_t t; \
if (radians) \
t = *a; \
else \
t = os_RealDegToRad(a); \
return os_func(&t); \
}
REAL_TRIG(degRadSin, os_RealSinRad)
REAL_TRIG(degRadCos, os_RealCosRad)
REAL_TRIG(degRadTan, os_RealTanRad)
#define REAL_INVTRIG(name, os_func) \
real_t name(real_t *a) { \
real_t t = os_func(a); \
if (!radians) \
t = os_RealRadToDeg(&t); \
return t; \
}
REAL_INVTRIG(radDegAsin, os_RealAsinRad)
REAL_INVTRIG(radDegAcos, os_RealAcosRad)
REAL_INVTRIG(radDegAtan, os_RealAtanRad)
real_t realLogBase10(real_t *a) {
real_t t = os_RealLog(a);
return os_RealDiv(&t, &r_ln10);
}
real_t realSquare(real_t *a) {
return os_RealMul(a, a);
}
void main() {
uint8_t key;
init_real_constants();
new_problem();
while ((key = os_GetCSC()) != sk_Graph) {
if (constantsmode) {
if (key == sk_Power) {
stack[idx] = r_pi;
constantsmode = false;
draw_line_clear(true);
} else if (key == sk_Div) {
stack[idx] = r_e;
constantsmode = false;
draw_line_clear(true);
} else if (key == sk_2nd) {
constantsmode = false;
} else if (key == sk_Del) {
new_problem();
}
} else {
if (key == sk_0 || key == sk_1 || key == sk_2 || key == sk_3 || key == sk_4 ||
key == sk_5 || key == sk_6 || key == sk_7 || key == sk_8 || key == sk_9 ) {
if (!decimal) {
stack[idx] = os_RealMul(&stack[idx], &r_10);
real_t toAdd = r_0;
if (key == sk_1) toAdd = r_1;
if (key == sk_2) toAdd = r_2;
if (key == sk_3) toAdd = r_3;
if (key == sk_4) toAdd = r_4;
if (key == sk_5) toAdd = r_5;
if (key == sk_6) toAdd = r_6;
if (key == sk_7) toAdd = r_7;
if (key == sk_8) toAdd = r_8;
if (key == sk_9) toAdd = r_9;
if (!negative)
stack[idx] = os_RealAdd(&stack[idx], &toAdd);
else
stack[idx] = os_RealSub(&stack[idx], &toAdd);
draw_line();
} else {
real_t toAdd = r_0;
if (key == sk_1) toAdd = r_1;
if (key == sk_2) toAdd = r_2;
if (key == sk_3) toAdd = r_3;
if (key == sk_4) toAdd = r_4;
if (key == sk_5) toAdd = r_5;
if (key == sk_6) toAdd = r_6;
if (key == sk_7) toAdd = r_7;
if (key == sk_8) toAdd = r_8;
if (key == sk_9) toAdd = r_9;
toAdd = os_RealMul(&toAdd, &decimalfactor);
if (!negative)
stack[idx] = os_RealAdd(&stack[idx], &toAdd);
else
stack[idx] = os_RealSub(&stack[idx], &toAdd);
decimalfactor = os_RealDiv(&decimalfactor, &r_10);
draw_line_clear(true);
}
} else if (key == sk_Chs) {
stack[idx] = os_RealNeg(&stack[idx]);
negative = !negative;
draw_line_clear(true);
} else if (key == sk_DecPnt) {
if (!decimal) {
decimal = true;
decimalfactor = os_RealDiv(&r_1, &r_10);
drawdecimal_line();
}
} else if (key == sk_Clear) {
new_entry();
} else if (key == sk_Left) {
if (negative) os_RealNeg(&stack[idx]);
if (!decimal) {
stack[idx] = os_RealDiv(&stack[idx], &r_10);
} else decimal = false;
stack[idx] = os_RealFloor(&stack[idx]);
if (negative) os_RealNeg(&stack[idx]);
draw_line_clear(true);
} else if (key == sk_Enter) {
if (idx == 98) {
new_problem();
} else {
draw_stack(idx++);
new_entry();
}
} else if (key == sk_Mode) {
scimode = !scimode;
draw_full_stack();
} else if (key == sk_Stat) {
radians = !radians;
os_SetCursorPos(9, 0);
os_PutStrFull(radians ? "r" : "d");
}else if (key == sk_Del) {
new_problem();
} else if (key == sk_Add) {
BINARY_OP(os_RealAdd);
} else if (key == sk_Sub) {
BINARY_OP(os_RealSub);
} else if (key == sk_Mul) {
BINARY_OP(os_RealMul);
} else if (key == sk_Div) {
BINARY_OP(os_RealDiv);
} else if (key == sk_Power) {
BINARY_OP(os_RealPow);
} else if (key == sk_Log) {
UNARY_OP(realLogBase10);
} else if (key == sk_Ln) {
UNARY_OP(os_RealLog);
} else if (key == sk_Sin) {
UNARY_OP(degRadSin);
} else if (key == sk_Cos) {
UNARY_OP(degRadCos);
} else if (key == sk_Tan) {
UNARY_OP(degRadTan);
} else if (key == sk_Apps) {
UNARY_OP(radDegAsin);
} else if (key == sk_Prgm) {
UNARY_OP(radDegAcos);
} else if (key == sk_Vars) {
UNARY_OP(radDegAtan);
} else if (key == sk_Square) {
UNARY_OP(realSquare);
} else if (key == sk_Recip) {
UNARY_OP(os_RealInv);
} else if (key == sk_2nd) {
constantsmode = true;
} else if (key == sk_Yequ) {
os_ClrHome();
os_SetCursorPos(0, 0);
os_PutStrFull("Arjun's RPN Calculator");
os_SetCursorPos(1, 0);
os_PutStrFull("v2.0 (ASM)");
os_SetCursorPos(3, 0);
os_PutStrFull("git.io/ti84rpn");
while (os_GetCSC() == 0);
os_ClrHome();
draw_full_stack();
draw_line_clear(true);
}
}
}
}我使用的tice.h来自CE-程序设计/工具链
发布于 2021-04-05 16:51:17
而不是
#define OVERDRAW_IS_REDRAW 0
#if OVERDRAW_IS_REDRAW
void draw_line() {
draw_line_clear(true);
}
#else
void draw_line() {
draw_line_clear(false);
}
#endif好呀
#define OVERDRAW_IS_REDRAW false
void draw_line() {
draw_line_clear(OVERDRAW_IS_REDRAW);
}?
否则:我不清楚您的z80编译器的功能,但是
将其编译为本机z80程序集。
可能不是发生了什么。您可能正在编译为本机z80机器代码,并且更关心这个机器代码而不是程序集。根据编译器的不同,它可以作为中间步骤发出程序集列表;在gcc中,这可能类似于gcc -Wa,-al。
BINARY_OP和UNARY_OP有点尴尬。它们会像你的main那么大,已经太大了。相反,请考虑将它们转换为接受os_func函数指针的普通旧函数。除其他外,这将减少您的最终二进制大小。这个呼叫开销是否会如此繁重以至于难以察觉,这是值得怀疑的,但请进行测试。
我看到您的while (false)模式也反映在您正在使用的第三方工具链头中。为什么?如果您只想要一个合理的块,请保留{}并删除do/while(false)。匿名作用域块在C中很容易并且是免费的,不应该需要循环攻击。但是,如果您将_OP函数转换为正常函数,这将不是一个问题。
main太大太复杂了。把它分解成子程序。
整个街区:
if (key == sk_1) toAdd = r_1;
if (key == sk_2) toAdd = r_2;
if (key == sk_3) toAdd = r_3;
if (key == sk_4) toAdd = r_4;
if (key == sk_5) toAdd = r_5;
if (key == sk_6) toAdd = r_6;
if (key == sk_7) toAdd = r_7;
if (key == sk_8) toAdd = r_8;
if (key == sk_9) toAdd = r_9;可以用查找表替换。一些疯子认为sk_值应该是不连续的:
#define sk_0 0x21
#define sk_1 0x22
#define sk_4 0x23
#define sk_7 0x24
#define sk_2 0x1A
#define sk_5 0x1B
#define sk_8 0x1C
#define sk_3 0x12
#define sk_6 0x13
#define sk_9 0x14因此,如果您确实制作了这样一个查找表,它将有一个“有趣的”值顺序;您可以将其初始化如下
static real_t r_numerals[sk_9 - sk_0 + 1];
// ...
r_numerals[sk_0 - sk_0] = r_0;
r_numerals[sk_1 - sk_0] = r_1;
r_numerals[sk_2 - sk_0] = r_2;
r_numerals[sk_3 - sk_0] = r_3;
r_numerals[sk_4 - sk_0] = r_4;
r_numerals[sk_5 - sk_0] = r_5;
r_numerals[sk_6 - sk_0] = r_6;
r_numerals[sk_7 - sk_0] = r_7;
r_numerals[sk_8 - sk_0] = r_8;
r_numerals[sk_9 - sk_0] = r_9;
// ...
toAdd = r_numerals[key - sk_0];或者,如果您更担心性能,而不那么担心内存,只需创建一个长为0x40元素的数组,该数组代表整个键空间。您可以更进一步,使用指向您自己函数的指针填充一个完整的查找表,这将真正减少main中的键检查噪声。
https://codereview.stackexchange.com/questions/259105
复制相似问题