Initial Commit
This commit is contained in:
parent
f90ec20b6b
commit
7579d0b30c
|
@ -1,2 +1,6 @@
|
|||
# PebbleCalc
|
||||
A simple calculator app for the Pebble smartwatch
|
||||
Support addition, subtraction, multiplication, division and exponentiation.
|
||||
Supports up to 2 digits of decimals using fixed-point arithmetic.
|
||||
|
||||
Credit to Wojciech Siewierski for his fixed point arithmetic implementation. It was made for his [GravCalc](https://github.com/Vifon/GravCalc) Pebble app.
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"appKeys": {},
|
||||
"capabilities": [
|
||||
""
|
||||
],
|
||||
"companyName": "Michael E.",
|
||||
"enableMultiJS": true,
|
||||
"longName": "Calculator",
|
||||
"projectType": "native",
|
||||
"resources": {
|
||||
"media": [
|
||||
{
|
||||
"file": "images/appicon.png",
|
||||
"menuIcon": true,
|
||||
"name": "APP_ICON_IDENTIFIER",
|
||||
"targetPlatforms": null,
|
||||
"type": "png"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sdkVersion": "3",
|
||||
"shortName": "Calculator",
|
||||
"targetPlatforms": [
|
||||
"aplite",
|
||||
"basalt"
|
||||
],
|
||||
"uuid": "3a239ae0-adc5-4d40-b871-6fbcd8c37e7c",
|
||||
"versionLabel": "1.1",
|
||||
"watchapp": {
|
||||
"watchface": false
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 230 B |
|
@ -0,0 +1,163 @@
|
|||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "fixed.h"
|
||||
#include "calc.h"
|
||||
#include "pebblisp.h"
|
||||
|
||||
static inline char* getToken(int n) {
|
||||
const int length = sizeof(tokens) / sizeof(tokens[0]);
|
||||
return tokens[n % length];
|
||||
}
|
||||
|
||||
static int8_t selected_token = 1; //Currently selected button, starts on '5'
|
||||
|
||||
// static bool operator_entered = false; //Has the operator been entered yet
|
||||
// static bool num1_is_ans = false; //Is the previous result in num1? Used to allow further calculations on result.
|
||||
// static char num1[MAX_LENGTH] = ""; //First operand
|
||||
// static char num2[MAX_LENGTH] = ""; //Second operand
|
||||
// static char result_text[MAX_LENGTH] = ""; //Results text layer buffer string
|
||||
// static uint8_t operator = 0; //Operator, where 0 is +, 1 is -, 2 is *, 3 is /, 4 is ^
|
||||
static struct Environment env;
|
||||
|
||||
static void updateText()
|
||||
{
|
||||
strcpy(temptext, mytext);
|
||||
if(getToken(selected_token)[0] == ' ') {
|
||||
strcat(temptext, "_");
|
||||
} else {
|
||||
strcat(temptext, getToken(selected_token));
|
||||
}
|
||||
|
||||
text_layer_set_text(s_input_text_layer, temptext);
|
||||
}
|
||||
|
||||
//Up or Down button handler
|
||||
static void up_down_handler(ClickRecognizerRef recognizer, void *context){
|
||||
//Move selected button down if down is pressed, and up if up is pressed
|
||||
selected_token += (click_recognizer_get_button_id(recognizer) == BUTTON_ID_DOWN) ? 1 : -1;
|
||||
//If selected button is outside button range, wrap around
|
||||
selected_token = selected_token < 0 ? TOKEN_END : selected_token > TOKEN_END ? 0 : selected_token;
|
||||
|
||||
updateText();
|
||||
}
|
||||
|
||||
// Adds the current string to the main string
|
||||
static void enter(){
|
||||
strcat(mytext, getToken(selected_token));
|
||||
selected_token = 0;
|
||||
updateText();
|
||||
}
|
||||
|
||||
// // Backspace. Clears whole number if full is true
|
||||
// static void clear(bool full){
|
||||
// char *num = operator_entered ? num2 : num1; //Create a pointer to the currently edited number
|
||||
// if(full)
|
||||
// *num = 0;
|
||||
// else
|
||||
// num[strlen(num)-1] = 0;
|
||||
// text_layer_set_text(s_input_text_layer, num);
|
||||
// }
|
||||
|
||||
//Calculate result, display it and reset
|
||||
static void calculate(){
|
||||
// Object obj = parseEval(mytext, &env);
|
||||
// snprintf(mytext, MAX_LENGTH, "R:%d", obj.number);
|
||||
// selected_token = 0;
|
||||
strcpy(mytext, "heythere");
|
||||
updateText();
|
||||
if(1)
|
||||
return;
|
||||
|
||||
/*
|
||||
bool overflow = false; //Overflow flag
|
||||
// Convert operands to numbers
|
||||
fixed lhs = str_to_fixed(num1, &overflow);
|
||||
fixed rhs = str_to_fixed(num2, &overflow);
|
||||
fixed result = 0;
|
||||
//Calculate the result
|
||||
switch(operator){
|
||||
case 0:
|
||||
result = fixed_add(lhs, rhs, &overflow);
|
||||
break;
|
||||
case 1:
|
||||
result = fixed_subt(lhs, rhs, &overflow);
|
||||
break;
|
||||
case 2:
|
||||
result = fixed_mult(lhs, rhs, &overflow);
|
||||
break;
|
||||
case 3:
|
||||
result = fixed_div(lhs, rhs);
|
||||
break;
|
||||
case 4:
|
||||
result = fixed_pow(lhs, fixed_to_int(rhs), &overflow); //Exponent must be an int
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
}
|
||||
|
||||
APP_LOG(APP_LOG_LEVEL_DEBUG, "num1: %d num2: %d result: %d", lhs, rhs, result);
|
||||
|
||||
//Reset operands, operator_entered and entering_decimal
|
||||
*num1 = 0;
|
||||
*num2 = 0;
|
||||
operator_entered = false;
|
||||
|
||||
if(overflow){
|
||||
text_layer_set_text(s_input_text_layer, "Overflow Error"); //Display message on overflow
|
||||
}
|
||||
else{
|
||||
fixed_repr(result, result_text, MAX_LENGTH); //Convert result to string
|
||||
text_layer_set_text(s_input_text_layer, result_text); //Display result
|
||||
strcpy(num1, result_text); //Copy result into num1
|
||||
num1_is_ans = true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Button press handler
|
||||
static void select_handler(ClickRecognizerRef recognizer, void *context){
|
||||
if(selected_token == sizeof(tokens) / sizeof(tokens[0]) - 1)
|
||||
calculate();
|
||||
else
|
||||
enter();
|
||||
}
|
||||
|
||||
static void click_config_provider(void *context) {
|
||||
// Register click handlers
|
||||
window_single_repeating_click_subscribe(BUTTON_ID_UP, 100, up_down_handler);
|
||||
window_single_repeating_click_subscribe(BUTTON_ID_DOWN, 100, up_down_handler);
|
||||
window_single_click_subscribe(BUTTON_ID_SELECT, select_handler);
|
||||
}
|
||||
|
||||
static void init(void) {
|
||||
// Create a window and get information about the window
|
||||
s_window = window_create();
|
||||
Layer *window_layer = window_get_root_layer(s_window);
|
||||
// Register click config provider
|
||||
window_set_click_config_provider(s_window, click_config_provider);
|
||||
|
||||
// Input text layer setup
|
||||
GRect text_bounds = GRect(6, 6, 132, 132);
|
||||
s_input_text_layer = text_layer_create(text_bounds);
|
||||
text_layer_set_text(s_input_text_layer, getToken(1));
|
||||
text_layer_set_font(s_input_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD));
|
||||
layer_add_child(window_get_root_layer(s_window), text_layer_get_layer(s_input_text_layer));
|
||||
|
||||
// Push the window, setting the window animation to 'true'
|
||||
window_stack_push(s_window, true);
|
||||
env = defaultEnv();
|
||||
}
|
||||
|
||||
static void deinit(void) {
|
||||
// Destroy the text layer
|
||||
text_layer_destroy(s_input_text_layer);
|
||||
|
||||
// Destroy the window
|
||||
window_destroy(s_window);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
init();
|
||||
app_event_loop();
|
||||
deinit();
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
#include <pebble.h>
|
||||
#include "pebblisp.h"
|
||||
|
||||
#define SMAX_LENGTH 256
|
||||
#define MAX_LENGTH 11
|
||||
#define END_PHRASE "END"
|
||||
|
||||
// Layers
|
||||
Window *s_window;
|
||||
TextLayer *s_input_text_layer;
|
||||
|
||||
char mytext[SMAX_LENGTH] = "";
|
||||
char temptext[SMAX_LENGTH] = "";
|
||||
|
||||
char *tokens[] = {
|
||||
" ", "(", ")",
|
||||
"+", "-", "*", "/",
|
||||
"1","2","3",
|
||||
"4","5","6",
|
||||
"7","8","9", "0",
|
||||
END_PHRASE
|
||||
};
|
||||
|
||||
#define TOKEN_END 17
|
|
@ -0,0 +1,299 @@
|
|||
/** @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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/** @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
|
|
@ -0,0 +1,288 @@
|
|||
#include "pebblisp.h"
|
||||
#include "tokens.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef STANDALONE
|
||||
#define printf(...) copySlice(NULL, NULL)
|
||||
#else
|
||||
#endif
|
||||
|
||||
void copySlice(char * dest, struct Slice *src)
|
||||
{
|
||||
if(!dest || !src)
|
||||
return;
|
||||
strncpy(dest, src->text, src->length);
|
||||
dest[src->length] = '\0';
|
||||
}
|
||||
|
||||
void debugSlice(struct Slice *s)
|
||||
{
|
||||
//printf("Debug Slice\n text:'");
|
||||
for(int i = 0; i < s->length; i++) {
|
||||
//printf("%c", s->text[i]);
|
||||
}
|
||||
// printf("'\n");
|
||||
// printf(" length: %d\n", s->length);
|
||||
}
|
||||
|
||||
Object fetchFromEnvironment(const char *name, struct Environment *env)
|
||||
{
|
||||
int i = 0;
|
||||
const char *next = env->strings[i];
|
||||
while(next != NULL) {
|
||||
// printf("fetching '%s' against '%s'\n", name, next);
|
||||
if(strcmp(name, next) == 0) {
|
||||
return env->objects[i];
|
||||
}
|
||||
next = env->strings[++i];
|
||||
}
|
||||
printf("DID NOT FIND SYMBOL\n");
|
||||
Object o;
|
||||
o.type = TYPE_ERROR;
|
||||
return o;
|
||||
}
|
||||
|
||||
Result parse(struct Slice *slices)
|
||||
{
|
||||
// printf("parse()\n");
|
||||
struct Slice *token = slices;
|
||||
struct Slice *rest;
|
||||
if(token->text != NULL) {
|
||||
rest = &slices[1];
|
||||
} else {
|
||||
// printf("Assigning null...\n");
|
||||
rest = NULL;
|
||||
}
|
||||
|
||||
if(token->text[0] == '(') {
|
||||
// todo check for null rest
|
||||
return readSeq(rest);
|
||||
} else { // todo error on closed paren
|
||||
return R(parseAtom(token), rest);
|
||||
}
|
||||
}
|
||||
|
||||
Result readSeq(struct Slice *tokens)
|
||||
{
|
||||
// printf("readSeq()\n");
|
||||
Object res;
|
||||
res.forward = NULL;
|
||||
res.type = TYPE_LIST;
|
||||
//res.list = malloc(sizeof(Object));
|
||||
|
||||
Object *march = &res;
|
||||
for(;;) {
|
||||
struct Slice *next = &tokens[0];
|
||||
struct Slice *rest = next->text? &next[1] : NULL;
|
||||
if(next->text[0] == ')') {
|
||||
return R(res, rest);
|
||||
}
|
||||
Result r = parse(tokens);
|
||||
march->forward = malloc(sizeof(Object));
|
||||
*march->forward = r.obj;
|
||||
// char out[MAX_TOK_LEN];
|
||||
// printf("stringObj: %s\n", stringObj(out, &r.obj));
|
||||
tokens = r.slices;
|
||||
march = march->forward;
|
||||
}
|
||||
}
|
||||
|
||||
Object parseAtom(struct Slice *s)
|
||||
{
|
||||
// printf("parseAtom()\n");
|
||||
Object o;
|
||||
o.forward = NULL;
|
||||
if(isDigit(s->text[0])) {
|
||||
o.type = TYPE_NUMBER;
|
||||
o.number = 0;
|
||||
for(int i = 0; i < s->length; i++) {
|
||||
o.number *= 10;
|
||||
o.number += s->text[i] - '0';
|
||||
}
|
||||
|
||||
} else {
|
||||
o.type = TYPE_SYMBOL;
|
||||
copySlice(o.name, s);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
Object eval(Object *obj, struct Environment *env)
|
||||
{
|
||||
Object o = *obj;
|
||||
switch(obj->type) {
|
||||
case TYPE_NUMBER:
|
||||
{
|
||||
return *obj;
|
||||
}
|
||||
case TYPE_LIST:
|
||||
{
|
||||
// printf("TYPE_LIST\n");
|
||||
Object first_form = *obj->forward;
|
||||
Object first_eval = eval(&first_form, env);
|
||||
return first_eval.func(*first_form.forward, *first_form.forward->forward);
|
||||
}
|
||||
case TYPE_SYMBOL:
|
||||
{
|
||||
return fetchFromEnvironment(obj->name, env);
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
char* stringObj(char *dest, Object *obj)
|
||||
{
|
||||
if(obj->type == TYPE_NUMBER) {
|
||||
snprintf(dest, MAX_TOK_LEN, "%d", obj->number);
|
||||
} else if(obj->type == TYPE_SYMBOL) {
|
||||
return obj->name;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
Result resultFromObjAndSlices(Object obj, struct Slice *slices)
|
||||
{
|
||||
Result r;
|
||||
r.obj = obj;
|
||||
r.slices = slices;
|
||||
return r;
|
||||
}
|
||||
|
||||
Object basicOp(Object *obj1, Object *obj2, const char op)
|
||||
{
|
||||
Object o;
|
||||
o.forward = NULL;
|
||||
o.type = TYPE_NUMBER;
|
||||
switch(op){
|
||||
case '+':
|
||||
o.number = obj1->number + obj2->number;
|
||||
break;
|
||||
case '-':
|
||||
o.number = obj1->number - obj2->number;
|
||||
break;
|
||||
case '*':
|
||||
o.number = obj1->number * obj2->number;
|
||||
break;
|
||||
case '/':
|
||||
o.number = obj1->number / obj2->number;
|
||||
break;
|
||||
default:
|
||||
o = *obj1;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
Object add(Object obj1, Object obj2)
|
||||
{ return basicOp(&obj1, &obj2, '+'); }
|
||||
|
||||
Object sub(Object obj1, Object obj2)
|
||||
{ return basicOp(&obj1, &obj2, '-'); }
|
||||
|
||||
Object mul(Object obj1, Object obj2)
|
||||
{ return basicOp(&obj1, &obj2, '*'); }
|
||||
|
||||
Object divi(Object obj1, Object obj2)
|
||||
{ return basicOp(&obj1, &obj2, '/'); }
|
||||
|
||||
void addFunc(const char *name, Object (*func)(Object, Object),
|
||||
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;
|
||||
o.type = TYPE_FUNC;
|
||||
o.forward = NULL;
|
||||
o.func = func;
|
||||
env->objects[i] = o;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Environment defaultEnv() {
|
||||
struct Environment e;
|
||||
e.strings = malloc(sizeof(char*) * MAX_ENV_ELM);
|
||||
e.objects = malloc(sizeof(Object) * MAX_ENV_ELM);
|
||||
addFunc("+", &add, &e);
|
||||
addFunc("-", &sub, &e);
|
||||
addFunc("*", &mul, &e);
|
||||
addFunc("/", &divi, &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;
|
||||
}
|
||||
|
||||
Object parseEval(const char *input, struct Environment *env)
|
||||
{
|
||||
struct Slice *tokens = tokenize(input);
|
||||
struct Slice *debug = tokens;
|
||||
if(debug) {
|
||||
while(debug->text) {
|
||||
char tok[10];
|
||||
copySlice(tok, debug);
|
||||
// printf("'%s', ", tok);
|
||||
debug++;
|
||||
}
|
||||
// printf("\n");
|
||||
} else {
|
||||
// printf("parse error\n");
|
||||
}
|
||||
// printf("parseEval() parse()\n");
|
||||
Object parsed = parse(tokens).obj;
|
||||
return eval(&parsed, env);
|
||||
}
|
||||
|
||||
#ifdef STANDALONE
|
||||
int repl(struct Environment *env)
|
||||
{
|
||||
char input[100] = "";
|
||||
while(input[0] != 'q') {
|
||||
printf("pebblisp>> ");
|
||||
fgets(input, 100, stdin);
|
||||
Object obj = parseEval(input, env);
|
||||
printf("eval: %d\n", obj.number);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct Environment env = defaultEnv();
|
||||
if(1) {
|
||||
repl(&env);
|
||||
} else {
|
||||
struct Slice *tokens = tokenize("(+ 10 5)");
|
||||
struct Slice *debug = tokens;
|
||||
|
||||
if(debug) {
|
||||
while(debug->text) {
|
||||
char tok[10];
|
||||
copySlice(tok, debug);
|
||||
printf("'%s', ", tok);
|
||||
debug++;
|
||||
}
|
||||
printf("\n");
|
||||
} else {
|
||||
printf("parse error\n");
|
||||
}
|
||||
parse(tokens);
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,78 @@
|
|||
#ifndef PEBBLISP_H
|
||||
#define PEBBLISP_H
|
||||
|
||||
// #define STANDALONE
|
||||
|
||||
#define MAX_TOK_LEN 6
|
||||
#define MAX_TOK_CNT 128
|
||||
#define MAX_ENV_ELM 50
|
||||
|
||||
// static const char* tokenFail = "Missing ')'\n";
|
||||
|
||||
typedef struct Object Object;
|
||||
|
||||
struct Slice {
|
||||
const char *text;
|
||||
int length;
|
||||
};
|
||||
|
||||
typedef enum Type {
|
||||
TYPE_NUMBER,
|
||||
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 {
|
||||
Object obj;
|
||||
struct Slice *slices;
|
||||
} Result;
|
||||
|
||||
struct Environment {
|
||||
char **strings;
|
||||
Object *objects;
|
||||
};
|
||||
|
||||
Object eval(Object *obj, struct Environment *env);
|
||||
char* stringObj(char *dest, Object *obj);
|
||||
Result parse(struct Slice *slices);
|
||||
Result readSeq(struct Slice *slices);
|
||||
Object parseAtom(struct Slice *slice);
|
||||
void copySlice(char * dest, struct Slice *src);
|
||||
Object parseEval(const char *input, struct Environment *env);
|
||||
struct Environment defaultEnv();
|
||||
|
||||
Result resultFromObjAndSlices(Object obj, struct Slice *slices);
|
||||
Object add(Object obj1, Object obj2);
|
||||
|
||||
#define R(_obj, _slices) resultFromObjAndSlices(_obj, _slices)
|
||||
|
||||
#endif
|
|
@ -0,0 +1,98 @@
|
|||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.9~svn20110310 //
|
||||
END_PHRASE calc.h 6;" d
|
||||
Environment pebblisp.h /^struct Environment {$/;" s
|
||||
FIXED_MAX fixed.h /^static const fixed FIXED_MAX = INT_MAX;$/;" v
|
||||
FIXED_SCALE fixed.h 40;" d
|
||||
MAX_ENV_ELM pebblisp.h 8;" d
|
||||
MAX_LENGTH calc.h 5;" d
|
||||
MAX_TOK_CNT pebblisp.h 7;" d
|
||||
MAX_TOK_LEN pebblisp.h 6;" d
|
||||
Object pebblisp.h /^struct Object {$/;" s
|
||||
Object pebblisp.h /^typedef struct Object Object;$/;" t typeref:struct:Object
|
||||
PEBBLISP_H pebblisp.h 2;" d
|
||||
R pebblisp.h 74;" d
|
||||
Result pebblisp.h /^typedef struct Result {$/;" s
|
||||
Result pebblisp.h /^} Result;$/;" t typeref:struct:Result
|
||||
SMAX_LENGTH calc.h 4;" d
|
||||
STANDALONE pebblisp.h 4;" d
|
||||
Slice pebblisp.h /^struct Slice {$/;" s
|
||||
TOKENS_H tokens.h 2;" d
|
||||
TYPE_ENV pebblisp.h /^ TYPE_ENV,$/;" e enum:Type
|
||||
TYPE_ERROR pebblisp.h /^ TYPE_ERROR$/;" e enum:Type
|
||||
TYPE_FUNC pebblisp.h /^ TYPE_FUNC,$/;" e enum:Type
|
||||
TYPE_LIST pebblisp.h /^ TYPE_LIST,$/;" e enum:Type
|
||||
TYPE_NUMBER pebblisp.h /^ TYPE_NUMBER,$/;" e enum:Type
|
||||
TYPE_SYMBOL pebblisp.h /^ TYPE_SYMBOL,$/;" e enum:Type
|
||||
Type pebblisp.h /^typedef enum Type {$/;" g
|
||||
Type pebblisp.h /^} Type;$/;" t typeref:enum:Type
|
||||
_h_FIXED_ fixed.h 26;" d
|
||||
add pebblisp.c /^Object add(Object obj1, Object obj2)$/;" f
|
||||
calculate calc.c /^static void calculate(){$/;" f file:
|
||||
clear calc.c /^static void clear(bool full){$/;" 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
|
||||
debugSlice pebblisp.c /^void debugSlice(struct Slice *s)$/;" f
|
||||
defaultEnv pebblisp.c /^struct Environment defaultEnv() {$/;" f
|
||||
deinit calc.c /^static void deinit(void) {$/;" f file:
|
||||
enter calc.c /^static void enter(){$/;" f file:
|
||||
eval pebblisp.c /^Object eval(Object *obj, struct Environment *env)$/;" f
|
||||
fixed fixed.h /^typedef int fixed;$/;" t
|
||||
fixed_add fixed.c /^fixed fixed_add(fixed lhs, fixed rhs, bool* overflow)$/;" f
|
||||
fixed_div fixed.c /^fixed fixed_div(fixed lhs, fixed rhs)$/;" f
|
||||
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:
|
||||
int_to_fixed fixed.c /^fixed int_to_fixed(int n)$/;" f
|
||||
isDigit tokens.c /^int isDigit(const char c) {$/;" f
|
||||
isSingle tokens.c /^int isSingle(const char c) {$/;" f
|
||||
length pebblisp.h /^ int length;$/;" m struct:Slice
|
||||
list pebblisp.h /^ Object *list;$/;" m union:Object::__anon1
|
||||
main calc.c /^int main(void) {$/;" f
|
||||
main pebblisp.c /^int main(void)$/;" f
|
||||
mytext calc.h /^char mytext[SMAX_LENGTH] = "";$/;" v
|
||||
name pebblisp.h /^ char name[MAX_TOK_LEN];$/;" m union:Object::__anon1
|
||||
num1 calc.c /^static char num1[MAX_LENGTH] = ""; \/\/First operand$/;" v file:
|
||||
num1_is_ans calc.c /^static bool num1_is_ans = false; \/\/Is the previous result in num1? Used to allow further calculations on result.$/;" v file:
|
||||
num2 calc.c /^static char num2[MAX_LENGTH] = ""; \/\/Second operand$/;" v file:
|
||||
number pebblisp.h /^ int number;$/;" m union:Object::__anon1
|
||||
obj pebblisp.h /^ Object obj;$/;" m struct:Result
|
||||
objects pebblisp.h /^ Object *objects;$/;" m struct:Environment
|
||||
operator calc.c /^static uint8_t operator = 0; \/\/Operator, where 0 is +, 1 is -, 2 is *, 3 is \/, 4 is ^$/;" v file:
|
||||
operator_entered calc.c /^static bool operator_entered = false; \/\/Has the operator been entered yet$/;" v file:
|
||||
parse pebblisp.c /^Result parse(struct Slice *slices)$/;" f
|
||||
parseAtom pebblisp.c /^Object parseAtom(struct Slice *s)$/;" f
|
||||
parseEval pebblisp.c /^Object parseEval(const char *input, struct Environment *env)$/;" f
|
||||
printf pebblisp.c 7;" d file:
|
||||
readSeq pebblisp.c /^Result readSeq(struct Slice *tokens)$/;" f
|
||||
repl pebblisp.c /^int repl(struct Environment *env)$/;" f
|
||||
resultFromObjAndSlices pebblisp.c /^Result resultFromObjAndSlices(Object obj, struct Slice *slices)$/;" f
|
||||
result_text calc.c /^static char result_text[MAX_LENGTH] = ""; \/\/Results text layer buffer string$/;" v file:
|
||||
s_input_text_layer calc.h /^TextLayer *s_input_text_layer;$/;" v
|
||||
s_window calc.h /^Window *s_window;$/;" v
|
||||
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:
|
||||
singleTokens tokens.c /^static const char singleTokens[] = "()+-*\/";$/;" v file:
|
||||
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
|
||||
str_to_int fixed.c /^int str_to_int(const char *str, char **endptr, int maxnum) {$/;" f
|
||||
stringObj pebblisp.c /^char* stringObj(char *dest, Object *obj)$/;" f
|
||||
strings pebblisp.h /^ char **strings;$/;" m struct:Environment
|
||||
temptext calc.h /^char temptext[SMAX_LENGTH] = "";$/;" v
|
||||
text pebblisp.h /^ const char *text;$/;" m struct:Slice
|
||||
tokenFail pebblisp.h /^static const char* tokenFail = "Missing ')'\\n";$/;" v
|
||||
tokenize tokens.c /^struct Slice *tokenize(const char *input)$/;" f
|
||||
tokens calc.h /^char *tokens[] = {$/;" v
|
||||
type pebblisp.h /^ Type type;$/;" m struct:Object
|
||||
up_down_handler calc.c /^static void up_down_handler(ClickRecognizerRef recognizer, void *context){$/;" f file:
|
||||
updateText calc.c /^static void updateText()$/;" f file:
|
|
@ -0,0 +1,83 @@
|
|||
#include "tokens.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef STANDALONE
|
||||
#include <stdio.h>
|
||||
#else
|
||||
#define printf(...) tokenize(NULL)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Grammar:
|
||||
* token
|
||||
* expr
|
||||
* (op expr expr)
|
||||
* (list expr expr ... )
|
||||
*/
|
||||
|
||||
// Is the char a standalone token?
|
||||
static const char singleTokens[] = "()+-*/";
|
||||
int isSingle(const char c) {
|
||||
int i = 0;
|
||||
while(singleTokens[i] != '\0'){
|
||||
if(singleTokens[i] == c)
|
||||
return singleTokens[i];
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int isDigit(const char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
struct Slice *tokenize(const char *input)
|
||||
{
|
||||
if(!input)
|
||||
return NULL;
|
||||
|
||||
struct Slice *slices = malloc(sizeof(struct Slice) * MAX_TOK_CNT);
|
||||
|
||||
int i = 0;
|
||||
int slice = 0;
|
||||
|
||||
int parens = 0;
|
||||
while(input[i] != '\0') {
|
||||
printf("input: '%c'\n", input[i]);
|
||||
if(input[i] == '(') {
|
||||
parens++;
|
||||
} else if (input[i] == ')') {
|
||||
parens--;
|
||||
}
|
||||
|
||||
if(isSingle(input[i])) {
|
||||
slices[slice].text = &input[i];
|
||||
slices[slice].length = 1;
|
||||
slice++;
|
||||
i++;
|
||||
|
||||
} else if(isDigit(input[i])) {
|
||||
slices[slice].text = &input[i];
|
||||
|
||||
int l = 1;
|
||||
while(isDigit(input[++i]))
|
||||
l++;
|
||||
|
||||
slices[slice].length = l;
|
||||
slice++;
|
||||
|
||||
} else { // Whitespace or other uncaught
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if(parens){
|
||||
free(slices);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
slices[slice].text = NULL;
|
||||
slices[slice].length = 0;
|
||||
|
||||
return slices;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef TOKENS_H
|
||||
#define TOKENS_H
|
||||
|
||||
#include "pebblisp.h"
|
||||
int isSingle(const char c);
|
||||
int isDigit(const char c);
|
||||
struct Slice *tokenize(const char *input);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,41 @@
|
|||
#
|
||||
# This file is the default set of rules to compile a Pebble project.
|
||||
#
|
||||
# Feel free to customize this to your needs.
|
||||
#
|
||||
|
||||
import os.path
|
||||
|
||||
top = '.'
|
||||
out = 'build'
|
||||
|
||||
|
||||
def options(ctx):
|
||||
ctx.load('pebble_sdk')
|
||||
|
||||
|
||||
def configure(ctx):
|
||||
ctx.load('pebble_sdk')
|
||||
|
||||
|
||||
def build(ctx):
|
||||
ctx.load('pebble_sdk')
|
||||
|
||||
build_worker = os.path.exists('worker_src')
|
||||
binaries = []
|
||||
|
||||
for p in ctx.env.TARGET_PLATFORMS:
|
||||
ctx.set_env(ctx.all_envs[p])
|
||||
ctx.set_group(ctx.env.PLATFORM_NAME)
|
||||
app_elf = '{}/pebble-app.elf'.format(ctx.env.BUILD_DIR)
|
||||
ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'), target=app_elf)
|
||||
|
||||
if build_worker:
|
||||
worker_elf = '{}/pebble-worker.elf'.format(ctx.env.BUILD_DIR)
|
||||
binaries.append({'platform': p, 'app_elf': app_elf, 'worker_elf': worker_elf})
|
||||
ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/**/*.c'), target=worker_elf)
|
||||
else:
|
||||
binaries.append({'platform': p, 'app_elf': app_elf})
|
||||
|
||||
ctx.set_group('bundle')
|
||||
ctx.pbl_bundle(binaries=binaries, js=ctx.path.ant_glob('src/js/**/*.js'), js_entry_file='src/js/app.js')
|
Loading…
Reference in New Issue