tcctok.h: - Add __has_include_next tccpp.c: - New functions parse_include and get_include_file - Changed expr_preprocess and preprocess
Unified · Split
| @@ -1494,8 +1494,98 @@ static void maybe_run_test(TCCState *s) · 1493 unmodified lines | |||
| 1494 | define_push(tok, MACRO_OBJ, NULL, NULL); | 1494 | define_push(tok, MACRO_OBJ, NULL, NULL); |
| 1495 | } | 1495 | } |
| 1496 | 1496 | ||
| 1497 | static int parse_include(char *buf, size_t size_buf, int last) | ||
| 1498 | { | ||
| 1499 | int c; | ||
| 1500 | |||
| 1501 | skip_spaces(); | ||
| 1502 | if (ch == '<') { | ||
| 1503 | c = '>'; | ||
| 1504 | goto read_name; | ||
| 1505 | } else if (ch == '\"') { | ||
| 1506 | char *q; | ||
| 1507 | |||
| 1508 | c = ch; | ||
| 1509 | read_name: | ||
| 1510 | inp(); | ||
| 1511 | q = buf; | ||
| 1512 | while (ch != c && ch != '\n' && ch != CH_EOF) { | ||
| 1513 | if ((q - buf) < size_buf - 1) | ||
| 1514 | *q++ = ch; | ||
| 1515 | if (ch == '\\') { | ||
| 1516 | if (handle_stray_noerror() == 0) | ||
| 1517 | --q; | ||
| 1518 | } else | ||
| 1519 | inp(); | ||
| 1520 | } | ||
| 1521 | if (ch != c) | ||
| 1522 | goto error; | ||
| 1523 | *q = '\0'; | ||
| 1524 | minp(); | ||
| 1525 | #if 0 | ||
| 1526 | /* eat all spaces and comments after include */ | ||
| 1527 | /* XXX: slightly incorrect */ | ||
| 1528 | while (ch1 != '\n' && ch1 != CH_EOF) | ||
| 1529 | inp(); | ||
| 1530 | #endif | ||
| 1531 | } else { | ||
| 1532 | int len; | ||
| 1533 | /* computed #include : concatenate everything up to linefeed, | ||
| 1534 | the result must be one of the two accepted forms. | ||
| 1535 | Don't convert pp-tokens to tokens here. */ | ||
| 1536 | parse_flags = (PARSE_FLAG_PREPROCESS | ||
| 1537 | | PARSE_FLAG_LINEFEED | ||
| 1538 | | (parse_flags & PARSE_FLAG_ASM_FILE)); | ||
| 1539 | next(); | ||
| 1540 | buf[0] = '\0'; | ||
| 1541 | while (tok != TOK_LINEFEED && tok != last) { | ||
| 1542 | pstrcat(buf, size_buf, get_tok_str(tok, &tokc)); | ||
| 1543 | next(); | ||
| 1544 | } | ||
| 1545 | len = strlen(buf); | ||
| 1546 | if (tok == last) | ||
| 1547 | unget_tok(0); | ||
| 1548 | /* check syntax and remove '<>|""' */ | ||
| 1549 | if ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') && | ||
| 1550 | (buf[0] != '<' || buf[len-1] != '>')))) | ||
| 1551 | error: | ||
| 1552 | tcc_error("'#include' expects \"FILENAME\" or <FILENAME>"); | ||
| 1553 | c = buf[len-1]; | ||
| 1554 | memmove(buf, buf + 1, len - 2); | ||
| 1555 | buf[len - 2] = '\0'; | ||
| 1556 | } | ||
| 1557 | return c; | ||
| 1558 | } | ||
| 1559 | |||
| 1560 | static int get_include_file(TCCState *s1, int i, int c, | ||
| 1561 | char *buf, char *buf1, size_t size_buf1) | ||
| 1562 | { | ||
| 1563 | const char *path; | ||
| 1564 | |||
| 1565 | if (i == 0) { | ||
| 1566 | /* check absolute include path */ | ||
| 1567 | if (!IS_ABSPATH(buf)) | ||
| 1568 | return -1; | ||
| 1569 | buf1[0] = 0; | ||
| 1570 | } else if (i == 1) { | ||
| 1571 | /* search in file's dir if "header.h" */ | ||
| 1572 | if (c != '\"') | ||
| 1573 | return -1; | ||
| 1574 | path = file->true_filename; | ||
| 1575 | pstrncpy(buf1, path, tcc_basename(path) - path); | ||
| 1576 | } else { | ||
| 1577 | /* search in all the include paths */ | ||
| 1578 | int j = i - 2, k = j - s1->nb_include_paths; | ||
| 1579 | path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k]; | ||
| 1580 | pstrcpy(buf1, size_buf1, path); | ||
| 1581 | pstrcat(buf1, size_buf1, "/"); | ||
| 1582 | } | ||
| 1583 | pstrcat(buf1, size_buf1, buf); | ||
| 1584 | return 0; | ||
| 1585 | } | ||
| 1586 | |||
| 1497 | /* eval an expression for #if/#elif */ | 1587 | /* eval an expression for #if/#elif */ |
| 1498 | static int expr_preprocess(void) | 1588 | static int expr_preprocess(TCCState *s1) |
| 1499 | { | 1589 | { |
| 1500 | int c, t; | 1590 | int c, t; |
| 1501 | TokenString *str; | 1591 | TokenString *str; |
| @@ -1510,11 +1600,15 @@ static int expr_preprocess(void) · 8 unmodified lines | |||
| 1510 | t = tok; | 1600 | t = tok; |
| 1511 | if (t == '(') | 1601 | if (t == '(') |
| 1512 | next_nomacro(); | 1602 | next_nomacro(); |
| 1513 | if (tok < TOK_IDENT) | 1603 | if (tok == TOK___HAS_INCLUDE || tok == TOK___HAS_INCLUDE_NEXT) |
| 1514 | expect("identifier"); | 1604 | c = 1; |
| 1515 | if (tcc_state->run_test) | 1605 | else { |
| 1516 | maybe_run_test(tcc_state); | 1606 | if (tok < TOK_IDENT) |
| 1517 | c = define_find(tok) != 0; | 1607 | expect("identifier"); |
| 1608 | if (tcc_state->run_test) | ||
| 1609 | maybe_run_test(tcc_state); | ||
| 1610 | c = define_find(tok) != 0; | ||
| 1611 | } | ||
| 1518 | if (t == '(') { | 1612 | if (t == '(') { |
| 1519 | next_nomacro(); | 1613 | next_nomacro(); |
| 1520 | if (tok != ')') | 1614 | if (tok != ')') |
| @@ -1522,15 +1616,34 @@ static int expr_preprocess(void) · 1 unmodified line | |||
| 1522 | } | 1616 | } |
| 1523 | tok = TOK_CINT; | 1617 | tok = TOK_CINT; |
| 1524 | tokc.i = c; | 1618 | tokc.i = c; |
| 1525 | } else if (1 && tok == TOK___HAS_INCLUDE) { | 1619 | } else if (tok == TOK___HAS_INCLUDE || |
| 1526 | next(); /* XXX check if correct to use expansion */ | 1620 | tok == TOK___HAS_INCLUDE_NEXT) { |
| 1527 | skip('('); | 1621 | int c, n, i, fd, save_tok = tok; |
| 1528 | while (tok != ')' && tok != TOK_EOF) | 1622 | char buf[1024]; |
| 1529 | next(); | 1623 | |
| 1624 | next_nomacro(); | ||
| 1625 | if (tok != '(') | ||
| 1626 | expect("("); | ||
| 1627 | ch = file->buf_ptr[0]; | ||
| 1628 | c = parse_include(buf, sizeof(buf), ')'); | ||
| 1629 | next_nomacro(); | ||
| 1530 | if (tok != ')') | 1630 | if (tok != ')') |
| 1531 | expect("')'"); | 1631 | expect("')'"); |
| 1532 | tok = TOK_CINT; | 1632 | tok = TOK_CINT; |
| 1533 | tokc.i = 0; | 1633 | tokc.i = 0; |
| 1634 | i = save_tok == TOK___HAS_INCLUDE_NEXT ? file->include_next_index + 1 : 0; | ||
| 1635 | n = 2 + s1->nb_include_paths + s1->nb_sysinclude_paths; | ||
| 1636 | for (; i < n; i++) { | ||
| 1637 | char buf1[sizeof file->filename]; | ||
| 1638 | |||
| 1639 | if (get_include_file(s1, i, c, buf, buf1, sizeof(buf1))) | ||
| 1640 | continue; | ||
| 1641 | if ((fd = open(buf1, O_RDONLY | O_BINARY)) >= 0) { | ||
| 1642 | close(fd); | ||
| 1643 | tokc.i = 1; | ||
| 1644 | break; | ||
| 1645 | } | ||
| 1646 | } | ||
| 1534 | } else if (tok >= TOK_IDENT) { | 1647 | } else if (tok >= TOK_IDENT) { |
| 1535 | /* if undefined macro, replace with zero, check for func-like */ | 1648 | /* if undefined macro, replace with zero, check for func-like */ |
| 1536 | t = tok; | 1649 | t = tok; |
| @@ -1842,55 +1955,8 @@ ST_FUNC void preprocess(int is_bof) · 305 unmodified lines | |||
| 1842 | case TOK_INCLUDE_NEXT: | 1955 | case TOK_INCLUDE_NEXT: |
| 1843 | ch = file->buf_ptr[0]; | 1956 | ch = file->buf_ptr[0]; |
| 1844 | /* XXX: incorrect if comments : use next_nomacro with a special mode */ | 1957 | /* XXX: incorrect if comments : use next_nomacro with a special mode */ |
| 1845 | skip_spaces(); | 1958 | |
| 1846 | if (ch == '<') { | 1959 | c = parse_include(buf, sizeof(buf), 0); |
| 1847 | c = '>'; | ||
| 1848 | goto read_name; | ||
| 1849 | } else if (ch == '\"') { | ||
| 1850 | c = ch; | ||
| 1851 | read_name: | ||
| 1852 | inp(); | ||
| 1853 | q = buf; | ||
| 1854 | while (ch != c && ch != '\n' && ch != CH_EOF) { | ||
| 1855 | if ((q - buf) < sizeof(buf) - 1) | ||
| 1856 | *q++ = ch; | ||
| 1857 | if (ch == '\\') { | ||
| 1858 | if (handle_stray_noerror() == 0) | ||
| 1859 | --q; | ||
| 1860 | } else | ||
| 1861 | inp(); | ||
| 1862 | } | ||
| 1863 | *q = '\0'; | ||
| 1864 | minp(); | ||
| 1865 | #if 0 | ||
| 1866 | /* eat all spaces and comments after include */ | ||
| 1867 | /* XXX: slightly incorrect */ | ||
| 1868 | while (ch1 != '\n' && ch1 != CH_EOF) | ||
| 1869 | inp(); | ||
| 1870 | #endif | ||
| 1871 | } else { | ||
| 1872 | int len; | ||
| 1873 | /* computed #include : concatenate everything up to linefeed, | ||
| 1874 | the result must be one of the two accepted forms. | ||
| 1875 | Don't convert pp-tokens to tokens here. */ | ||
| 1876 | parse_flags = (PARSE_FLAG_PREPROCESS | ||
| 1877 | | PARSE_FLAG_LINEFEED | ||
| 1878 | | (parse_flags & PARSE_FLAG_ASM_FILE)); | ||
| 1879 | next(); | ||
| 1880 | buf[0] = '\0'; | ||
| 1881 | while (tok != TOK_LINEFEED) { | ||
| 1882 | pstrcat(buf, sizeof(buf), get_tok_str(tok, &tokc)); | ||
| 1883 | next(); | ||
| 1884 | } | ||
| 1885 | len = strlen(buf); | ||
| 1886 | /* check syntax and remove '<>|""' */ | ||
| 1887 | if ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') && | ||
| 1888 | (buf[0] != '<' || buf[len-1] != '>')))) | ||
| 1889 | tcc_error("'#include' expects \"FILENAME\" or <FILENAME>"); | ||
| 1890 | c = buf[len-1]; | ||
| 1891 | memmove(buf, buf + 1, len - 2); | ||
| 1892 | buf[len - 2] = '\0'; | ||
| 1893 | } | ||
| 1894 | 1960 | ||
| 1895 | if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) | 1961 | if (s1->include_stack_ptr >= s1->include_stack + INCLUDE_STACK_SIZE) |
| 1896 | tcc_error("#include recursion too deep"); | 1962 | tcc_error("#include recursion too deep"); |
| @@ -1899,31 +1965,9 @@ ST_FUNC void preprocess(int is_bof) · 2 unmodified lines | |||
| 1899 | for (; i < n; ++i) { | 1965 | for (; i < n; ++i) { |
| 1900 | char buf1[sizeof file->filename]; | 1966 | char buf1[sizeof file->filename]; |
| 1901 | CachedInclude *e; | 1967 | CachedInclude *e; |
| 1902 | const char *path; | ||
| 1903 | |||
| 1904 | if (i == 0) { | ||
| 1905 | /* check absolute include path */ | ||
| 1906 | if (!IS_ABSPATH(buf)) | ||
| 1907 | continue; | ||
| 1908 | buf1[0] = 0; | ||
| 1909 | |||
| 1910 | } else if (i == 1) { | ||
| 1911 | /* search in file's dir if "header.h" */ | ||
| 1912 | if (c != '\"') | ||
| 1913 | continue; | ||
| 1914 | /* https://savannah.nongnu.org/bugs/index.php?50847 */ | ||
| 1915 | path = file->true_filename; | ||
| 1916 | pstrncpy(buf1, path, tcc_basename(path) - path); | ||
| 1917 | |||
| 1918 | } else { | ||
| 1919 | /* search in all the include paths */ | ||
| 1920 | int j = i - 2, k = j - s1->nb_include_paths; | ||
| 1921 | path = k < 0 ? s1->include_paths[j] : s1->sysinclude_paths[k]; | ||
| 1922 | pstrcpy(buf1, sizeof(buf1), path); | ||
| 1923 | pstrcat(buf1, sizeof(buf1), "/"); | ||
| 1924 | } | ||
| 1925 | 1968 | ||
| 1926 | pstrcat(buf1, sizeof(buf1), buf); | 1969 | if (get_include_file(s1, i, c, buf, buf1, sizeof(buf1))) |
| 1970 | continue; | ||
| 1927 | e = search_cached_include(s1, buf1, 0); | 1971 | e = search_cached_include(s1, buf1, 0); |
| 1928 | if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) { | 1972 | if (e && (define_find(e->ifndef_macro) || e->once == pp_once)) { |
| 1929 | /* no need to parse the include because the 'ifndef macro' | 1973 | /* no need to parse the include because the 'ifndef macro' |
| @@ -1965,7 +2009,7 @@ include_done: · 35 unmodified lines | |||
| 1965 | c = 1; | 2009 | c = 1; |
| 1966 | goto do_ifdef; | 2010 | goto do_ifdef; |
| 1967 | case TOK_IF: | 2011 | case TOK_IF: |
| 1968 | c = expr_preprocess(); | 2012 | c = expr_preprocess(s1); |
| 1969 | goto do_if; | 2013 | goto do_if; |
| 1970 | case TOK_IFDEF: | 2014 | case TOK_IFDEF: |
| 1971 | c = 0; | 2015 | c = 0; |
| @@ -1981,7 +2025,10 @@ include_done: · 9 unmodified lines | |||
| 1981 | file->ifndef_macro = tok; | 2025 | file->ifndef_macro = tok; |
| 1982 | } | 2026 | } |
| 1983 | } | 2027 | } |
| 1984 | c = (define_find(tok) != 0) ^ c; | 2028 | if (tok == TOK___HAS_INCLUDE || tok == TOK___HAS_INCLUDE_NEXT) |
| 2029 | c = 1 ^ c; | ||
| 2030 | else | ||
| 2031 | c = (define_find(tok) != 0) ^ c; | ||
| 1985 | do_if: | 2032 | do_if: |
| 1986 | if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) | 2033 | if (s1->ifdef_stack_ptr >= s1->ifdef_stack + IFDEF_STACK_SIZE) |
| 1987 | tcc_error("memory full (ifdef)"); | 2034 | tcc_error("memory full (ifdef)"); |
| @@ -2004,7 +2051,7 @@ include_done: · 16 unmodified lines | |||
| 2004 | if (c == 1) { | 2051 | if (c == 1) { |
| 2005 | c = 0; | 2052 | c = 0; |
| 2006 | } else { | 2053 | } else { |
| 2007 | c = expr_preprocess(); | 2054 | c = expr_preprocess(s1); |
| 2008 | s1->ifdef_stack_ptr[-1] = c; | 2055 | s1->ifdef_stack_ptr[-1] = c; |
| 2009 | } | 2056 | } |
| 2010 | test_else: | 2057 | test_else: |
| @@ -94,6 +94,7 @@ · 93 unmodified lines | |||
| 94 | DEF(TOK___VA_ARGS__, "__VA_ARGS__") | 94 | DEF(TOK___VA_ARGS__, "__VA_ARGS__") |
| 95 | DEF(TOK___COUNTER__, "__COUNTER__") | 95 | DEF(TOK___COUNTER__, "__COUNTER__") |
| 96 | DEF(TOK___HAS_INCLUDE, "__has_include") | 96 | DEF(TOK___HAS_INCLUDE, "__has_include") |
| 97 | DEF(TOK___HAS_INCLUDE_NEXT, "__has_include_next") | ||
| 97 | 98 | ||
| 98 | /* special identifiers */ | 99 | /* special identifiers */ |
| 99 | DEF(TOK___FUNC__, "__func__") | 100 | DEF(TOK___FUNC__, "__func__") |