Decent `if` and `def` support!
This commit is contained in:
parent
77ff84fd30
commit
a3bf8ab864
|
@ -24,7 +24,7 @@
|
||||||
"aplite",
|
"aplite",
|
||||||
"basalt"
|
"basalt"
|
||||||
],
|
],
|
||||||
"uuid": "3a239ae0-adc5-4d40-b871-6fbcd8c37e7c",
|
"uuid": "70ec170a-8e1b-11ea-bc55-0242ac130003",
|
||||||
"versionLabel": "0.1",
|
"versionLabel": "0.1",
|
||||||
"watchapp": {
|
"watchapp": {
|
||||||
"watchface": false
|
"watchface": false
|
||||||
|
|
Binary file not shown.
58
src/calc.c
58
src/calc.c
|
@ -1,25 +1,32 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "fixed.h"
|
//#include "fixed.h"
|
||||||
#include "calc.h"
|
#include "calc.h"
|
||||||
#include "pebblisp.h"
|
|
||||||
|
|
||||||
static inline char* getToken(int n) {
|
static inline int8_t tokenCount() {
|
||||||
const int length = sizeof(tokens) / sizeof(tokens[0]);
|
return sizeof(tokens) / sizeof(tokens[0]);
|
||||||
return tokens[n % length];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int8_t selected_token = 1; //Currently selected button, starts on '5'
|
static inline char* getToken(int8_t n) {
|
||||||
static struct Environment env;
|
return tokens[n % tokenCount()];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Currently selected button, starts on '('
|
||||||
|
static int8_t selected_token = 1;
|
||||||
|
|
||||||
|
// Update the current code text with the contents of `mytext`,
|
||||||
|
// and add the current selected_token to the end
|
||||||
static void updateText()
|
static void updateText()
|
||||||
{
|
{
|
||||||
strcpy(temptext, mytext);
|
strcpy(temptext, mytext);
|
||||||
|
|
||||||
if(getToken(selected_token)[0] == ' ') {
|
const char *token = getToken(selected_token);
|
||||||
|
if(token[0] == ' ') {
|
||||||
strcat(temptext, "_");
|
strcat(temptext, "_");
|
||||||
|
} else if(token[0] == '\n') {
|
||||||
|
strcat(temptext, "\\n");
|
||||||
} else {
|
} else {
|
||||||
strcat(temptext, getToken(selected_token));
|
strcat(temptext, token);
|
||||||
}
|
}
|
||||||
|
|
||||||
text_layer_set_text(s_input_text_layer, temptext);
|
text_layer_set_text(s_input_text_layer, temptext);
|
||||||
|
@ -28,18 +35,26 @@ static void updateText()
|
||||||
// Button handler
|
// Button handler
|
||||||
static void up_down_handler(ClickRecognizerRef recognizer, void *context){
|
static void up_down_handler(ClickRecognizerRef recognizer, void *context){
|
||||||
// Change current token
|
// Change current token
|
||||||
selected_token += (click_recognizer_get_button_id(recognizer) == BUTTON_ID_DOWN) ? 1 : -1;
|
if(click_recognizer_get_button_id(recognizer) == BUTTON_ID_DOWN)
|
||||||
|
selected_token++;
|
||||||
|
else
|
||||||
|
selected_token--;
|
||||||
|
|
||||||
// If selected token is outside of range, wrap around
|
// If selected token is outside of range, wrap around
|
||||||
selected_token = selected_token < 0 ? TOKEN_END : selected_token > TOKEN_END ? 0 : selected_token;
|
if(selected_token < 0)
|
||||||
|
selected_token = tokenCount() - 1;
|
||||||
|
else if(selected_token >= tokenCount())
|
||||||
|
selected_token = 0;
|
||||||
|
|
||||||
updateText();
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Backspace if possible, otherwise close the app
|
||||||
static void back_handler(ClickRecognizerRef recognizer, void *context) {
|
static void back_handler(ClickRecognizerRef recognizer, void *context) {
|
||||||
if(mytext[0] == '\0') {
|
if(mytext[0] == '\0') {
|
||||||
window_stack_remove(window_stack_get_top_window(), true);
|
window_stack_remove(window_stack_get_top_window(), true);
|
||||||
} else {
|
} else {
|
||||||
int i = 0;
|
int8_t i = 0;
|
||||||
while(mytext[++i] != '\0') { ; }
|
while(mytext[++i] != '\0') { ; }
|
||||||
mytext[i-1] = '\0';
|
mytext[i-1] = '\0';
|
||||||
updateText();
|
updateText();
|
||||||
|
@ -53,14 +68,14 @@ static void enter(){
|
||||||
updateText();
|
updateText();
|
||||||
}
|
}
|
||||||
|
|
||||||
//Calculate result, display it and reset
|
// Calculate result, display it and reset
|
||||||
static void calculate(){
|
static void calculate(){
|
||||||
Object obj = parseEval(mytext, &env);
|
Object obj = parseEval(mytext, &env);
|
||||||
char temp[MAX_LENGTH-2] = "";
|
char temp[MAX_LENGTH-2] = "";
|
||||||
|
|
||||||
stringObj(temp, &obj);
|
stringObj(temp, &obj);
|
||||||
snprintf(resulttext, MAX_LENGTH, "R:%s", temp);
|
snprintf(resulttext, MAX_LENGTH, "R:%s", temp);
|
||||||
selected_token = 0;
|
selected_token = 0;
|
||||||
//strcpy(mytext, HAHA);
|
|
||||||
text_layer_set_text(s_result_text_layer, resulttext);
|
text_layer_set_text(s_result_text_layer, resulttext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +98,7 @@ static void click_config_provider(void *context) {
|
||||||
static void init(void) {
|
static void init(void) {
|
||||||
// Create a window and get information about the window
|
// Create a window and get information about the window
|
||||||
s_window = window_create();
|
s_window = window_create();
|
||||||
// Layer *window_layer = window_get_root_layer(s_window);
|
|
||||||
// Register click config provider
|
// Register click config provider
|
||||||
window_set_click_config_provider(s_window, click_config_provider);
|
window_set_click_config_provider(s_window, click_config_provider);
|
||||||
|
|
||||||
|
@ -105,13 +120,20 @@ static void init(void) {
|
||||||
// Push the window, setting the window animation to 'true'
|
// Push the window, setting the window animation to 'true'
|
||||||
window_stack_push(s_window, true);
|
window_stack_push(s_window, true);
|
||||||
env = defaultEnv();
|
env = defaultEnv();
|
||||||
|
|
||||||
|
// If possible, load the previous code text
|
||||||
|
if(persist_exists(CODE_PKEY)) {
|
||||||
|
persist_read_string(CODE_PKEY, mytext, SMAX_LENGTH);
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deinit(void) {
|
static void deinit(void) {
|
||||||
// Destroy the text layer
|
// Save the current code text
|
||||||
text_layer_destroy(s_input_text_layer);
|
persist_write_string(CODE_PKEY, temptext);
|
||||||
|
|
||||||
// Destroy the window
|
deleteEnv(&env);
|
||||||
|
text_layer_destroy(s_input_text_layer);
|
||||||
window_destroy(s_window);
|
window_destroy(s_window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
20
src/calc.h
20
src/calc.h
|
@ -1,3 +1,6 @@
|
||||||
|
#ifndef CALC_H
|
||||||
|
#define CALC_H
|
||||||
|
|
||||||
#include <pebble.h>
|
#include <pebble.h>
|
||||||
#include "pebblisp.h"
|
#include "pebblisp.h"
|
||||||
|
|
||||||
|
@ -5,13 +8,23 @@
|
||||||
#define MAX_LENGTH 11
|
#define MAX_LENGTH 11
|
||||||
#define END_PHRASE "END"
|
#define END_PHRASE "END"
|
||||||
|
|
||||||
|
#define CODE_PKEY 1
|
||||||
|
|
||||||
// Layers
|
// Layers
|
||||||
Window *s_window;
|
Window *s_window;
|
||||||
TextLayer *s_input_text_layer;
|
TextLayer *s_input_text_layer;
|
||||||
TextLayer *s_result_text_layer;
|
TextLayer *s_result_text_layer;
|
||||||
|
|
||||||
|
// PebbLisp environment
|
||||||
|
static struct Environment env;
|
||||||
|
|
||||||
|
// Live code text
|
||||||
char mytext[SMAX_LENGTH] = "";
|
char mytext[SMAX_LENGTH] = "";
|
||||||
|
|
||||||
|
// The actual displayed code text
|
||||||
char temptext[SMAX_LENGTH] = "";
|
char temptext[SMAX_LENGTH] = "";
|
||||||
|
|
||||||
|
// The result of execution
|
||||||
char resulttext[MAX_LENGTH] = "";
|
char resulttext[MAX_LENGTH] = "";
|
||||||
|
|
||||||
char *tokens[] = {
|
char *tokens[] = {
|
||||||
|
@ -21,8 +34,11 @@ char *tokens[] = {
|
||||||
"4","5","6",
|
"4","5","6",
|
||||||
"7","8","9", "0",
|
"7","8","9", "0",
|
||||||
"a", "b", "c", "d", "e",
|
"a", "b", "c", "d", "e",
|
||||||
"= ", "< ", "> ", "def",
|
"= ", "< ", "> ",
|
||||||
|
"def", "if", "\n",
|
||||||
END_PHRASE
|
END_PHRASE
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TOKEN_END 26
|
#define TOKEN_END 27
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
299
src/fixed.c
299
src/fixed.c
|
@ -1,299 +0,0 @@
|
||||||
/** @file fixed.c
|
|
||||||
* @brief A fixed point numbers implementation.
|
|
||||||
* @author Wojciech 'vifon' Siewierski
|
|
||||||
*/
|
|
||||||
|
|
||||||
/***********************************************************************************/
|
|
||||||
/* Copyright (C) 2015 Wojciech Siewierski <wojciech dot siewierski at onet dot pl> */
|
|
||||||
/* */
|
|
||||||
/* Author: Wojciech Siewierski <wojciech dot siewierski at onet dot pl> */
|
|
||||||
/* */
|
|
||||||
/* 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 3 */
|
|
||||||
/* 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. If not, see <http://www.gnu.org/licenses/>. */
|
|
||||||
/***********************************************************************************/
|
|
||||||
|
|
||||||
#include "fixed.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
/** Sum two fixed point numbers.
|
|
||||||
*
|
|
||||||
* @param lhs
|
|
||||||
* @param rhs
|
|
||||||
* @param[out] overflow Indicate whether the addition would
|
|
||||||
* result in an overflow. If the initial value is @p true, it will
|
|
||||||
* stay @p true. The returned value is unspecified if it is true.
|
|
||||||
*
|
|
||||||
* @return The result.
|
|
||||||
*/
|
|
||||||
fixed fixed_add(fixed lhs, fixed rhs, bool* overflow)
|
|
||||||
{
|
|
||||||
// If both arguments have the same sign...
|
|
||||||
if ((rhs > 0) == (lhs > 0)) {
|
|
||||||
// ...check for the overflow.
|
|
||||||
*overflow = *overflow || abs(lhs) > FIXED_MAX - abs(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*overflow) {
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lhs + rhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Subtract two fixed point numbers.
|
|
||||||
*
|
|
||||||
* @param lhs
|
|
||||||
* @param rhs
|
|
||||||
* @param[out] overflow Indicate whether the subtraction would
|
|
||||||
* result in an overflow. If the initial value is @p true, it will
|
|
||||||
* stay @p true. The returned value is unspecified if it is true.
|
|
||||||
*
|
|
||||||
* @return The result.
|
|
||||||
*/
|
|
||||||
fixed fixed_subt(fixed lhs, fixed rhs, bool* overflow)
|
|
||||||
{
|
|
||||||
return fixed_add(lhs, -rhs, overflow);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Multiply two fixed point numbers.
|
|
||||||
*
|
|
||||||
* @param lhs
|
|
||||||
* @param rhs
|
|
||||||
* @param[out] overflow Indicate whether the multiplication would
|
|
||||||
* result in an overflow. If the initial value is @p true, it will
|
|
||||||
* stay @p true. The returned value is unspecified if it is true.
|
|
||||||
*
|
|
||||||
* @return The result.
|
|
||||||
*/
|
|
||||||
fixed fixed_mult(fixed lhs, fixed rhs, bool* overflow)
|
|
||||||
{
|
|
||||||
if (fixed_to_int(rhs) != 0) {
|
|
||||||
*overflow = *overflow || abs(lhs) > abs(fixed_div(FIXED_MAX, rhs));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*overflow) {
|
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (lhs / FIXED_SCALE) * rhs
|
|
||||||
+ ((lhs % FIXED_SCALE) * rhs) / FIXED_SCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Divide two fixed point numbers.
|
|
||||||
*
|
|
||||||
* @param lhs
|
|
||||||
* @param rhs
|
|
||||||
*
|
|
||||||
* @note The fractional part of @p rhs is ignored for large @p lhs
|
|
||||||
* due to a change in the order of performed operations made to avoid
|
|
||||||
* overflows.
|
|
||||||
*
|
|
||||||
* @return The result.
|
|
||||||
*/
|
|
||||||
fixed fixed_div(fixed lhs, fixed rhs)
|
|
||||||
{
|
|
||||||
/* Check if it's safe to normalize lhs instead of rhs for precision. */
|
|
||||||
if (lhs < FIXED_MAX / FIXED_SCALE) {
|
|
||||||
/* Keep precision whether possible. */
|
|
||||||
lhs = lhs * FIXED_SCALE;
|
|
||||||
} else {
|
|
||||||
/* Sacrifice the fractional part of rhs when the another order
|
|
||||||
* of operations would cause an overflow. */
|
|
||||||
rhs = fixed_to_int(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rhs == 0) {
|
|
||||||
return 0; /* TODO: handle properly */
|
|
||||||
} else {
|
|
||||||
return lhs / rhs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Create the textual representation of the fixed point number.
|
|
||||||
*
|
|
||||||
* @param fixed A number to represent.
|
|
||||||
* @param buffer A buffer to store the representation.
|
|
||||||
* @param size Size of @p buffer.
|
|
||||||
*
|
|
||||||
* @return A pointer to the @p buffer parameter.
|
|
||||||
*/
|
|
||||||
char* fixed_repr(fixed fixed, char* buffer, size_t size)
|
|
||||||
{
|
|
||||||
const char* sign = (fixed < 0 ? "-" : "");
|
|
||||||
int integal_part = abs(fixed) / FIXED_SCALE;
|
|
||||||
int fractional_part = abs(fixed) % FIXED_SCALE;
|
|
||||||
|
|
||||||
if (fractional_part != 0) {
|
|
||||||
int n = snprintf(buffer, size,
|
|
||||||
"%s%d.%02u",
|
|
||||||
sign, integal_part, fractional_part);
|
|
||||||
|
|
||||||
/* Remove the trailing zeros. */
|
|
||||||
if (fractional_part >= 10 &&
|
|
||||||
fractional_part % 10 == 0) {
|
|
||||||
|
|
||||||
buffer[n-1] = '\0';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
snprintf(buffer, size,
|
|
||||||
"%s%d",
|
|
||||||
sign, integal_part);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convert a string to integer.
|
|
||||||
*
|
|
||||||
* @param str String to convert.
|
|
||||||
* @param[out] endptr If non-NULL, set to the first invalid character.
|
|
||||||
* @param maxnum Max number of digits to read. Pass -1 for unlimited.
|
|
||||||
*
|
|
||||||
* @return The converted integer.
|
|
||||||
*/
|
|
||||||
int str_to_int(const char *str, char **endptr, int maxnum) {
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
int sign = 1;
|
|
||||||
if (*str == '-') {
|
|
||||||
++str;
|
|
||||||
sign = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (*str >= '0' && *str <= '9' && maxnum-- != 0) {
|
|
||||||
result *= 10;
|
|
||||||
result += *str++ - '0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* save the position of the first invalid character */
|
|
||||||
if (endptr != NULL) {
|
|
||||||
/* http://stackoverflow.com/questions/993700/are-strtol-strtod-unsafe */
|
|
||||||
*endptr = (char*)str;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sign * result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convert a string to a fixed point number.
|
|
||||||
*
|
|
||||||
* @param str String to convert.
|
|
||||||
* @param[out] overflow Indicate whether the conversion would
|
|
||||||
* result in an overflow. If the initial value is @p true, it will
|
|
||||||
* stay @p true. The returned value is unspecified if it is true.
|
|
||||||
*
|
|
||||||
* @return The converted fixed point number.
|
|
||||||
*/
|
|
||||||
fixed str_to_fixed(const char* str, bool* overflow)
|
|
||||||
{
|
|
||||||
char* fractional_start;
|
|
||||||
char* endptr;
|
|
||||||
|
|
||||||
int sign = 1;
|
|
||||||
if (*str == '-') {
|
|
||||||
++str;
|
|
||||||
sign = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Detect a potential overflow.
|
|
||||||
static const int FIXED_MAX_digits = 8;
|
|
||||||
static const char* FIXED_MAX_char = "21474836"; /* FIXED_MAX/FIXED_SCALE */
|
|
||||||
const char* integral_end = strchr(str, '.');
|
|
||||||
if (integral_end == NULL) {
|
|
||||||
integral_end = str + strlen(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (integral_end - str > FIXED_MAX_digits) {
|
|
||||||
*overflow = true;
|
|
||||||
return 0;
|
|
||||||
} else if (integral_end - str == FIXED_MAX_digits) {
|
|
||||||
/* strcmp will return a positive number for string
|
|
||||||
* lexicographically greater than FIXED_MAX_digits. For
|
|
||||||
* strings of the same length (which is the case in this if
|
|
||||||
* branch) it is the same as being numerically greater. */
|
|
||||||
if (strncmp(str, FIXED_MAX_char, FIXED_MAX_digits) > 0) {
|
|
||||||
*overflow = true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int integral_part = str_to_int(str, &fractional_start, -1) * FIXED_SCALE;
|
|
||||||
if (*fractional_start != '\0') {
|
|
||||||
++fractional_start;
|
|
||||||
}
|
|
||||||
int fractional_part = str_to_int(fractional_start, &endptr, 2);
|
|
||||||
|
|
||||||
if (endptr - fractional_start == 1) {
|
|
||||||
/* There was only one digit -- higher order of magnitude. */
|
|
||||||
fractional_part *= 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sign * (integral_part + fractional_part);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convert the fixed point value to a regular integer.
|
|
||||||
*
|
|
||||||
* @param n
|
|
||||||
*
|
|
||||||
* @return The integral part of the fixed point number.
|
|
||||||
*/
|
|
||||||
int fixed_to_int(fixed n)
|
|
||||||
{
|
|
||||||
return n / FIXED_SCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Convert the integer to a fixed point value.
|
|
||||||
*
|
|
||||||
* @param n
|
|
||||||
*
|
|
||||||
* @return The converted fixed point number.
|
|
||||||
*/
|
|
||||||
fixed int_to_fixed(int n)
|
|
||||||
{
|
|
||||||
return n * FIXED_SCALE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A simple implementation of the <tt>pow(3)</tt> standard function
|
|
||||||
* for fixed point numbers.
|
|
||||||
*
|
|
||||||
* @param base
|
|
||||||
* @param exponent
|
|
||||||
* @param[out] overflow Indicate whether the exponentiation would
|
|
||||||
* result in an overflow. If the initial value is @p true, it will
|
|
||||||
* stay @p true. The returned value is unspecified if it is true.
|
|
||||||
*
|
|
||||||
* @return The exponentiation result.
|
|
||||||
*
|
|
||||||
* @note The exponent is an integer, not a fixed point number.
|
|
||||||
*/
|
|
||||||
fixed fixed_pow(fixed base, int exponent, bool* overflow)
|
|
||||||
{
|
|
||||||
fixed result = FIXED_SCALE;
|
|
||||||
|
|
||||||
bool negative = exponent < 0;
|
|
||||||
exponent = abs(exponent);
|
|
||||||
|
|
||||||
while (exponent-- && *overflow == false) {
|
|
||||||
result = fixed_mult(result, base, overflow);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (negative) {
|
|
||||||
return fixed_div(int_to_fixed(1),
|
|
||||||
result);
|
|
||||||
} else {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
55
src/fixed.h
55
src/fixed.h
|
@ -1,55 +0,0 @@
|
||||||
/** @file fixed.h
|
|
||||||
* @brief A fixed point numbers implementation.
|
|
||||||
* @author Wojciech 'vifon' Siewierski
|
|
||||||
*/
|
|
||||||
|
|
||||||
/***********************************************************************************/
|
|
||||||
/* Copyright (C) 2015 Wojciech Siewierski <wojciech dot siewierski at onet dot pl> */
|
|
||||||
/* */
|
|
||||||
/* Author: Wojciech Siewierski <wojciech dot siewierski at onet dot pl> */
|
|
||||||
/* */
|
|
||||||
/* 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 3 */
|
|
||||||
/* 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. If not, see <http://www.gnu.org/licenses/>. */
|
|
||||||
/***********************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _h_FIXED_
|
|
||||||
#define _h_FIXED_
|
|
||||||
|
|
||||||
/* Do not include pebble.h when compiling the unittests. */
|
|
||||||
#ifndef __cplusplus
|
|
||||||
# include <pebble.h> /* for bool */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <limits.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/** The underlying fixed point representation. */
|
|
||||||
typedef int fixed;
|
|
||||||
|
|
||||||
/** The scaling factor of the fixed point numbers. */
|
|
||||||
#define FIXED_SCALE 100
|
|
||||||
|
|
||||||
/** Maximum representable value. */
|
|
||||||
static const fixed FIXED_MAX = INT_MAX;
|
|
||||||
|
|
||||||
fixed fixed_add(fixed lhs, fixed rhs, bool* overflow);
|
|
||||||
fixed fixed_subt(fixed lhs, fixed rhs, bool* overflow);
|
|
||||||
fixed fixed_mult(fixed lhs, fixed rhs, bool* overflow);
|
|
||||||
fixed fixed_div(fixed lhs, fixed rhs);
|
|
||||||
char* fixed_repr(fixed fixed, char* buffer, size_t size);
|
|
||||||
fixed str_to_fixed(const char* str, bool* overflow);
|
|
||||||
int fixed_to_int(fixed n);
|
|
||||||
fixed int_to_fixed(int n);
|
|
||||||
fixed fixed_pow(fixed base, int exponent, bool* overflow);
|
|
||||||
|
|
||||||
#endif
|
|
214
src/pebblisp.c
214
src/pebblisp.c
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#ifndef STANDALONE
|
#ifndef STANDALONE
|
||||||
#define printf(...) copySlice(NULL, NULL)
|
#define printf(...) copySlice(NULL, NULL)
|
||||||
#else
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void copySlice(char * dest, struct Slice *src)
|
void copySlice(char * dest, struct Slice *src)
|
||||||
|
@ -14,25 +13,25 @@ void copySlice(char * dest, struct Slice *src)
|
||||||
if(!dest || !src)
|
if(!dest || !src)
|
||||||
return;
|
return;
|
||||||
strncpy(dest, src->text, src->length);
|
strncpy(dest, src->text, src->length);
|
||||||
dest[src->length] = '\0';
|
dest[(int)src->length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void debugSlice(struct Slice *s)
|
void debugSlice(struct Slice *s)
|
||||||
{
|
{
|
||||||
//printf("Debug Slice\n text:'");
|
printf("Debug Slice\n text:'");
|
||||||
for(int i = 0; i < s->length; i++) {
|
for(int i = 0; i < s->length; i++) {
|
||||||
//printf("%c", s->text[i]);
|
printf("%c", s->text[i]);
|
||||||
}
|
}
|
||||||
// printf("'\n");
|
printf("'\n");
|
||||||
// printf(" length: %d\n", s->length);
|
printf(" length: %d\n", s->length);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object fetchFromEnvironment(const char *name, struct Environment *env)
|
Object fetchFromEnvironment(const char *name, struct Environment *env)
|
||||||
{
|
{
|
||||||
|
printf("Fetching '%s' from env\n", name);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
const char *next = env->strings[i];
|
const char *next = env->strings[i];
|
||||||
while(next != NULL) {
|
while(next != NULL) {
|
||||||
// printf("fetching '%s' against '%s'\n", name, next);
|
|
||||||
if(strcmp(name, next) == 0) {
|
if(strcmp(name, next) == 0) {
|
||||||
return env->objects[i];
|
return env->objects[i];
|
||||||
}
|
}
|
||||||
|
@ -46,13 +45,12 @@ Object fetchFromEnvironment(const char *name, struct Environment *env)
|
||||||
|
|
||||||
Result parse(struct Slice *slices)
|
Result parse(struct Slice *slices)
|
||||||
{
|
{
|
||||||
// printf("parse() START\n");
|
|
||||||
struct Slice *token = slices;
|
struct Slice *token = slices;
|
||||||
struct Slice *rest;
|
struct Slice *rest;
|
||||||
if(token->text != NULL) {
|
if(token->text != NULL) {
|
||||||
rest = &slices[1];
|
rest = &slices[1];
|
||||||
} else {
|
} else {
|
||||||
// printf("Assigning null...\n");
|
printf("Assigning null...\n");
|
||||||
rest = NULL;
|
rest = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,18 +60,11 @@ Result parse(struct Slice *slices)
|
||||||
} else { // todo error on closed paren
|
} else { // todo error on closed paren
|
||||||
return R(parseAtom(token), rest);
|
return R(parseAtom(token), rest);
|
||||||
}
|
}
|
||||||
// printf("parse() END\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result readSeq(struct Slice *tokens)
|
Result readSeq(struct Slice *tokens)
|
||||||
{
|
{
|
||||||
// printf("readSeq() START\n");
|
Object res = listObject();
|
||||||
Object res;
|
|
||||||
res.forward = NULL;
|
|
||||||
res.type = TYPE_LIST;
|
|
||||||
//res.list = malloc(sizeof(Object));
|
|
||||||
|
|
||||||
Object *march = &res;
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
struct Slice *next = &tokens[0];
|
struct Slice *next = &tokens[0];
|
||||||
struct Slice *rest = next->text? &next[1] : NULL;
|
struct Slice *rest = next->text? &next[1] : NULL;
|
||||||
|
@ -81,16 +72,9 @@ Result readSeq(struct Slice *tokens)
|
||||||
return R(res, rest);
|
return R(res, rest);
|
||||||
}
|
}
|
||||||
Result r = parse(tokens);
|
Result r = parse(tokens);
|
||||||
// printf("readSeq() before malloc\n");
|
addToList(&res, r.obj);
|
||||||
march->forward = malloc(sizeof(struct Object));
|
|
||||||
// printf("readSeq() after malloc\n");
|
|
||||||
*march->forward = r.obj;
|
|
||||||
// char out[MAX_TOK_LEN];
|
|
||||||
// printf("stringObj: %s\n", stringObj(out, &r.obj));
|
|
||||||
tokens = r.slices;
|
tokens = r.slices;
|
||||||
march = march->forward;
|
|
||||||
}
|
}
|
||||||
// printf("readSeq() END\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parseAtom(struct Slice *s)
|
Object parseAtom(struct Slice *s)
|
||||||
|
@ -117,34 +101,25 @@ Object parseAtom(struct Slice *s)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalDefArgs(const Object *first, const Object *rest,
|
Object evalDefArgs(const Object *arg_forms, struct Environment *env)
|
||||||
struct Environment *env)
|
|
||||||
{
|
{
|
||||||
printf("evalDefArgs()\n");
|
printf("evalDefArgs()\n");
|
||||||
Object o;
|
|
||||||
return o;
|
const Object *first_form = &arg_forms[0];
|
||||||
|
const char *name = first_form->name;
|
||||||
|
|
||||||
|
Object second_eval = eval(first_form->forward, env);
|
||||||
|
|
||||||
|
addToEnv(env, name, second_eval);
|
||||||
|
|
||||||
|
return *first_form;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalIfArgs(const Object *arg_forms, struct Environment *env)
|
Object evalIfArgs(const Object *arg_forms, struct Environment *env)
|
||||||
{
|
{
|
||||||
printf("evalIfArgs()\n");
|
return eval(arg_forms, env).number?
|
||||||
Object o;
|
eval(arg_forms->forward, env) :
|
||||||
|
eval(arg_forms->forward->forward, env);
|
||||||
printf("test_form:\n");
|
|
||||||
const Object *test_form = arg_forms;
|
|
||||||
printObj(test_form);
|
|
||||||
printObj(test_form->list);
|
|
||||||
//printObj(test_form->list->forward);
|
|
||||||
|
|
||||||
printf("test_eval:\n");
|
|
||||||
Object test_eval = eval(test_form, env);
|
|
||||||
printObj(&test_eval);
|
|
||||||
|
|
||||||
printf("test_form END\n");
|
|
||||||
|
|
||||||
o.type = TYPE_NUMBER;
|
|
||||||
o.number = 222;
|
|
||||||
return o;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object evalBuiltIns(const Object *first, const Object *rest, int *found,
|
Object evalBuiltIns(const Object *first, const Object *rest, int *found,
|
||||||
|
@ -152,7 +127,7 @@ Object evalBuiltIns(const Object *first, const Object *rest, int *found,
|
||||||
{
|
{
|
||||||
if(strcmp(first->name, "def") == 0) {
|
if(strcmp(first->name, "def") == 0) {
|
||||||
*found = 0;
|
*found = 0;
|
||||||
return evalDefArgs(first, rest, env);
|
return evalDefArgs(rest, env);
|
||||||
}else if(strcmp(first->name, "if") == 0) {
|
}else if(strcmp(first->name, "if") == 0) {
|
||||||
*found = 0;
|
*found = 0;
|
||||||
return evalIfArgs(rest, env);
|
return evalIfArgs(rest, env);
|
||||||
|
@ -165,20 +140,27 @@ Object evalBuiltIns(const Object *first, const Object *rest, int *found,
|
||||||
|
|
||||||
Object eval(const Object *obj, struct Environment *env)
|
Object eval(const Object *obj, struct Environment *env)
|
||||||
{
|
{
|
||||||
printf("eval(): ");
|
// printf("eval(): ");
|
||||||
printObj(obj);
|
// printObj(obj);
|
||||||
Object o = *obj;
|
Object o = *obj;
|
||||||
switch(obj->type) {
|
switch(obj->type) {
|
||||||
case TYPE_NUMBER:
|
case TYPE_NUMBER:
|
||||||
case TYPE_BOOL:
|
case TYPE_BOOL:
|
||||||
return *obj;
|
return o;
|
||||||
|
|
||||||
case TYPE_SYMBOL:
|
case TYPE_SYMBOL:
|
||||||
return fetchFromEnvironment(obj->name, env);
|
o = fetchFromEnvironment(obj->name, env);
|
||||||
|
printf("fetched object '%s':\n", obj->name);
|
||||||
|
printObj(&o);
|
||||||
|
return o;
|
||||||
|
|
||||||
case TYPE_LIST:
|
case TYPE_LIST:
|
||||||
{
|
{
|
||||||
Object first_form = *obj->forward;
|
if(listLength(obj) == 1) {
|
||||||
|
o = *obj->list;
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
Object first_form = *obj->list;
|
||||||
|
|
||||||
{ // Try to eval built-ins
|
{ // Try to eval built-ins
|
||||||
int i = -1;
|
int i = -1;
|
||||||
|
@ -195,7 +177,9 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
Object arg2 = eval(first_form.forward->forward, env);
|
Object arg2 = eval(first_form.forward->forward, env);
|
||||||
|
|
||||||
printf("Evaluating func\n");
|
printf("Evaluating func\n");
|
||||||
return first_eval.func(arg1, arg2);
|
Object func_eval = first_eval.func(arg1, arg2);
|
||||||
|
deleteList(obj);
|
||||||
|
return func_eval;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
|
@ -203,37 +187,6 @@ Object eval(const Object *obj, struct Environment *env)
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* stringObj(char *dest, const Object *obj)
|
|
||||||
{
|
|
||||||
if(obj->type == TYPE_NUMBER) {
|
|
||||||
snprintf(dest, MAX_TOK_LEN, "%d", obj->number);
|
|
||||||
} else if(obj->type == TYPE_SYMBOL) {
|
|
||||||
snprintf(dest, MAX_TOK_LEN, "%s", obj->name);
|
|
||||||
} else if(obj->type == TYPE_BOOL) {
|
|
||||||
snprintf(dest, MAX_TOK_LEN, "%s", obj->number ? "T" : "F");
|
|
||||||
}
|
|
||||||
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printObj(const Object *obj)
|
|
||||||
{
|
|
||||||
if(obj->type == TYPE_NUMBER) {
|
|
||||||
printf("TYPE_NUMBER");
|
|
||||||
} else if(obj->type == TYPE_LIST) {
|
|
||||||
printf("TYPE_LIST");
|
|
||||||
} else if(obj->type == TYPE_SYMBOL) {
|
|
||||||
printf("TYPE_SYMBOL");
|
|
||||||
} else if(obj->type == TYPE_BOOL) {
|
|
||||||
printf("TYPE_BOOL");
|
|
||||||
} else {
|
|
||||||
printf("TYPE_OTHER");
|
|
||||||
}
|
|
||||||
char temp[20] = "";
|
|
||||||
stringObj(temp, obj);
|
|
||||||
printf(": %s\n", temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
Result resultFromObjAndSlices(Object obj, struct Slice *slices)
|
Result resultFromObjAndSlices(Object obj, struct Slice *slices)
|
||||||
{
|
{
|
||||||
Result r;
|
Result r;
|
||||||
|
@ -242,37 +195,54 @@ Result resultFromObjAndSlices(Object obj, struct Slice *slices)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo could include and return a starting index for faster multi-adds
|
||||||
|
void addToEnv(struct Environment *env, const char *name, const Object obj)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < MAX_ENV_ELM; i++) {
|
||||||
|
if(env->strings[i] == NULL) {
|
||||||
|
env->strings[i] = malloc(sizeof(name));
|
||||||
|
strncpy(env->strings[i], name, MAX_TOK_LEN);
|
||||||
|
env->objects[i] = obj;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Object basicOp(Object *obj1, Object *obj2, const char op)
|
Object basicOp(Object *obj1, Object *obj2, const char op)
|
||||||
{
|
{
|
||||||
Object o;
|
Object o;
|
||||||
o.forward = NULL;
|
o.forward = NULL;
|
||||||
|
|
||||||
o.type = TYPE_NUMBER;
|
o.type = TYPE_NUMBER;
|
||||||
|
const int n1 = obj1->number;
|
||||||
|
const int n2 = obj2->number;
|
||||||
|
|
||||||
switch(op){
|
switch(op){
|
||||||
case '+':
|
case '+':
|
||||||
o.number = obj1->number + obj2->number;
|
o.number = n1 + n2;
|
||||||
return o;
|
return o;
|
||||||
case '-':
|
case '-':
|
||||||
o.number = obj1->number - obj2->number;
|
o.number = n1 - n2;
|
||||||
return o;
|
return o;
|
||||||
case '*':
|
case '*':
|
||||||
o.number = obj1->number * obj2->number;
|
o.number = n1 * n2;
|
||||||
return o;
|
return o;
|
||||||
case '/':
|
case '/':
|
||||||
o.number = obj1->number / obj2->number;
|
o.number = n1 / n2;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
o.type = TYPE_BOOL;
|
o.type = TYPE_BOOL;
|
||||||
switch(op) {
|
switch(op) {
|
||||||
case '=':
|
case '=':
|
||||||
o.number = obj1->number == obj2->number;
|
o.number = n1 == n2;
|
||||||
return o;
|
return o;
|
||||||
case '>':
|
case '>':
|
||||||
o.number = obj1->number > obj2->number;
|
o.number = n1 > n2;
|
||||||
return o;
|
return o;
|
||||||
case '<':
|
case '<':
|
||||||
o.number = obj1->number < obj2->number;
|
o.number = n1 < n2;
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,24 +261,31 @@ bopf(sub, '-');
|
||||||
bopf(mul, '*');
|
bopf(mul, '*');
|
||||||
bopf(dvi, '/');
|
bopf(dvi, '/');
|
||||||
bopf(equ, '=');
|
bopf(equ, '=');
|
||||||
|
bopf(gth, '>');
|
||||||
|
bopf(lth, '<');
|
||||||
|
|
||||||
void addFunc(const char *name, Object (*func)(Object, Object),
|
void addFunc(const char *name, Object (*func)(Object, Object),
|
||||||
struct Environment *env)
|
struct Environment *env)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
for(i = 0; i < MAX_ENV_ELM; i++) {
|
|
||||||
if(env->strings[i] == NULL) {
|
|
||||||
//printf("Adding at %d\n", i);
|
|
||||||
env->strings[i] = malloc(sizeof(name));
|
|
||||||
strncpy(env->strings[i], name, MAX_TOK_LEN);
|
|
||||||
Object o;
|
Object o;
|
||||||
o.type = TYPE_FUNC;
|
o.type = TYPE_FUNC;
|
||||||
o.forward = NULL;
|
o.forward = NULL;
|
||||||
o.func = func;
|
o.func = func;
|
||||||
env->objects[i] = o;
|
addToEnv(env, name, o);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
void deleteEnv(struct Environment *e)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while(e->strings[i]) {
|
||||||
|
free(e->strings[i]);
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
|
free(e->strings);
|
||||||
|
e->strings = NULL;
|
||||||
|
|
||||||
|
free(e->objects);
|
||||||
|
e->objects = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Environment defaultEnv() {
|
struct Environment defaultEnv() {
|
||||||
|
@ -317,42 +294,32 @@ struct Environment defaultEnv() {
|
||||||
for(int i = 0; i < MAX_ENV_ELM; i++) {
|
for(int i = 0; i < MAX_ENV_ELM; i++) {
|
||||||
e.strings[i] = NULL;
|
e.strings[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
e.objects = malloc(sizeof(Object) * MAX_ENV_ELM);
|
e.objects = malloc(sizeof(Object) * MAX_ENV_ELM);
|
||||||
|
|
||||||
addFunc("+", &add, &e);
|
addFunc("+", &add, &e);
|
||||||
addFunc("-", &sub, &e);
|
addFunc("-", &sub, &e);
|
||||||
addFunc("*", &mul, &e);
|
addFunc("*", &mul, &e);
|
||||||
addFunc("/", &dvi, &e);
|
addFunc("/", &dvi, &e);
|
||||||
addFunc("=", &equ, &e);
|
addFunc("=", &equ, &e);
|
||||||
|
addFunc(">", >h, &e);
|
||||||
|
addFunc("<", <h, &e);
|
||||||
|
|
||||||
/*
|
|
||||||
e.strings[0] = malloc(sizeof("+"));
|
|
||||||
strncpy(e.strings[0], "+", MAX_TOK_LEN);
|
|
||||||
Object o;
|
|
||||||
o.type = TYPE_FUNC;
|
|
||||||
o.forward = NULL;
|
|
||||||
o.func = &add;
|
|
||||||
e.objects[0] = o;
|
|
||||||
*/
|
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object parseEval(const char *input, struct Environment *env)
|
Object parseEval(const char *input, struct Environment *env)
|
||||||
{
|
{
|
||||||
struct Slice *tokens = tokenize(input);
|
struct Slice *tokens = nf_tokenize(input);
|
||||||
struct Slice *debug = tokens;
|
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
|
struct Slice *debug = tokens;
|
||||||
if(debug) {
|
if(debug) {
|
||||||
while(debug->text) {
|
while(debug->text) {
|
||||||
char tok[MAX_TOK_LEN];
|
char tok[MAX_TOK_LEN];
|
||||||
copySlice(tok, debug);
|
copySlice(tok, debug);
|
||||||
// printf("'%s', ", tok);
|
|
||||||
debug++;
|
debug++;
|
||||||
}
|
}
|
||||||
// printf("\n");
|
|
||||||
} else {
|
|
||||||
// printf("parse error\n");
|
|
||||||
}
|
}
|
||||||
// printf("parseEval() parse()\n");
|
|
||||||
#endif
|
#endif
|
||||||
Object parsed = parse(tokens).obj;
|
Object parsed = parse(tokens).obj;
|
||||||
free(tokens);
|
free(tokens);
|
||||||
|
@ -368,18 +335,17 @@ int repl(struct Environment *env)
|
||||||
fgets(input, 100, stdin);
|
fgets(input, 100, stdin);
|
||||||
Object obj = parseEval(input, env);
|
Object obj = parseEval(input, env);
|
||||||
printObj(&obj);
|
printObj(&obj);
|
||||||
//printf("eval: %d\n", obj.number);
|
//break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
struct Environment env = defaultEnv();
|
struct Environment env = defaultEnv();
|
||||||
if(1) {
|
#ifndef NO_REPL
|
||||||
repl(&env);
|
repl(&env);
|
||||||
} else {
|
#else
|
||||||
struct Slice *tokens = tokenize("(+ 10 5)");
|
struct Slice *tokens = nf_tokenize("(+ 10 5)");
|
||||||
struct Slice *debug = tokens;
|
struct Slice *debug = tokens;
|
||||||
|
|
||||||
if(debug) {
|
if(debug) {
|
||||||
|
@ -394,6 +360,8 @@ int main(void)
|
||||||
printf("parse error\n");
|
printf("parse error\n");
|
||||||
}
|
}
|
||||||
parse(tokens);
|
parse(tokens);
|
||||||
}
|
free(tokens);
|
||||||
|
#endif
|
||||||
|
deleteEnv(&env);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,54 +2,13 @@
|
||||||
#define PEBBLISP_H
|
#define PEBBLISP_H
|
||||||
|
|
||||||
// #define STANDALONE
|
// #define STANDALONE
|
||||||
|
// #define NO_REPL
|
||||||
|
|
||||||
#define MAX_TOK_LEN 4
|
#include "object.h"
|
||||||
#define MAX_TOK_CNT 128 // 128
|
|
||||||
#define MAX_ENV_ELM 15 // 50
|
|
||||||
|
|
||||||
// static const char* tokenFail = "Missing ')'\n";
|
|
||||||
|
|
||||||
typedef struct Object Object;
|
|
||||||
|
|
||||||
struct Slice {
|
struct Slice {
|
||||||
const char *text;
|
const char *text;
|
||||||
int length;
|
char length;
|
||||||
};
|
|
||||||
|
|
||||||
typedef enum Type {
|
|
||||||
TYPE_NUMBER,
|
|
||||||
TYPE_BOOL,
|
|
||||||
TYPE_LIST,
|
|
||||||
TYPE_FUNC,
|
|
||||||
//TYPE_STRING,
|
|
||||||
TYPE_SYMBOL,
|
|
||||||
//TYPE_CONS,
|
|
||||||
//TYPE_LAMBDA,
|
|
||||||
//TYPE_MACRO,
|
|
||||||
//TYPE_PRIMITIVE,
|
|
||||||
TYPE_ENV,
|
|
||||||
TYPE_ERROR
|
|
||||||
} Type;
|
|
||||||
|
|
||||||
struct Object {
|
|
||||||
Type type;
|
|
||||||
Object *forward;
|
|
||||||
union {
|
|
||||||
int number;
|
|
||||||
Object *list;
|
|
||||||
char name[MAX_TOK_LEN];
|
|
||||||
Object (*func)(Object, Object);
|
|
||||||
|
|
||||||
/*
|
|
||||||
struct { double number; }; // number
|
|
||||||
struct { char string[sizeof (Object *[3])]; }; // string, symbol
|
|
||||||
struct { Object *car, *cdr; }; // cons
|
|
||||||
struct { Object *params, *body, *env; }; // lambda, macro
|
|
||||||
struct { int primitive; char *name; }; // primitive
|
|
||||||
struct { Object *parent, *vars, *vals; }; // env
|
|
||||||
struct { Object *forward; }; // forwarding pointer
|
|
||||||
*/
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Result {
|
typedef struct Result {
|
||||||
|
@ -63,18 +22,22 @@ struct Environment {
|
||||||
};
|
};
|
||||||
|
|
||||||
Object eval(const Object *obj, struct Environment *env);
|
Object eval(const Object *obj, struct Environment *env);
|
||||||
char* stringObj(char *dest, const Object *obj);
|
|
||||||
Result parse(struct Slice *slices);
|
Result parse(struct Slice *slices);
|
||||||
Result readSeq(struct Slice *slices);
|
Result readSeq(struct Slice *slices);
|
||||||
Object parseAtom(struct Slice *slice);
|
Object parseAtom(struct Slice *slice);
|
||||||
void copySlice(char * dest, struct Slice *src);
|
void copySlice(char * dest, struct Slice *src);
|
||||||
Object parseEval(const char *input, struct Environment *env);
|
Object parseEval(const char *input, struct Environment *env);
|
||||||
struct Environment defaultEnv();
|
struct Environment defaultEnv();
|
||||||
void printObj(const Object *obj);
|
void deleteEnv(struct Environment *e);
|
||||||
|
void addToEnv(struct Environment *env, const char *name, const Object obj);
|
||||||
|
|
||||||
Result resultFromObjAndSlices(Object obj, struct Slice *slices);
|
Result resultFromObjAndSlices(Object obj, struct Slice *slices);
|
||||||
Object add(Object obj1, Object obj2);
|
Object add(Object obj1, Object obj2);
|
||||||
|
|
||||||
|
// Slices
|
||||||
|
void copySlice(char * dest, struct Slice *src);
|
||||||
|
void debugSlice(struct Slice *s);
|
||||||
|
|
||||||
#define R(_obj, _slices) resultFromObjAndSlices(_obj, _slices)
|
#define R(_obj, _slices) resultFromObjAndSlices(_obj, _slices)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
97
src/tags
97
src/tags
|
@ -4,79 +4,81 @@
|
||||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||||
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
||||||
END_PHRASE calc.h 6;" d
|
CALC_H calc.h 2;" d
|
||||||
|
CODE_PKEY calc.h 11;" d
|
||||||
|
END_PHRASE calc.h 9;" d
|
||||||
Environment pebblisp.h /^struct Environment {$/;" s
|
Environment pebblisp.h /^struct Environment {$/;" s
|
||||||
FIXED_MAX fixed.h /^static const fixed FIXED_MAX = INT_MAX;$/;" v
|
MAX_ENV_ELM object.h 6;" d
|
||||||
FIXED_SCALE fixed.h 40;" d
|
MAX_LENGTH calc.h 8;" d
|
||||||
MAX_ENV_ELM pebblisp.h 8;" d
|
MAX_TOK_CNT object.h 5;" d
|
||||||
MAX_LENGTH calc.h 5;" d
|
MAX_TOK_LEN object.h 4;" d
|
||||||
MAX_TOK_CNT pebblisp.h 7;" d
|
OBJECT_H object.h 2;" d
|
||||||
MAX_TOK_LEN pebblisp.h 6;" d
|
Object object.h /^struct Object {$/;" s
|
||||||
Object pebblisp.h /^struct Object {$/;" s
|
Object object.h /^typedef struct Object Object;$/;" t typeref:struct:Object
|
||||||
Object pebblisp.h /^typedef struct Object Object;$/;" t typeref:struct:Object
|
|
||||||
PEBBLISP_H pebblisp.h 2;" d
|
PEBBLISP_H pebblisp.h 2;" d
|
||||||
R pebblisp.h 78;" d
|
R pebblisp.h 41;" d
|
||||||
Result pebblisp.h /^typedef struct Result {$/;" s
|
Result pebblisp.h /^typedef struct Result {$/;" s
|
||||||
Result pebblisp.h /^} Result;$/;" t typeref:struct:Result
|
Result pebblisp.h /^} Result;$/;" t typeref:struct:Result
|
||||||
SMAX_LENGTH calc.h 4;" d
|
SMAX_LENGTH calc.h 7;" d
|
||||||
Slice pebblisp.h /^struct Slice {$/;" s
|
Slice pebblisp.h /^struct Slice {$/;" s
|
||||||
TOKENS_H tokens.h 2;" d
|
TOKENS_H tokens.h 2;" d
|
||||||
TOKEN_END calc.h 28;" d
|
TOKEN_END calc.h 42;" d
|
||||||
TYPE_BOOL pebblisp.h /^ TYPE_BOOL,$/;" e enum:Type
|
TYPE_BOOL object.h /^ TYPE_BOOL,$/;" e enum:Type
|
||||||
TYPE_ENV pebblisp.h /^ TYPE_ENV,$/;" e enum:Type
|
TYPE_ERROR object.h /^ TYPE_ERROR$/;" e enum:Type
|
||||||
TYPE_ERROR pebblisp.h /^ TYPE_ERROR$/;" e enum:Type
|
TYPE_FUNC object.h /^ TYPE_FUNC,$/;" e enum:Type
|
||||||
TYPE_FUNC pebblisp.h /^ TYPE_FUNC,$/;" e enum:Type
|
TYPE_LIST object.h /^ TYPE_LIST,$/;" e enum:Type
|
||||||
TYPE_LIST pebblisp.h /^ TYPE_LIST,$/;" e enum:Type
|
TYPE_NUMBER object.h /^ TYPE_NUMBER,$/;" e enum:Type
|
||||||
TYPE_NUMBER pebblisp.h /^ TYPE_NUMBER,$/;" e enum:Type
|
TYPE_SYMBOL object.h /^ TYPE_SYMBOL,$/;" e enum:Type
|
||||||
TYPE_SYMBOL pebblisp.h /^ TYPE_SYMBOL,$/;" e enum:Type
|
Type object.h /^typedef enum Type {$/;" g
|
||||||
Type pebblisp.h /^typedef enum Type {$/;" g
|
Type object.h /^} Type;$/;" t typeref:enum:Type
|
||||||
Type pebblisp.h /^} Type;$/;" t typeref:enum:Type
|
|
||||||
_h_FIXED_ fixed.h 26;" d
|
|
||||||
addFunc pebblisp.c /^void addFunc(const char *name, Object (*func)(Object, Object), $/;" f
|
addFunc pebblisp.c /^void addFunc(const char *name, Object (*func)(Object, Object), $/;" f
|
||||||
|
addToEnv pebblisp.c /^void addToEnv(struct Environment *env, const char *name, const Object obj)$/;" f
|
||||||
|
addToList object.c /^void addToList(Object *dest, const Object src)$/;" f
|
||||||
back_handler calc.c /^static void back_handler(ClickRecognizerRef recognizer, void *context) {$/;" f file:
|
back_handler calc.c /^static void back_handler(ClickRecognizerRef recognizer, void *context) {$/;" f file:
|
||||||
basicOp pebblisp.c /^Object basicOp(Object *obj1, Object *obj2, const char op)$/;" f
|
basicOp pebblisp.c /^Object basicOp(Object *obj1, Object *obj2, const char op)$/;" f
|
||||||
bopf pebblisp.c 257;" d file:
|
bopf pebblisp.c 264;" d file:
|
||||||
calculate calc.c /^static void calculate(){$/;" f file:
|
calculate calc.c /^static void calculate(){$/;" f file:
|
||||||
click_config_provider calc.c /^static void click_config_provider(void *context) {$/;" f file:
|
click_config_provider calc.c /^static void click_config_provider(void *context) {$/;" f file:
|
||||||
copySlice pebblisp.c /^void copySlice(char * dest, struct Slice *src)$/;" f
|
copySlice pebblisp.c /^void copySlice(char * dest, struct Slice *src)$/;" f
|
||||||
debugSlice pebblisp.c /^void debugSlice(struct Slice *s)$/;" f
|
debugSlice pebblisp.c /^void debugSlice(struct Slice *s)$/;" f
|
||||||
defaultEnv pebblisp.c /^struct Environment defaultEnv() {$/;" f
|
defaultEnv pebblisp.c /^struct Environment defaultEnv() {$/;" f
|
||||||
deinit calc.c /^static void deinit(void) {$/;" f file:
|
deinit calc.c /^static void deinit(void) {$/;" f file:
|
||||||
|
deleteEnv pebblisp.c /^void deleteEnv(struct Environment *e)$/;" f
|
||||||
|
deleteList object.c /^void deleteList(const Object *dest)$/;" f
|
||||||
enter calc.c /^static void enter(){$/;" f file:
|
enter calc.c /^static void enter(){$/;" f file:
|
||||||
env calc.c /^static struct Environment env;$/;" v typeref:struct:Environment file:
|
env calc.h /^static struct Environment env;$/;" v typeref:struct:Environment
|
||||||
eval pebblisp.c /^Object eval(const Object *obj, struct Environment *env)$/;" f
|
eval pebblisp.c /^Object eval(const Object *obj, struct Environment *env)$/;" f
|
||||||
evalBuiltIns pebblisp.c /^Object evalBuiltIns(const Object *first, const Object *rest, int *found,$/;" f
|
evalBuiltIns pebblisp.c /^Object evalBuiltIns(const Object *first, const Object *rest, int *found,$/;" f
|
||||||
evalIfArgs pebblisp.c /^Object evalIfArgs(const Object *first, const Object *rest, $/;" f
|
evalDefArgs pebblisp.c /^Object evalDefArgs(const Object *arg_forms, struct Environment *env)$/;" f
|
||||||
|
evalIfArgs pebblisp.c /^Object evalIfArgs(const Object *arg_forms, struct Environment *env)$/;" f
|
||||||
fetchFromEnvironment pebblisp.c /^Object fetchFromEnvironment(const char *name, struct Environment *env)$/;" f
|
fetchFromEnvironment pebblisp.c /^Object fetchFromEnvironment(const char *name, struct Environment *env)$/;" f
|
||||||
fixed fixed.h /^typedef int fixed;$/;" t
|
forward object.h /^ Object *forward;$/;" m struct:Object
|
||||||
fixed_add fixed.c /^fixed fixed_add(fixed lhs, fixed rhs, bool* overflow)$/;" f
|
func object.h /^ Object (*func)(Object, Object);$/;" m union:Object::__anon1
|
||||||
fixed_div fixed.c /^fixed fixed_div(fixed lhs, fixed rhs)$/;" f
|
getToken calc.c /^static inline char* getToken(int8_t n) {$/;" f file:
|
||||||
fixed_mult fixed.c /^fixed fixed_mult(fixed lhs, fixed rhs, bool* overflow)$/;" f
|
|
||||||
fixed_pow fixed.c /^fixed fixed_pow(fixed base, int exponent, bool* overflow)$/;" f
|
|
||||||
fixed_repr fixed.c /^char* fixed_repr(fixed fixed, char* buffer, size_t size)$/;" f
|
|
||||||
fixed_subt fixed.c /^fixed fixed_subt(fixed lhs, fixed rhs, bool* overflow)$/;" f
|
|
||||||
fixed_to_int fixed.c /^int fixed_to_int(fixed n)$/;" f
|
|
||||||
forward pebblisp.h /^ Object *forward;$/;" m struct:Object
|
|
||||||
func pebblisp.h /^ Object (*func)(Object, Object);$/;" m union:Object::__anon1
|
|
||||||
getToken calc.c /^static inline char* getToken(int n) {$/;" f file:
|
|
||||||
init calc.c /^static void init(void) {$/;" f file:
|
init calc.c /^static void init(void) {$/;" f file:
|
||||||
int_to_fixed fixed.c /^fixed int_to_fixed(int n)$/;" f
|
|
||||||
isDigit tokens.c /^int isDigit(const char c) {$/;" f
|
isDigit tokens.c /^int isDigit(const char c) {$/;" f
|
||||||
isSingle tokens.c /^int isSingle(const char c) {$/;" f
|
isSingle tokens.c /^int isSingle(const char c) {$/;" f
|
||||||
isWhitespace tokens.c /^int isWhitespace(const char c) {$/;" f
|
isWhitespace tokens.c /^int isWhitespace(const char c) {$/;" f
|
||||||
length pebblisp.h /^ int length;$/;" m struct:Slice
|
length pebblisp.h /^ char length;$/;" m struct:Slice
|
||||||
list pebblisp.h /^ Object *list;$/;" m union:Object::__anon1
|
list object.h /^ Object *list;$/;" m union:Object::__anon1
|
||||||
|
listLength object.c /^int listLength(const Object *listObj)$/;" f
|
||||||
|
listObject object.c /^inline Object listObject()$/;" f
|
||||||
main calc.c /^int main(void) {$/;" f
|
main calc.c /^int main(void) {$/;" f
|
||||||
main pebblisp.c /^int main(void)$/;" f
|
main pebblisp.c /^int main(void)$/;" f
|
||||||
mytext calc.h /^char mytext[SMAX_LENGTH] = "";$/;" v
|
mytext calc.h /^char mytext[SMAX_LENGTH] = "";$/;" v
|
||||||
name pebblisp.h /^ char name[MAX_TOK_LEN];$/;" m union:Object::__anon1
|
name object.h /^ char name[MAX_TOK_LEN];$/;" m union:Object::__anon1
|
||||||
number pebblisp.h /^ int number;$/;" m union:Object::__anon1
|
nf_tokenize tokens.c /^struct Slice *nf_tokenize(const char *input)$/;" f
|
||||||
|
notWhitespace tokens.c /^int notWhitespace(const char c) {$/;" f
|
||||||
|
number object.h /^ int number;$/;" m union:Object::__anon1
|
||||||
|
numberObject object.c /^inline Object numberObject(int num)$/;" f
|
||||||
obj pebblisp.h /^ Object obj;$/;" m struct:Result
|
obj pebblisp.h /^ Object obj;$/;" m struct:Result
|
||||||
objects pebblisp.h /^ Object *objects;$/;" m struct:Environment
|
objects pebblisp.h /^ Object *objects;$/;" m struct:Environment
|
||||||
parse pebblisp.c /^Result parse(struct Slice *slices)$/;" f
|
parse pebblisp.c /^Result parse(struct Slice *slices)$/;" f
|
||||||
parseAtom pebblisp.c /^Object parseAtom(struct Slice *s)$/;" f
|
parseAtom pebblisp.c /^Object parseAtom(struct Slice *s)$/;" f
|
||||||
parseEval pebblisp.c /^Object parseEval(const char *input, struct Environment *env)$/;" f
|
parseEval pebblisp.c /^Object parseEval(const char *input, struct Environment *env)$/;" f
|
||||||
printObj pebblisp.c /^void printObj(const Object *obj)$/;" f
|
printList object.c /^void printList(const Object *list)$/;" f
|
||||||
|
printObj object.c /^void printObj(const Object *obj)$/;" f
|
||||||
|
printf object.c 7;" d file:
|
||||||
printf pebblisp.c 8;" d file:
|
printf pebblisp.c 8;" d file:
|
||||||
printf tokens.c 7;" d file:
|
printf tokens.c 7;" d file:
|
||||||
readSeq pebblisp.c /^Result readSeq(struct Slice *tokens)$/;" f
|
readSeq pebblisp.c /^Result readSeq(struct Slice *tokens)$/;" f
|
||||||
|
@ -87,17 +89,16 @@ s_input_text_layer calc.h /^TextLayer *s_input_text_layer;$/;" v
|
||||||
s_result_text_layer calc.h /^TextLayer *s_result_text_layer;$/;" v
|
s_result_text_layer calc.h /^TextLayer *s_result_text_layer;$/;" v
|
||||||
s_window calc.h /^Window *s_window;$/;" v
|
s_window calc.h /^Window *s_window;$/;" v
|
||||||
select_handler calc.c /^static void select_handler(ClickRecognizerRef recognizer, void *context){$/;" f file:
|
select_handler calc.c /^static void select_handler(ClickRecognizerRef recognizer, void *context){$/;" f file:
|
||||||
selected_token calc.c /^static int8_t selected_token = 1; \/\/Currently selected button, starts on '5'$/;" v file:
|
selected_token calc.c /^static int8_t selected_token = 1;$/;" v file:
|
||||||
singleTokens tokens.c /^static const char singleTokens[] = "()+-*\/=";$/;" v file:
|
singleTokens tokens.c /^static const char singleTokens[] = "()+-*\/=";$/;" v file:
|
||||||
slices pebblisp.h /^ struct Slice *slices;$/;" m struct:Result typeref:struct:Result::Slice
|
slices pebblisp.h /^ struct Slice *slices;$/;" m struct:Result typeref:struct:Result::Slice
|
||||||
str_to_fixed fixed.c /^fixed str_to_fixed(const char* str, bool* overflow)$/;" f
|
stringObj object.c /^char* stringObj(char *dest, const Object *obj)$/;" f
|
||||||
str_to_int fixed.c /^int str_to_int(const char *str, char **endptr, int maxnum) {$/;" f
|
|
||||||
stringObj pebblisp.c /^char* stringObj(char *dest, const Object *obj)$/;" f
|
|
||||||
strings pebblisp.h /^ char **strings;$/;" m struct:Environment
|
strings pebblisp.h /^ char **strings;$/;" m struct:Environment
|
||||||
|
tail object.c /^Object *tail(const Object *listObj)$/;" f
|
||||||
temptext calc.h /^char temptext[SMAX_LENGTH] = "";$/;" v
|
temptext calc.h /^char temptext[SMAX_LENGTH] = "";$/;" v
|
||||||
text pebblisp.h /^ const char *text;$/;" m struct:Slice
|
text pebblisp.h /^ const char *text;$/;" m struct:Slice
|
||||||
tokenize tokens.c /^struct Slice *tokenize(const char *input)$/;" f
|
tokenCount calc.c /^static inline int8_t tokenCount() {$/;" f file:
|
||||||
tokens calc.h /^char *tokens[] = {$/;" v
|
tokens calc.h /^char *tokens[] = {$/;" v
|
||||||
type pebblisp.h /^ Type type;$/;" m struct:Object
|
type object.h /^ Type type;$/;" m struct:Object
|
||||||
up_down_handler calc.c /^static void up_down_handler(ClickRecognizerRef recognizer, void *context){$/;" f file:
|
up_down_handler calc.c /^static void up_down_handler(ClickRecognizerRef recognizer, void *context){$/;" f file:
|
||||||
updateText calc.c /^static void updateText()$/;" f file:
|
updateText calc.c /^static void updateText()$/;" f file:
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#ifdef STANDALONE
|
#ifdef STANDALONE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#else
|
#else
|
||||||
#define printf(...) tokenize(NULL)
|
#define printf(...) nf_tokenize(NULL)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -39,7 +39,8 @@ int notWhitespace(const char c) {
|
||||||
return !isWhitespace(c);
|
return !isWhitespace(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Slice *tokenize(const char *input)
|
// Return needs to be freed, if not null
|
||||||
|
struct Slice *nf_tokenize(const char *input)
|
||||||
{
|
{
|
||||||
if(!input)
|
if(!input)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -51,7 +52,7 @@ struct Slice *tokenize(const char *input)
|
||||||
|
|
||||||
int parens = 0;
|
int parens = 0;
|
||||||
while(input[i] != '\0') {
|
while(input[i] != '\0') {
|
||||||
printf("input: '%c'\n", input[i]);
|
//printf("input: '%c'\n", input[i]);
|
||||||
|
|
||||||
if(isWhitespace(input[i])) {
|
if(isWhitespace(input[i])) {
|
||||||
i++;
|
i++;
|
||||||
|
@ -77,6 +78,8 @@ struct Slice *tokenize(const char *input)
|
||||||
int l = 1;
|
int l = 1;
|
||||||
while(!isWhitespace(input[++i]) && !isSingle(input[i])) {
|
while(!isWhitespace(input[++i]) && !isSingle(input[i])) {
|
||||||
l++;
|
l++;
|
||||||
|
//slices[slice].length = l;
|
||||||
|
//debugSlice(&slices[slice]);
|
||||||
}
|
}
|
||||||
slices[slice].length = l;
|
slices[slice].length = l;
|
||||||
slice++;
|
slice++;
|
||||||
|
|
|
@ -4,6 +4,6 @@
|
||||||
#include "pebblisp.h"
|
#include "pebblisp.h"
|
||||||
int isSingle(const char c);
|
int isSingle(const char c);
|
||||||
int isDigit(const char c);
|
int isDigit(const char c);
|
||||||
struct Slice *tokenize(const char *input);
|
struct Slice *nf_tokenize(const char *input);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue